David Qin
David Qin

Reputation: 365

django no csrftoken in cookie

I'm testing to make a POST ajax request and I got a 403 because of no csrftoken. I followed the Document, however, it still doesn't work and I found that the cookie named csrftoken is empty, it means $.cookie("csrftoken") return null.

Can someone tell me the reason and how to set csrftoken into cookie?

Upvotes: 18

Views: 18388

Answers (5)

ramailo sathi
ramailo sathi

Reputation: 355

First of all, if you are designing the application, it is always better to use csrf Token in a header or in POST request rather than in a cookie, because:

  • All forms must have the value added to its HTML dynamically. Any AJAX POSTs must also include the value.
  • The cookie will be submitted for every request (i.e. all GETs for images, CSS, JS, etc, that are not involved in the CSRF process) increasing request size.

If you want to force usage of cookies in django, you could always:

request.META["CSRF_COOKIE_USED"] = True

in your project if you are not using {% csrf_token %} anywhere. According to [documentation][1], you are not required to do anything else, but write a simple javascript code. Actually it's not true. You have to put "request.META['CSRF_COOKIE_USED'] = True" line in every view (or write appropriate decorator).

Upvotes: 3

06userit
06userit

Reputation: 166

Expanding on o_c's answer: by commenting the CSRF_COOKIE_HTTPONLY line, csrf_token value is no longer 'undefined' (in Firefox firebug) and is shown as the 'real' value, e.g. 'qGuPe2Q7... etc.'.

Ajax request is no longer rejected with 403 Forbidden error and is correctly executed (provided that csrf_token is set in the AJAX header).

        $.ajaxSetup({
            beforeSend: function(xhr, settings) {
                 if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
                 xhr.setRequestHeader("X-CSRFToken", csrftoken);
                }
             }
        });

Upvotes: 2

o_c
o_c

Reputation: 4203

I had the same problem ($.cookie('csrftoken') returned 'undefined').

The problem was in my Django configuration, I commented the following line and it works:

#CSRF_COOKIE_HTTPONLY = True  # Prevent client-side JavaScript access to the CSRF cookie

Upvotes: 6

jerrykan
jerrykan

Reputation: 1096

You probably want to use the ensure_csrf_cookie view decorator (available since Django 1.4). This will set the csrftoken cookie even if you don't use the {{ csrf_token }} template tag.

Upvotes: 16

Igor
Igor

Reputation: 3179

I think you should provide the code how you get the csrf token in your HTML/JS code and settings for your middlewares.

First of all you should check that django.middleware.csrf.CsrfViewMiddleware is turned on.

I had a similar issue, when in python code I used request.META.get('CSRF_COOKIE') to get the token.

When you use this token in template - {% csrf_token %} Django notes that the token was rendered and sets the Cookie in CsrfViewMiddleware.process_response. If you get the token value in other way Django will miss this flag. So it will generate you a token but will not set the corresponding cookie.

I have 2 workarounds in code. You should add it to your views that are used to generate templates with JS code.

1. You can force Django to set the CSRF Cookie:

# Force updating CSRF cookie
request.META["CSRF_COOKIE_USED"] = True

2. Django sets the CSRF_COOKIE_USED automatically if you call get_token

from django.middleware.csrf import get_token
# don't use direct access to request.META.get('CSRF_COOKIE')
# in this case django will NOT send a CSRF cookie. Use get_token function
csrf_token = get_token(request)

Each one of this solutions should work separately. I advice to use get_token

Upvotes: 23

Related Questions