CSRF Cookie is not set with react frontend

But no where in the django documents it is mentioned to send the csrftoken as separate cookie rather than sending it in header by the name X-CSRFToken. If you could show me a sample request on how it is supposed to be sent, it would be helpful.

I don’t have any information to provide other than what’s documented in the CSRF Protection docs. I’ve never had any problems with it, it has always “just worked” for me.

Looking back at your first post, I don’t see where you’ve set the CSRF_HEADER_NAME setting. (Also see the AJAX paragraph in the CSRF Protection docs.)

by default CSRF_HEADER_NAME name is HTTP_X_CSRFTOKEN, which is available in the request Meta, still csrf cookie not set error is thrown

ken, when i print the request.META i can see the csrf cookie in HTTP_X_CSRFTOKEN key. But once i print request.COOKIES it is returning {} empty.

That’s fine - actually good. (The middleware looks for the cookie before looking for the X-CSRFToken header. If a cookie was being supplied, and was an incorrect cookie, that would have been a cause of a problem.)

I have been reading the middleware and making dummy requests, couldn’t find anything wrong with the middleware or the code i wrote. seems like it might be the issue on the frontend.
Thanks for your valuable time ken. I really appreciate it. If i get to know what might have caused this issue, i will surely update here

Hello @Bharath3697, I have been facing the same issue you had been facing and I managed to fix it. No, it’s not a frontend issue. You just need to add a few configurations in your settings.py of your Django App.

You just need to add CSRF_TRUSTED_ORIGINS where you specify your web app URL

CSRF_TRUSTED_ORIGINS = [
     "example.com"
]

This might be helpful for anyone who is struggling with this (I know the pain)

If you still face the same error try it with this config also:

SESSION_COOKIE_SAMESITE = None

@KenWhitesell , @Bharath3697 , hope you’re doing well and staying safe! :mask:

Environment

  • Django==3.1.1
  • django-cors-headers==3.10.0
  • frontend - React.js

Issue

  • trying to submit a form (used to create new user) (POST), gives 403

  • front-end is React.js so there will is no {% csrf_token %} in the form

  • form used to create new user

  • although, now I know that session is server-side thing and we store those in browser in the form of cookies

  • I’m no longer returning HTTP response from any of the views, because frontend is React.js for this project

  • I’ve managed CORS

CORS_ALLOW_ALL_ORIGINS = True

  • question
  1. how/where_from to get the csrf_token for that particular view function and the request and return it in JsonResponse ?
  2. How could the client can successfully complete the form request ?
  • register page is the first page when client visits server
  • how could client set csrf there ? (in request)

views.py

@ensure_csrf_cookie
def register(request):
    if request.method == "POST":
        username = request.POST["username"]
        email = request.POST["email"]
        password = request.POST["password"]
        confirmation = request.POST["confirmation"]
        try:
            user = User.objects.create_user(username, email, password)
            user.save()
            return JsonResponse({"message":"User Registered."})

Start with the AJAX docs in the CSRF page. That has always covered it for me. (Caveat: I’ve never used React.)

Hi @Bharath3697 did you find a solution?

Nope. I shifted to token based authentication

I don’t know if it will apply to your case but for mine there was no initial path for django project, there was only /api route, that result in browser to not set the cookie. After I added initial hello world get path to base path e.g

GET http://localhost:8080 Respose: Hello World

browser started to set the cookie

Hello.

I had run into the same problem. My session cookies from my Django API were not getting set on my React frontend since they were communicating in a cross site context. The solution was to tweak these settings on the backend:

  1. Allow for the cookies to be sent
CORS_ALLOW_CREDENTIALS = True
  1. Adding the frontend server to CSRF_TRUSTED_ORIGINS
CSRF_TRUSTED_ORIGINS = ["http://127.0.0.1:5173"]
  1. Changing SESSION_COOKIE_SAMESITE from Lax to None
SESSION_COOKIE_SAMESITE = None

For this setting, it is essential to take the below step.

  1. Changing CSRF_COOKIE_SECURE from False to True
CSRF_COOKIE_SECURE = True

