Django csrf token + Angularjs

Question:

I have django running on an apache server using mod_wsgi, as well as an angularjs app served directly by apache, not by django. I would like to make POST calls to the django server (running rest_framework) but I am having problems with the csrf token.

Is there someway to set the token from the server without putting {% csrf token %} as part of the template (since these pages aren’t going through django)?

  1. I would like to be able to get a csrf token through a GET request as a cookie.
  2. I would like to be able to then make POST requests to the django server with the csrf token cookie value.
Asked By: Preom

||

Answers:

Django and AngularJS both have CSRF support already, your part is quite simple.

First, you need to enable CSRF in Django, I believe you have already done so, if not, follow Django doc https://docs.djangoproject.com/en/1.5/ref/contrib/csrf/#ajax.

Now, Django will set a cookie named csrftoken on the first GET request and expects a custom HTTP header X-CSRFToken on later POST/PUT/DELETE requests.

For Angular, it expects the cookie named XSRF-TOKEN and will do POST/PUT/DELETE requests with X-XSRF-TOKEN header, so you need to do a little bit tweak to make the two go with each other:

$httpProvider.defaults.xsrfCookieName = 'csrftoken';
$httpProvider.defaults.xsrfHeaderName = 'X-CSRFToken';

Add above two lines somewhere in your js code, module.config() block is a good place for this.

That’s it.

NOTE: This is for angular 1.1.5, older versions might need different approach.

Update:

Since the angular app isn’t served by django, in order to let the cookie to be set, angular app needs to do a GET request to django first.

Answered By: Ye Liu

After searching around, what worked for me was from this post with the following code:

angular.module( '[your module name]',
    ... [some dependencies] ...
    'ngCookies',
    ... [other dependencies] ...
)
.run( function run( $http, $cookies ){

    // For CSRF token compatibility with Django
    $http.defaults.headers.post['X-CSRFToken'] = $cookies.get('csrftoken');
})

This is of course after getting the cookie through a GET request from the django server.

I also looked into some of the other answers here, including Ye Liun’s but couldn’t find anything in the official docs specifying changes to the defaults options for xsrf on $httpProvider, other than this pull request which didn’t work for me at the time of me writing this post.

Answered By: Preom
var foo = angular.module('foo', ['bar']);

foo.config(['$httpProvider', function($httpProvider) {
    $httpProvider.defaults.xsrfCookieName = 'csrftoken';
    $httpProvider.defaults.xsrfHeaderName = 'X-CSRFToken';
}]);

And all modules services and controllers, where $http used, will send requests with csrf token.

Answered By: Nikolay Baluk

I created a Django App for my AngularJS app, in the same Django project as my (REST) API Django App, that only serves the index.html file (which is just a sym.link). In this way the CSRF Cookie is set without an additional GET request.

Please see my answer here about AngularJS Single Page Web Application on Sub-domain A talking to a Django JSON (REST) API on Sub-domain B using CORS and CSRF protection

Answered By: Visionscaper

If you have your cookies set to disallow javascript access, you need to do the following. In your template, before creating the django app, add this:

<script>
    window.csrf_token = "{{ csrf_token }}";
</script>

In your angular app, add this:

angularApp.config(["$httpProvider", function($httpProvider) {
    $httpProvider.defaults.headers.common["X-CSRFToken"] = window.csrf_token;
}]);

At least through Django 1.9, the CSRF token does not change with each request. It only changes when a user logs in. If you are doing a single page angular app, you need to make sure you reset the token on login/logout and this should work fine.

NOTE: This does not currently work in Django 1.10 or later due to the CSRF token changing on each request. See Pass Django CSRF token to Angular with CSRF_COOKIE_HTTPONLY

Answered By: Zags