CSRF token missing react axios and django

I am trying to submit user login information with a react front end using axios or fetch, and a django back end, but cannot resolve the CSRF token missing error. I’ve used a similar solution as described here: Django CSRF Protection Guide: Examples and How to Enable where I ensure django sends the token using a view with @ensure_csrf_cookie and the browser saves the cookie. In the HTML form in React, I added
where csrftoken is the value of the token Q3bmH8V… When the login form is submitted, the POST request includes the header X-CSRFToken: Q3bmH8V… and the Cookie: Q3bmH8V…

In Settings.py I have CSRF_TRUSTED_ORIGINS = [‘http://localhost:3000’]
CSRF_COOKIE_NAME = “X_CSRFTOKEN”
CSRF_HEADER_NAME = ‘X_CSRFTOKEN’

I’ve tried using fetch, and I’ve tried axios, but nothing seems to resolve this error. Please help.

1 Like

It’s tough to diagnose things without seeing the actual code, but there is a difference between ‘X-CSRFToken’ and ‘X-CSRFTOKEN’ and ‘X_CSRFTOKEN’.

I’d suggest referring to the official Django docs at Cross Site Request Forgery protection | Django documentation | Django and being extremely careful about making sure things match.

1 Like

Thanks, based on the documentation I’ve updating the settings to be the defaults, with settings.py:
CSRF_COOKIE_NAME = “csrftoken”
CSRF_HEADER_NAME = ‘X-CSRFToken’

My front end is sending in the headers section:
csrftoken=hK2ZXclKOvrPbhI5YorIZl1yH4f8YykkyHi9AV4iO877qSKplXp5VUIbl9aZaGiF
and
X-CSRFToken:
hK2ZXclKOvrPbhI5YorIZl1yH4f8YykkyHi9AV4iO877qSKplXp5VUIbl9aZaGiF
But still getting CSRF token missing error.

Using a non-login view and temporarily turning off csrf protection with #@csrf_exempt and including print(request.META), I can see that django is receiving this:
‘HTTP_COOKIE’: ‘csrftoken=hK2ZXclKOvrPbhI5YorIZl1yH4f8YykkyHi9AV4iO877qSKplXp5VUIbl9aZaGiF’, ‘CSRF_COOKIE’:
‘hK2ZXclKOvrPbhI5YorIZl1yH4f8YykkyHi9AV4iO877qSKplXp5VUIbl9aZaGiF’
‘HTTP_X_CSRFTOKEN’: ‘hK2ZXclKOvrPbhI5YorIZl1yH4f8YykkyHi9AV4iO877qSKplXp5VUIbl9aZaGiF’,

I’ve tried all kinds of combinations of settings to try to match the header and cookie names, but but with csrf protection enabled (which will be required for login) I still get the error. Is there any way to figure out what django is expecting the csrftoken and cookie to look like in the headers?

Note: I know nothing about react, axios, or fetch - as a result, some of these questions may not make any sense. I’m trying to address this from a “pure JavaScript” perspective.

You’ve verified that the token you are sending is the token you have received for the initial GET from the site? (Are you getting this from your django site, or are you getting your front end from a different location?)

Are you POSTing an AJAX-style request (JSON data) or an HTML form-style request? (And does this match what your view is expecting?)

If you’re posting this as an HTML form, there’s this from the docs:

For all incoming requests that are not using HTTP GET, HEAD, OPTIONS or TRACE, a CSRF cookie must be present, and the ‘csrfmiddlewaretoken’ field must be present and correct. If it isn’t, the user will get a 403 error.
Are you currently running this using runserver (or runserver_plus) in a development environment, or are you looking at a production environment?

(If you’re posting this as AJAX, don’t worry about it.)

Thanks for continued help. Yes, I can see the token Django sent the front-end matches the token the front end is sending back. The front end is running on a node server localhost:3000, and Django is running on a backend server localhost:8000, and both are development environments. The POST request is being done AJAX-style with JSON data. Django doesn’t not have any errors when csrf protection is disabled, so I think it’s specific to the csrf token.

Just an update, I finally got it to work after changing CSRF_HEADER_NAME = ‘HTTP_X_CSRFTOKEN’. Kinda strange because the django documentation suggests you don’t need the ‘HTTP_’ part, but apparently this is needed. Thanks for your help!

Yep, you got it. The reply I had been working on —

Ok, I always forget this little tidbit from CSRF_HEADER_NAME

As with other HTTP headers in request.META , the header name received from the server is normalized by converting all characters to uppercase, replacing any hyphens with underscores, and adding an 'HTTP_' prefix to the name. For example, if your client sends a 'X-XSRF-TOKEN' header, the setting should be 'HTTP_X_XSRF_TOKEN' .

So I think:

should actually be:
CSRF_HEADER_NAME = ‘HTTP_X_CSRFTOKEN’
(which you’ve already discovered)

Thanks again for your help!!!

Good morning, I’m having the same problem, django in the back and Vue in the front.
However the post type requests are failing, it is already sending

@jeferson1985 Welcome!
I would suggest you open up a new topic with a more complete description of the situation you’re facing. While you might be having the same issue, it’s as likely as not that the underlying cause is different.