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)
very simple answer: it's only available from version 1.2.0, which is at the moment a release candidate.
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.
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.
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....
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