CSRF with Django, React+Redux using Axios
There are three ways. You can manually include the token in the header of each axios call, you can set axios's xsrfHeaderName
in each call, or you set a default xsrfHeaderName
.
1. Adding it manually
Let's say you've got the value of the token stored in a variable called csrfToken
. Set the headers in your axios call:
// ...
method: 'post',
url: '/api/data',
data: {...},
headers: {"X-CSRFToken": csrfToken},
// ...
2. Setting xsrfHeaderName
in the call:
Add this:
// ...
method: 'post',
url: '/api/data',
data: {...},
xsrfHeaderName: "X-CSRFToken",
// ...
Then in your settings.py
file, add this line:
CSRF_COOKIE_NAME = "XSRF-TOKEN"
3. Setting default headers[1]
Rather than defining the header in each call, you can set default headers for axios.
In the file where you're importing axios to make the call, add this below your imports:
axios.defaults.xsrfHeaderName = "X-CSRFToken";
Then in your settings.py
file, add this line:
CSRF_COOKIE_NAME = "XSRF-TOKEN"
Edit (June 10, 2017): User @yestema says that it works slightly different with Safari[2]
Edit (April 17, 2019): User @GregHolst says that the Safari solution above does not work for him. Instead, he used the above Solution #3 for Safari 12.1 on MacOS Mojave. (from comments)
Edit (February 17, 2019): You might also need to set[3]:
axios.defaults.withCredentials = true
Question: Is this next section useful to anyone? I'm wondering if this answer might be improved by only including the solutions. Let me know if you have an opinion please.
The confusion:
Django Docs
First, the whole passage from the Django docs that James Evans referenced:
...on each XMLHttpRequest, set a custom X-CSRFToken header to the value of the CSRF token. This is often easier, because many JavaScript frameworks provide hooks that allow headers to be set on every request.
As a first step, you must get the CSRF token itself. The recommended source for the token is the csrftoken cookie, which will be set if you’ve enabled CSRF protection for your views as outlined above.
Note
The CSRF token cookie is named csrftoken by default, but you can control the cookie name via the CSRF_COOKIE_NAME setting.
The CSRF header name is HTTP_X_CSRFTOKEN by default, but you can customize it using the CSRF_HEADER_NAME setting.
Axios Docs
This is from the Axios docs. It indicates that you set the name of the cookie which contains the csrftoken
, and the name of the header here:
// `xsrfCookieName` is the name of the cookie to use as a value for xsrf token
xsrfCookieName: 'XSRF-TOKEN', // default
// `xsrfHeaderName` is the name of the http header that carries the xsrf token value
xsrfHeaderName: 'X-XSRF-TOKEN', // default
Terms
As indicated in my question, you access cookies with document.cookie
. The only cookie I have is the CSRF token I put in the Django template. Here is an example:
csrftoken=5knNceCUi9nL669hGGsvCi93XfqNhwTwM9Pev7bLYBOMXGbHVrjitlkKi44CtpFU
There are a few concepts being thrown around in those docs that get confusing:
- The name of the cookie that contains the CSRF token. In Django this is by default
csrftoken
, which is on the left side of the equals sign in the cookie. - The actual token. This is everything on the right side of the equals sign in the cookie.
- The http header that carries the token value.
Things I tried that didn't work: 1, 2
I've found out, that axios.defaults.xsrfCookieName = "XCSRF-TOKEN";
and CSRF_COOKIE_NAME = "XCSRF-TOKEN"
DOESN'T WORK IN APPLE Safari on Mac OS
The solution for MAC Safari is easy, just change XCSRF-TOKEN
to csrftoken
So, in js-code should be:
import axios from 'axios';
axios.defaults.xsrfHeaderName = "X-CSRFTOKEN";
axios.defaults.xsrfCookieName = "csrftoken";
In settings.py:
CSRF_COOKIE_NAME = "csrftoken"
This configuration works for me without problems Config axios CSRF django
import axios from 'axios'
/**
* Config global for axios/django
*/
axios.defaults.xsrfHeaderName = "X-CSRFToken"
axios.defaults.xsrfCookieName = 'csrftoken'
export default axios