9

I'm developing a DJANGO + AngularJS application, where the angular part is not being served by django.

I set the angular $httpProvider as follows:

myApp = angular.module('myApp', [])

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

Then, before doing any POST, I do a GET which sets the cookie. I can confirm through Chrome that the cookie is set:

set-cookie:csrftoken=hg88ZZFEdLPnwDdN1eiNquA8YzTySdQO; expires=Tue, 19-Aug-2014 12:26:35 GMT; Max-Age=31449600; Path=/

(it's visible in resources/cookies/localhost in the Chrome developer tools)

However when I do a POST, no X-CSRFToken header is being set

this is the POST as recorded by Chrome:

POST /data/activities/search HTTP/1.1
Host: localhost:14080
Connection: keep-alive
Content-Length: 2
Accept: application/json, text/plain, */*
Origin: http://localhost:14080
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.95 Safari/537.36
Content-Type: application/json;charset=UTF-8
Referer: http://localhost:14080/public/html/main.html?codekitCB=398694184.799418
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8
Cookie: csrftoken=hg88ZZFEdLPnwDdN1eiNquA8YzTySdQO

Why is no header being set? What else should I do to activate this functionality?

(side note: if I manually pass the header in the $http() call, the POST request works fine.. therefore the problem is really the header not being set by AngularJS)

luca
  • 10,961
  • 13
  • 61
  • 100

5 Answers5

8

very simple answer: it's only available from version 1.2.0, which is at the moment a release candidate.

luca
  • 10,961
  • 13
  • 61
  • 100
  • @OZ_ And who says 1.1.5, says 1.0.x :) – Jesus Rodriguez Aug 30 '13 at 20:19
  • 1
    nope, it's correct, the new automatic way (the one object of this question) is only from angular 1.2, you're doing it manually (which can still be useful) – luca Sep 19 '13 at 14:23
  • It is worth also noting that if you are using django views with a response context, you'll still have no csrf_token if there are no forms in the template (which there often wont be). That is why you may need to use the ensure_csrf_cookie decorator so that the angular api calls will have the token they need. – Paul Whipp Oct 13 '14 at 07:18
5

The 1.2.0 update wasn't sufficient for me when using Safari or Firefox (Chrome was working just fine all the time). The problem with Safari and Firefox was that the Django backend didn't send the csrf-cookie in the HTTP response.

What I had to do was add the @ensure_csrf_cookie decorator to my view function that builds up the page for Angularjs.

@ensure_csrf_token
def my_view(request):
    ...

and in the javascript file:

myApp.config(function($httpProvider) {
    $httpProvider.defaults.xsrfCookieName = 'csrftoken';
    $httpProvider.defaults.xsrfHeaderName = 'X-CSRFToken';
}

At least for now I have no idea why Chrome works without it but the other browsers don't.

Janne
  • 823
  • 1
  • 9
  • 17
2

I had a similar issue and it was embarrassingly my fault.

My mistake:

$.post('/url', data)

Make sure you're using the $http object!

$http.post('/url', data)

It was very easy to make this mistake since both seem to work equally as well as each other, except former does not look at $http.defaults.headers.common['X-CSRFToken'], etc.

gak
  • 29,596
  • 24
  • 111
  • 150
1
app.config(["$httpProvider", function($httpProvider) {
    var csrfToken = getCookie('csrftoken');
    $httpProvider.defaults.headers.common['X-CSRFToken'] = csrfToken; 
}])

getCookie() take from https://docs.djangoproject.com/en/dev/ref/contrib/csrf/


Or set each method separately

 $httpProvider.defaults.headers.post['X-CS....
 $httpProvider.defaults.headers.get['X-CS....
Serge K.
  • 331
  • 3
  • 10
1

Angular changes very frequently and some answers do not work with latest versions. In any way, since Angular expects a XSRF-TOKEN cookie name, and sends a X-XSRF-TOKEN header, we can alternatively simply tell Django to use these by default:

CSRF_COOKIE_NAME = 'XSRF-TOKEN'
CSRF_HEADER_NAME = 'HTTP_X_XSRF_TOKEN'

The first setting (see docs) is the cookie name for the csrf token, whereas the second one (see docs, only introduced in 1.9) is the respective header name.

Last, just for reference, do not forget to set:

CSRF_COOKIE_HTTPONLY = False
Wtower
  • 15,424
  • 11
  • 94
  • 69