Note: For the above setting, you need to be using an HTTPS protocol or your localhost.

I have enlisted the above settings assuming you have added the basic configuration for the django-cors-headers package to your settings.

Reference: I normally test in FIrefox, but decided to test in Chrome for once. When the cookies were being sent, Chrome gave a detailed explanation about why the cookies could not be set. I referred MDN for some more clarity.

please tell me someone managed to fix this. This is my settings

CORS_ALLOWED_ORIGINS = [
    'http://localhost:3000',
    'https://localhost:3000',
    'http://127.0.0.1:3000',
    'http://0.0.0.0',
]
CSRF_TRUSTED_ORIGINS = ['http://localhost:3000',
                        'https://localhost:3000',
                        'http://127.0.0.1:3000',
                        'https://127.0.0.1:3000',
                        'http://0.0.0.0']

CORS_ALLOW_CREDENTIALS = True
CSRF_COOKIE_SECURE = False
CSRF_COOKIE_HTTPONLY = False

The cookie is sent from backend. If I go to api/getcsrfcookie url in normal browser, I can see the cookie value in the storage part of dev tools but with react, I am doing the same thing. I am doing axios.get(api/getcsrfcookie) in one component then rendering that component to another component but there is no cookie in storage. I can see the set-cookie in network tab in dev tools. I am about to lose my mind. It was working before but I cleared cache is it stopped working

For future people, in my case with react, I added withcredentials: true when sending a request and it fixed my problem. My code is like this

const config = {
    withCredentials: true,
    headers: {
      Accept: "application/json",
      "Content-Type": "application/json",
      "X-CSRFToken": Cookies.get('csrftoken')
    },
  };

  const body = JSON.stringify({ username, password, email });

  try {
    const res = await axios.post(
      `${process.env.REACT_APP_API_URL}/user/register`,
      body,
      config,
    );

Also, just to add to @tamusandesh99 's answer, for those using fetch, use { credentials: 'include' }, e.g.:

const response = await fetch(CSRF_URL, {
    credentials: 'include',
});
const cookie = await response.headers.get('X-CSRFToken');
setCsrfToken(cookie);

Also, with some help from this blog (and Django docs + SO), here are my related settings:

# -------- CROSS DOMAIN SESSION AUTHENTICATION
# CSRF_COOKIE_HTTPONLY = True
CSRF_TRUSTED_ORIGINS = [
    'http://localhost:5173',
    'http://127.0.0.1:5173',
]
CSRF_COOKIE_SAMESITE = 'Lax'
SESSION_COOKIE_SAMESITE = 'Lax'
SESSION_COOKIE_HTTPONLY = True

# PROD SETTINGS
# CSRF_COOKIE_SECURE = True
# SESSION_COOKIE_SECURE = True

CORS_ALLOWED_ORIGINS = [
    'http://localhost:5173',
    'http://127.0.0.1:5173',
]
CORS_EXPOSE_HEADERS = ['Content-Type', 'X-CSRFToken']
CORS_ALLOW_CREDENTIALS = True

…commenting out CSRF_COOKIE_HTTPONLY = True allows me to access the cookie in React. I know the docs mention that setting this to True “offers little practical benefit”, but I’m curious if I should have this set to True since it’s mentioned in the blog? My server + browser are hosted separately, which is a new setup for me so I’m sure I’m missing something… anyways just thinking out loud.

For more info towards future people,

if the issue is in prod, where your backend and frontend is hosted by two different servers with different domains then the cookie will not set because of security reasons. For example if you frontend is is mydomain.com and backend is in backend.com then it wont work. Both BE and FE needs to be in same domain. If your frontend is in mydomain.com then you can add subdomain for backend such as api.mydomain.com then the browser will accept and store the cookie. Additionally if you haven’t you will need to add these settings:

CORS_ALLOW_CREDENTIALS = True
CSRF_COOKIE_HTTPONLY = False
SESSION_COOKIE_SECURE = False
CSRF_COOKIE_SECURE = True  # Set to True in production (requires HTTPS)
CSRF_COOKIE_SAMESITE = 'None'
CSRF_COOKIE_DOMAIN = '.mydomain.com'