djangocsrfdjango-csrf

django CSRF token cookie not set for some users


I have been getting sporadic CSRF errors in an app that is mostly working ok. I do everything as I'm supposed to do: I use {% csrf_token %} in my template for normal forms and in my ajax POSTs I set the X-CSRFToken header:

$.ajaxSetup({
    beforeSend: function(xhr, settings) {
        xhr.setRequestHeader("X-CSRFToken", $.cookie('csrftoken'));
    },
});

I'm even forcing the cookie to be set in all views by writing a custom Middleware that calls get_token

def CSRFForceCookieMiddleware(get_response):
    def middleware(request):
        response = get_response(request)
        get_token(request) # Force to set cookie in all responses
        return response
    return middleware

Everything works OK in my localhost and in production for most users. But for some users I get 403 CSRF validation error.

I added a lot of debug info. Turns out that even if CsrfViewMiddleware is setting the csrftoken is setting the cookie in the response, in the actual browser the cookie is not set ($.cookie('csrftoken') is null). So when the ajax call is made, there is no cookie present in the request.

So, I guess this pretty much means that some users' browsers are blocking this cookie? Anyone else had this experience?


Solution

  • Most browsers have an option to "block all cookies". You may want to detect that in javascript and give your users a warning that some functional cookies are required for the site to work correctly. There's another SO question that shows how to do that.

    Alternatively, grab the token from a hidden input field ({% csrf_token %} will add that field in your template). That should always work.