How to send CSRF Cookie from React to Django Rest Framework with Axios
Asked Answered
T

2

7

I want to make a POST request from a React app using Axios to a Django Rest Framework backend. I have managed to get a CSRF Token from the backend but I can't manage to send it with my request, so I always get a Forbidden (CSRF cookie not set.) error:

This is the code of my React app:

handleClick() {
    const axios = require('axios');
    var csrfCookie = Cookies.get('XSRF-TOKEN');
    console.log(csrfCookie)
    axios.post('http://127.0.0.1:8000/es/api-auth/login/',
      {
        next: '/',
        username: '[email protected]',
        password: 'Cancun10!',
      },
      {
        headers: {
          'x-xsrf-token': csrfCookie,  // <------- Is this the right way to send the cookie?
        },
        withCredentials = true,
      }
    )
    .then(function (response) {
      console.log(response);
    })
    .catch(function (error) {
      console.log(error);
    })
  }

And this is my settings.py CSRF configuration:

CORS_ALLOW_CREDENTIALS = True
CORS_ALLOW_HEADERS = (
    'xsrfheadername',
    'xsrfcookiename',
    'content-type',
    'XSRF-TOKEN',
)

CORS_ORIGIN_WHITELIST = serverconfig.CORS_ORIGIN_WHITELIST
CSRF_TRUSTED_ORIGINS = serverconfig.CSRF_TRUSTED_ORIGINS
CSRF_COOKIE_NAME = "XSRF-TOKEN"
Tahsildar answered 8/1, 2019 at 18:19 Comment(0)
S
6

Django uses X-CSRFTOKEN as the csrf header by default, see here. The option CSRF_COOKIE_NAME you use in your Django settings only changes the cookie name, which by default is csrftoken, see here.

To solve your issue, use this header in your axios call: headers: { 'X-CSRFTOKEN': csrfCookie }.

Use the following:

axios.post('http://127.0.0.1:8000/es/api-auth/login/',
    {
        next: '/',
        username: '[email protected]',
        password: 'Cancun10!',
    },
    {
        headers: {
             'X-CSRFTOKEN': csrfCookie,
         },
    },
)

Also, remove XSRF-TOKEN from CORS_ALLOW_HEADERS in your Django settings, and add X-CSRFTOKEN to it instead. If you don't feel like removing XSRF-TOKEN, you can safely add X-CSRFTOKEN to CORS_ALLOW_HEADERS with the following, documentation here

# settings.py

from corsheaders.defaults import default_headers

CORS_ALLOW_HEADERS = list(default_headers) + [
    'X-CSRFTOKEN',
]
Sommerville answered 8/1, 2019 at 18:58 Comment(9)
I tried your answer, and I didn't get an error from the backend (this is the backend console result: "OPTIONS /es/api-auth/login/ HTTP/1.1" 200 0), but the frontend console reports an error: Access to XMLHttpRequest at 'http://127.0.0.1:8000/es/api-auth/login/' from origin 'http://localhost:3000' has been blocked by CORS policy: Request header field x-csrftoken is not allowed by Access-Control-Allow-Headers in preflight responseTahsildar
@HugoLuisVillalobosCanto Try adding X-CSRFTOKEN to CORS_ALLOW_HEADERS in Django settings.Sommerville
I did it, and I got back to the original point (Forbidden (CSRF cookie not set.))Tahsildar
@HugoLuisVillalobosCanto Try adding withCredentials: True to the axios config (after headers).Sommerville
I was making a mistake. Now it is working, but I get another error: Forbidden (CSRF token missing or incorrect.))Tahsildar
There was a typo - use X-CSRFTOKEN instead of X-XCSRFTOKEN.Sommerville
Your solution works, but I found that the name of the cookie must be x-xsrf-tokenTahsildar
@HugoLuisVillalobosCanto that doesn't seem right. After looking at the axios source code, it seems that all you have to do is add the headers as shown in my answer. You don't want to use x-xsrf-token in the headers because that's not the header name, it's the cookie name. Also, make sure Cookies.get('XSRF-TOKEN') exists. I can help you over chat if needed be.Sommerville
Can we use this X-CSRFTOKEN without username and password. Because I am using this with Google Oauth.Hirohito
C
5

Also, it's will be easier if you create an Axios instance

const instance = axios.create({
  baseURL: API_URL,
  withCredentials: true,
  xsrfHeaderName: 'X-CSRFToken',
  xsrfCookieName: 'csrftoken',
})

And make sure xsrfCookieName and CSRF_COOKIE_NAME have the same name. Note that if CSRF_COOKIE_HTTPONLY set to True, client-side JavaScript will not be able to access the CSRF cookie:

# settings.py

CSRF_COOKIE_NAME = "csrftoken"
CSRF_COOKIE_HTTPONLY = False

CORS_EXPOSE_HEADERS = ["Content-Type", "X-CSRFToken"]
CORS_ALLOW_CREDENTIALS = True
Charlotte answered 25/8, 2021 at 9:51 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.