How to get / provide CSRF token to / from Django as an API

I am working on a project that uses the Django REST Framework as a backend (say, at api.somecompany.com , but has an external React.js interface (at www.somecompany.com ) that is not served by Django, which handles AJAX requests.

Therefore, I cannot use the traditional Django method to have the template include a CSRF token like this <form action="." method="post">{% csrf_token %} <form action="." method="post">{% csrf_token %}

I can make a request to the Django REST Framework api-auth\login\ url that will return this header: Set-Cookie:csrftoken=tjQfRZXWW4GtnWfe5fhTYor7uWnAYqhz; expires=Mon, 01-Aug-2016 16:32:10 GMT; Max-Age=31449600; Path=/ Set-Cookie:csrftoken=tjQfRZXWW4GtnWfe5fhTYor7uWnAYqhz; expires=Mon, 01-Aug-2016 16:32:10 GMT; Max-Age=31449600; Path=/ Set-Cookie:csrftoken=tjQfRZXWW4GtnWfe5fhTYor7uWnAYqhz; expires=Mon, 01-Aug-2016 16:32:10 GMT; Max-Age=31449600; Path=/ - but I cannot extract this cookie to send back with my AJAX requests using X-CSRFToken (my understanding refers to a separate subdomain), and it does not seem to turn on automatically.

Here is my corresponding code:

 // using jQuery function getCookie(name) { var cookieValue = null; if (document.cookie && document.cookie != '') { var cookies = document.cookie.split(';'); for (var i = 0; i < cookies.length; i++) { var cookie = jQuery.trim(cookies[i]); // Does this cookie string begin with the name we want? if (cookie.substring(0, name.length + 1) == (name + '=')) { cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); break; } } } return cookieValue; } function csrfSafeMethod(method) { // these HTTP methods do not require CSRF protection return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method)); } $.ajaxSetup({ beforeSend: function(xhr, settings) { if (!csrfSafeMethod(settings.type)) { xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken')); } } }); 

As the page loads, I call this to make sure I have a token:

 $.ajax(loginUrl, { method: "OPTIONS", async: false }) .done(function(data, textStatus, jqXHR) { console.log(jqXHR) app.csrftoken@ = $.cookie("csrftoken") console.log($.cookie("csrftoken")) console.log(app.csrftoken) }) .fail(function(jqXHR, textStatus, errorThrown) { console.log(jqXHR) }); 

This is not entirely clean, but I have not yet proven my concept.

What is the β€œcorrect” way to authenticate / protect against CSRF when the interface and backend are on different ports / domains?

+5
source share
1 answer

You can essentially do this job with CSRF protection using a whitelist of allowed query sources.

To do this, you will need to use Cross-Origin Resource Sharing (CORS). To achieve this, I would recommend creating a middleware class that will set your credentials for sharing. There's a great style outlining how to use some of the cross-header collectors for HTTP headers. You can, if you wish, insert the CSRF token using middleware in this way by changing the initial values ​​for the query for the query.

The django-cors-headers app does this for you. You can see how they matched the CSRF tokens into their middleware file if you're interested.

Read more about this in the Django REST CORS Docs (using django-cors-headers is recommended).

If you still have difficulties, try:

  • setting the crossDomain parameter of your AJAX request to True . Sometimes jQuery does not process the request unless specified.
  • if you still don't get the marker header in the request at all, try adding the ensure_csrf_cookie() decorator around your browsing method. Sometimes, when there is no {% csrf_token %} template tag on the page (if you do not show the form), Django will not include the token in the request at all.
+1
source

All Articles