Django 4.0 wildcard subdomain preventing from setting csrf token

I’m having a problem with Django 4.0 backend in debug mode where I use session auth with csrf token.
I use wildcard subdomains:

CSRF_TRUSTED_ORIGINS = ["http://*.local.lab:8080"]
ALLOWED_HOSTS = [".local.lab"]
CORS_ALLOW_ALL_ORIGINS = True
CORS_ALLOW_CREDENTIALS = True
CSRF_COOKIE_HTTPONLY = False
CSRF_COOKIE_SECURE = False
SESSION_COOKIE_HTTPONLY = True

When I’m accessing app on http://local.lab:8080 CSRF token is being sent and set in browser storage, all works as intended.

When I’m accessing app with any other URL combination i.e. http://www.local.lab:8080 or http://subdomain.local.lab:8080 CSRF request comes back with the correct cookie but the cookie is never set in a browsers storage and that prevents me from creating x-csrf token and making any post requests.

Everything I’m testing on local domain where I mapped my local IP to the domain local.lab with help of the tool dnsmasq.

What am I doing wrong in here?

For clarification:

  • You’re issuing a request to www.local.lab.
  • The response contains a cookie for the domain www.local.lab
  • The browser is not saving the cookie

Is this a correct summary of the situation?

I ran into this recently where browsers started enforcing third party cookies slightly differently. For me, the change meant I had to always set the cookies secure value. The browsers now ignore that when it’s for a local URL. Try setting CSRF_COOKIE_SECURE = True. My worry for you is I don’t know if the browser will identify your URL as a local URL.

Edit: Another setting to look at is CSRF_COOKIE_SAMESITE

Yes that is correct.
CSRF is being set correctly only for local.lab

CSRF_COOKIE_SECURE tried this option already setting it to None but it didn’t work.
CSRF_COOKIE_SECURE = True the only problem with this I will have to setup local https to test - on it anyway nothing to loose.

CSRF_COOKIE_SECURE = True the only problem with this I will have to setup local https to test it.

Is it possible to have the root host be localhost? The MDN docs indicate that the https requirements are ignored when the attribute is set by localhost.

You were right with root host as localhost I was able to set CSRF_COOKIE_SECURE = True but that didn’t help my case. I will setup https and test again, I’ve read somewhere that setting CSRF_COOKIE_SAMESITE = None doesn’t have proper effect until you have https, not sure if that’s true but I’m gonna check anyway.

Added self signed SSL certificates and few Django settings but still without success:

SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")
CSRF_COOKIE_SAMESITE = 'None'
SESSION_COOKIE_SAMESITE = 'None'
CSRF_COOKIE_SECURE = True 
SESSION_COOKIE_SECURE = True

For clarification:

You’re issuing a request to www.local.lab.
The response contains a cookie for the domain www.local.lab
The browser is not saving the cookie

Is this a correct summary of the situation?

Do you have any suggestion what else i could try or who to ask for help?

I don’t have any specific suggestions, it just seems odd to me that if:

  • You’re issuing a proper request to www.local.lab
  • The server is issuing a proper cookie in the response for the domain www.local.lab
  • You’re seeing the cookie being received by the browser in the response coming from www.local.lab

and the browser isn’t saving a proper cookie being returned to it, that it’s in any way a Django issue.

If I were investigating this, I’d be looking really closely at exactly what is being sent and received by the browser during this transaction.

Did you update the trusted origins settings to use the https scheme?

Yes I did, no change, any other ideas?

What browser are you using? Can you try a different browser? (And perhaps the current browser using “privacy” or “incognito” mode?)
How about clearing all cache and cookies currently associated with that domain?

I used Firefox, Chrome, Ungoogled Chromum, Brave all with incognito mode, non incognito with cache cleaned same result.

How are you running your server? Is this a development environment using runserver (or runserver_plus)? Or is this behind a web server such as nginx or apache?

(At this point, I’m just trying to rule out potential external influences.)

I have 2 environments, prod is using nginx, gunicorn with static vuejs and axios where the http requests comes from. Dev env is using simply runserver python manage.py runserver 0.0.0.0:8000.
I’m testing both at the same time as I dockerized all.

p.s didn’t know about runserver_plus will need to look into it as well.

1 Like

I don’t expect this to solve the issue of the cookies not being saved in the browser, but I think it’s worth mentioning. fetch and axios both support the ability to send credentials, and in this case it includes the cookies when withCredentials is enabled in the axios request. See axios request config and relevant GH issue.

Yes I’m using axios.defaults.withCredentials = true; I just swapped axios for fetch and still the same.
I’m slowly getting nuts here.

Does the browser’s dev tool’s console panel show any information about why the cookie is being rejected?


No errors when cookie is rejected.
I’ve attached a screen cap with headers from my http requests, left one sets cookie in browser right one not.