Template-less Django + AJAX: Does Django's CSRF token get updated during the course of a browsing session?

StackOverflow https://stackoverflow.com/questions/20361653

  •  28-08-2022
  •  | 
  •  

Question

My current setup is AngularJS + Django 1.5 and I have completely thrown away the use of Django's template engine (ie. the backend is pretty much an API server).

Since I am not using the csrf_token template tag, Django, in turn, does not set and send the csrftoken cookie in response. As instructed by the official docs, the ensure_csrf_cookie() decorator should be used to force the decorated view to send the csrftoken cookie.

I have applied the ensure_csrf_cookie() decorator to the view, which serves the first GET request that my web client calls at bootstrapping. With that, my web client gets a hold of the CSRF token and henceforth is allowed to call unsafe methods (ex. POST) to the server.

The above setup works fine only if the CSRF token remains the same until the browsing session ends.

Question: Does Django's CSRF token get updated during the course of a browsing session? If 'yes', does that mean I would need to apply the ensure_csrf_cookie() decorator to all the views I have?

Was it helpful?

Solution

1) Does Django's CSRF token get updated during the course of a browsing session?

Looks like the CSRF token is unique per session, but it is based in my observations, I have no "official" source. With Angular.js I use the following code without problems:

angular.module('app', ...)
  .config(function($httpProvider) {
    var cookies = document.cookie.split(';');
    var csrftoken = _.find(cookies, function(v) { 
                      return v.trim().indexOf('csrftoken=') == 0; 
                    });
    if(csrftoken) {
      $httpProvider.defaults.headers.common['X-CSRFToken'] = csrftoken.split('=')[1];
    }
  })

Since I serve the HTML from Django, by the time Angular bootstraps the cookie is already there.

2) If 'yes', does that mean I would need to apply the ensure_csrf_cookie() decorator to all the views I have?

You can try CORS instead if CSRF. Otto Yiu maintains the django-cors-headers package, which is known to work correctly with REST framework APIs.

Some (untested) ideas to apply ensure_csrf_cookie():

  • monkey-patch APIView
  • create a CSRFCookie mixin and add it to your views
  • apply ensure_csrf_cookie() to your base classes

OTHER TIPS

Giving support to the @Paulo Scardine ideas of applying the ensure_csrf_cookie() (which I consider valid, and useful), I would like to add a new one possible solution to it, if you definitely have to ensure_csrf_cookie() in all your views. You could write a custom middleware, and implement the logic that is there inside the ensure_csrf_cookie. Something like this:

On your app.middleware.py:

from django.middleware.csrf import get_token


class EnsureCsrfCookie(object):

    def process_request(self, request):
        # Forces process_response to send the cookie
        get_token(request)

and of courses on your settings file add the middleware to the MIDDLEWARE_CLASSES:

MIDDLEWARE_CLASSES = (
    .,
    .,
    .,
    'app.middleware.EnsureCsrfCookie',
    .,
    .,
    .,
)

It is just one idea more to face this problem. I hope it can be useful for somebody in the future.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top