Search code examples
djangoazureshopifycsrfshopify-app

Django CSRF token not saving to browser cookies in Production environment, but working in Development environment


We have created a Django application to create a Shopify Application. We are having issues with out production environment we AJAX calls to the Django application are failing because the CSRF token is not being saved to cookies and therefore nothing gets parsed in the AJAX call headers.

We have followed the Django documentation and added {% csrf_token %} in the <head> tag of our base.html file which all other html files reference. I have also tried to add the following into <head> tag:

<script>
    var csrf_token = '{{ csrf_token }}';
</script>

My AJAX call looks like:

$.ajax({
  url: url,
  type: 'GET',
  dataType: 'json',
  method: 'POST',
  headers: {
    'X-CSRFToken': csrf_token,
    'X-Shopify-Domain': shopifyDomain
  },
  mode: 'same-origin',
  success: function(data) {
    resolve(data);
  },
  error: function(xhr, status, error) {
    console.error(`Error in ${url}:\nStatus: ${xhr.status}\nError: ${error}\nResponse: ${xhr.responseText}`);
    reject(new Error(`Error in ${url}: ${xhr.responseText}`));
  }
});

Because this is a Shopify App, this app is embedded into a iFrame in Shopify but I am not sure this is the culprit as its the same in our development environment. Production Application in is Azure App Service and behind a Azure Front Door, not sure if this is causing any issues.

There does seem to be cookies in the browser from our domain, just not the csrf token:

enter image description here

We can't find a solution to why this is happening. We have had to mark our functions dispatch with @csrf_exempt which we don't want to have to do moving forward. For example:

    @csrf_exempt
    def dispatch(self, *args, **kwargs):
        return super().dispatch(*args, **kwargs)

Session Settings:

SESSION_ENGINE = 'django.contrib.sessions.backends.db'  # Store sessions in the database
SESSION_COOKIE_NAME = 'sessionid'  # The name of the cookie to use for sessions
SESSION_COOKIE_SECURE = True  # Set to True if you're using HTTPS
SESSION_COOKIE_HTTPONLY = True  # Helps prevent Cross-Site Scripting (XSS) attacks
SESSION_COOKIE_AGE = 1209600  # 2 weeks, in seconds
SESSION_EXPIRE_AT_BROWSER_CLOSE = False  # If True, session will expire when the user closes their browser
SESSION_SAVE_EVERY_REQUEST = True  # If True, Django will save session data on every request
SESSION_COOKIE_SAMESITE = 'None' # Allows cross-site cookies
CSRF_COOKIE_SECURE = True  # Set to True if you're using HTTPS
CSRF_COOKIE_SAMESITE = 'None' # Allows cross-site cookies

Solution

  • Given that your requests are coming from a different origin (shopify via iframe), you will have to set various flags such as the "same site" in your settings.py. It will allow cookies to be sent on requests from different origins (https://code.djangoproject.com/ticket/27863)

    Try adding these to your django settings.

    SESSION_COOKIE_SAMESITE = None
    CSRF_COOKIE_SAMESITE = None