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?