I'm working on a project that uses the Django REST Framework as a backend (let's say at api.somecompany.com
but has a React.js frontend (at www.somecompany.com
) not served by Django that makes AJAX requests.
I can't, therefore, use Django's traditional method of having the template include the CSRF token like this <form action="." method="post">{% csrf_token %}
I can make a request to Django REST Framework's api-auth\login\
url, which will return this header:
Set-Cookie:csrftoken=tjQfRZXWW4GtnWfe5fhTYor7uWnAYqhz; expires=Mon, 01-Aug-2016 16:32:10 GMT; Max-Age=31449600; Path=/
- but I can't then retrieve this cookie to send back with my AJAX requests with X-CSRFToken
(my understanding is of the separate subdomain), and it doesn't seem to be included automatically.
Here's my relevant 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 isn't exactly clean but I haven't proven the concept to myself yet.
What is the 'correct' way of authenticating / protecting against CSRF when the frontend and backend are on different ports/domains?