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"

2 Answers 2

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',
]
Sign up to request clarification or add additional context in comments.

9 Comments

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
@HugoLuisVillalobosCanto Try adding X-CSRFTOKEN to CORS_ALLOW_HEADERS in Django settings.
I did it, and I got back to the original point (Forbidden (CSRF cookie not set.))
@HugoLuisVillalobosCanto Try adding withCredentials: True to the axios config (after headers).
I was making a mistake. Now it is working, but I get another error: Forbidden (CSRF token missing or incorrect.))
|
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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.