Django Csrf Token + Angularjs

Django csrf token + Angularjs

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.

What is the recommended way to have CSRF protection in a Django Rest Framework + Angular application?

The Angular recommended way is explained in the HTTP Guide but, for some of us, it has some tricky steps. Fortunately, in recent versions of Angular, you need minimal changes. And all the default/recommended CSRF middleware behaves well once things have been set up. There is some information DRF-specific and also a reference to the Django official documentation

The minimal changes that, right now, are working for me (Django 2.1, Angular 6, and up-to-date version of dependencies) are the following

Django side

First of all, you need to set up Django to send the cookie as Angular expects:

# settings.py
CSRF_USE_SESSIONS = False
CSRF_COOKIE_HTTPONLY = False # this is the default, and should be kept this way
CSRF_COOKIE_NAME = 'XSRF-TOKEN'
CSRF_HEADER_NAME = 'HTTP_X_XSRF_TOKEN'

Caution! Remember that cookie names are case sensitive. I lost a lot of time there :(

Note that the CSRF cookie should be accessible by the Javascript, so httpOnly flag should not be set to True.

Here I am assuming that you already have a functional authentication system and are using both django.contrib.sessions.middleware.SessionMiddleware and django.middleware.csrf.CsrfViewMiddleware (typically you will find those modules listed in the MIDDLEWARE variable in the settings.py).

Angular side

Then, activate the CSRF at the angular side:

# app.module.ts
import {HttpClientModule, HttpClientXsrfModule} from '@angular/common/http';

...

@NgModule({
imports: [
// ...
HttpClientModule,
HttpClientXsrfModule,
]
// ...

If you don't want to change Django default name for CSRF Header and Cookie, you can instead change them at the Angular side, by changing HttpClientXsrfModule, line for:

HttpClientXsrfModule.withOptions({
cookieName: 'csrftoken',
headerName: 'X-CSRFTOKEN',
}),

I have not fully tested this configuration. Remember that, at the Django side, you have to change a little bit the CSRF_HEADER_NAME (at least: hyphen-to-underscores and HTTP_ prefix). The previous example should match de fault value of HTTP_X_CSRFTOKEN. The default CSRF_COOKIE_NAME Django setting is csrftoken (lowercase).

If you have problems with custom namings, check the actual headers inserted by Angular (with developer tools of your browser), and you can double check how are you receiving them in Django by debugging the content of request.META

Django Rest Framework + AngularJS: Correct way for CSRF Protection?

Your second way ($httpProvider.defaults) is probably the best way to do it. See the angular docs on http here. The xsrfCookieName and xsrfHeaderName options are relatively new in Angular. (I think they came in in 1.3, if memory serves...) So the other code you found probably just predated the newer, better way to do it. No need for a rendering or escape call in the template = cleaner code.

Pass Django CSRF token to Angular with CSRF_COOKIE_HTTPONLY

Django has a documented solution for this. Any Javascript can get the CSRF token from the DOM even if CSRF_COOKIE_HTTPONLY is enabled as long as the CSRF token is in the DOM.

Step 1: I add a tag to let Django middleware put csrf token to the DOM

# Django put CSRF token to DOM
{% csrf_token %}

How to create a POST request (including CSRF token) using Django and AngularJS

Can't you make a call like this:

$http({
method: 'POST',
url: url,
data: xsrf,
headers: {'Content-Type': 'application/x-www-form-urlencoded'}
})

The data can be whatever you wish to pass and then just append &{{csrf_token}} to that.

In your resource params:{}, try adding csrfmiddlewaretoken:{{csrf_token}} inside the params

Edit:

You can pass data to the request body as

item.$update({csrfmiddlewaretoken:{{csrf_token}}})

and to headers as

var csrf = '{{ csrf_token }}'; 
update:{method:'POST', headers: {'X-CSRFToken' : csrf }}

It is an undocumented issue



Related Topics



Leave a reply



Submit