Reputation: 365
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
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:
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
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
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
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
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