Angular+Django CSRF token not being saved as cookie

I have a webapp with Angular frontend and Django backend. Everything works fine locally so I deployed the backend to PythonAnywhere. I use CSRF tokens so as soon the user opens the page, an empty request is sent to the backend, which responds with the token which is automatically saved as a cookie. However this does not work when I deploy the backend. I can see the token is in the response, but it does not appear in the browser storage, and it cannot be used for the following requests.

I'm not sure how to even debug this. What could be causing this to begin with?

This is the relevant part of my setttings.py:

ALLOWED_HOSTS = ['*']

# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'corsheaders',
]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    'corsheaders.middleware.CorsMiddleware',
]

CORS_ALLOWED_ORIGINS = (
    'http://localhost:4200',
)

CSRF_TRUSTED_ORIGINS = (
    'http://localhost:4200',
)

CORS_ALLOW_CREDENTIALS = True

CSRF_COOKIE_SAMESITE = 'None'
CSRF_COOKIE_SECURE = True

I get the same problem when I deploy the frontend (then I also add it as a trusted origin but I skipped that in this extract).

Like I said, I can see the token in the response in the browser network view, but it never reaches the browser storage. And it works fine when running the same backend locally.

Cookie settings need to be:

SameSite=None  # Mandatory
Secure  =True  # Mandatory
HttpOnly=True  # Optional but recommended

You seem to have this part configured correctly already. Your CORS configuration also looks correct.

Without information about your frontend, I can only presume that the last step now is to instruct the backend calls to include third-party cookies (and in the eyes of your browser, your backend is a third-party).

How you do this depends on how you're sending the calls. For fetch, it will look like this:

fetch('https://backend.com/', {
    method: 'GET',
    credentials: 'include',
})

The notable drawback to this setup is that it's hard to develop/test locally, as the cookie settings make it so that the cookie will only be sent over HTTPS. There are ways to set that up, but that's out of scope for this question.

Back to Top