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: 'admin@admin.com',
        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"
HuLu ViCa
  • 5,077
  • 10
  • 43
  • 93

2 Answers2

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: 'admin@admin.com',
        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',
]
Community
  • 1
  • 1
nebuler
  • 1,515
  • 1
  • 9
  • 8
  • 1
    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 response` – HuLu ViCa Jan 08 '19 at 19:37
  • @HugoLuisVillalobosCanto Try adding `X-CSRFTOKEN` to `CORS_ALLOW_HEADERS` in Django settings. – nebuler Jan 08 '19 at 19:38
  • I did it, and I got back to the original point (`Forbidden (CSRF cookie not set.)`) – HuLu ViCa Jan 08 '19 at 19:42
  • @HugoLuisVillalobosCanto Try adding `withCredentials: True` to the axios config (after headers). – nebuler Jan 08 '19 at 19:59
  • I was making a mistake. Now it is working, but I get another error: `Forbidden (CSRF token missing or incorrect.)`) – HuLu ViCa Jan 08 '19 at 20:11
  • There was a typo - use `X-CSRFTOKEN` instead of `X-XCSRFTOKEN`. – nebuler Jan 08 '19 at 20:20
  • Your solution works, but I found that the name of the cookie must be `x-xsrf-token` – HuLu ViCa Jan 08 '19 at 20:24
  • @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. – nebuler Jan 09 '19 at 00:00
  • Can we use this X-CSRFTOKEN without username and password. Because I am using this with Google Oauth. – london_utku Jun 24 '22 at 20:52
4

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
o4x
  • 41
  • 1
  • 3