CSRF Cookie is not set with react frontend


I’m facing an issue with handling the csrftoken sent by drf. though the csrftoken cookie is visible in the response header, it is not getting added to the cookies storage. I have tried all the possible SO answers, but none of them seems to work.

The flow consists of a get request to an endpoint “/get-csrf-token/” which will return a response “CSRF Cookie set”, in the response header the csrf cookie will be available. but the problem is, it is not getting stored. i have added below values settings.py

CSRF_COOKIE_AGE = 8 * 3600           
CSRF_COOKIE_SAMESITE = 'Strict' ('lax' also doesn't work, 'None' results in error)

below is the view.py

@method_decorator(ensure_csrf_cookie, name='dispatch')
class getcsrf(APIView):
    permission_classes = [AllowAny]
    def get(self, request, format=None):
        return Response({'Success': 'CSRF Cookie set'})

path('get-csrf-token/', getcsrf.as_view(), name='getcsrf')

If anyone could sort out the cause, it would be a great help. please do not suggest csrf_exempt as an answer.

Are you sure this is a Django issue? It appears that you’re getting the cookie from the server. So my impression would be that it’s something in your JavaScript that you may need to do to save that cookie within your browser’s storage. (Or am I misunderstanding the information you’re providing here?)

Hi Ken,

I have tried to send one more cookie but that also doesn’t seems to get stored.

@method_decorator(ensure_csrf_cookie, name='dispatch')
class getcsrf(APIView):
    permission_classes = [AllowAny]
    def get(self, request, format=None):
        return resp

so none of the cookies get stored using set-cookie. If i hit the origin api endpoint from browser, the cookies are stored. But with react as front end, it is not all storing any cookies

So I’m interpreting this as saying that Django is working fine - it’s sending the cookie. It’s up to the browser to save it. How are you trying to save that cookie in React?

react is not my cup of tea. front end is handled by someone else. So are you sure there is no issue with the backend?

About as sure as I can be. Django is sending the cookies - you’re seeing that. What the browser (and JavaScript running in the browser) does with those cookies is not something that Django can control.

As per the django documentation [Cross Site Request Forgery protection | Django documentation | Django], for ajax calls it fetches the cookie using “document.cookie” method, for that the cookie must be stored first. in this case the output will be undefined. So just to clarify, is it django’s work to set the cookie or has it to be done by react?

As part of a reply to a request, Django can include a Set-Cookie header. That is the limit of what Django can do. Django has no control over what the browser does with any data sent to it.

What the browser does with the content of that header is strictly under the control of the browser. Your JavaScript could either store that cookie in the browser’s cookie store, or it can store it within your local data store.

1 Like

Thanks Ken, i understood it now. Btw, wanted to ask for one more suggestion as there is a long debate happening about this, which one would be better token auth (xss attack) or session auth (csrf attack) ?

Hi Ken,

Just came across a SO question https://stackoverflow.com/questions/61873089/unable-to-get-set-cookie-value-from-header-with-axios-reactjs

here it is said that the set-cookie will not be available in response header, but can be fetched using “document.cookie” . Since i get undefined for document.cookie, how can it be handled from frontend?

So still confused what might be the cause for this

It’s not one being “better” than the other - the two are different and each has their own advantages. The decision between the two should depend upon how those advantages or benefits stack up for your particular application.

Check the CSRF_COOKIE_HTTPONLY setting in your settings.py file and confirm whether or not httponly is being set on the cookie. It defaults to False, and the docs explain why it’s not much help to set it to true. But if it’s set, it’ll explain what you’re seeing.

CSRF_COOKIE_SECURE is also set to False

Let’s make sure we’re really identifying the right problem here. I’d like to look at this from a different angle.

Since the cookies are mostly supposed to be transparent to the application layer, there really shouldn’t be much that you need to do with them.

If you’ve got an AJAX call that is supposed to be sending the cookies, can you verify in your browser’s developer tools what the headers are being sent in the request that is supposed to include the csrf-cookie?

Hi Ken,
Now the request header contains X-CSRFTOKEN and the csrf cookie value is passed to the view function. But in csrf middleware, the validation is failing because the cookie is fetched using csrf_token = request.META.get('CSRF_COOKIE').

This is happening because cookie is present in header with key “X-CSRFTOKEN”, But middleware checks for the csrf token using “CSRF_COOKIE” as the key. why is it happening so?
If i make the request using postman both X-CSRFTOKEN and CSRF_COOKIE keys are present in the header and it passes the csrf validation , but with browser CSRF_COOKIE key is not present.

What about the cookies? Are the cookies being submitted in the request?

yes ken. csrf token is passed as X-CSRFToken. But the django csrf middleware checks for token using request.META.get('CSRF_COOKIE') under “process_view” function of middleware/csrf.py . since there is no key named “CSRF_COOKIE” in the request it is raising cookie not set error.

why is it so?

I’m not asking about the headers - I’m asking about any cookies being submitted along with the request.

No. no cookies are passed. But csrf is a cookie right except that nothing else is passed

In the HTTP transport, a cookie is a header - a separate header than any of the X-whatever headers. So something sent under the “Cookie” header is different than something sent as X-CSRFToken. If the JavaScript is not sending the “Cookie” header, that’s a different issue.