Proper Django CSRF validation using fetch post request
Figured this out. The issue is that fetch
doesn't include cookies by default.
Simple solution is to add credentials: "same-origin"
to the request and it works (with the form field but without the headers). Here's the working code:
let data = new FormData();
data.append('file', file);;
data.append('fileName', file.name);
// add form input from hidden input elsewhere on the page
data.append('csrfmiddlewaretoken', $('#csrf-helper input[name="csrfmiddlewaretoken"]').attr('value'));
fetch("/upload/", {
method: 'POST',
body: data,
credentials: 'same-origin',
})
Your question is very close to success. Here is a json way if you do not want the form method. Btw, @Cory's form method is very neat.
- Neat way with 3rd library
let data = {
'file': file,
'fileName': file.name,
};
// You have to download 3rd Cookies library
// https://docs.djangoproject.com/en/dev/ref/csrf/#ajax
let csrftoken = Cookies.get('csrftoken');
let response = fetch("/upload/", {
method: 'POST',
body: JSON.stringify(data),
headers: { "X-CSRFToken": csrftoken },
})
2. Another cumbersome way, but without any 3rd library
let data = {
'file': file,
'fileName': file.name,
};
let csrftoken = getCookie('csrftoken');
let response = fetch("/upload/", {
method: 'POST',
body: JSON.stringify(data),
headers: { "X-CSRFToken": csrftoken },
})
// The following function are copying from
// https://docs.djangoproject.com/en/dev/ref/csrf/#ajax
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 = cookies[i].trim();
// 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;
}