2

Based on the w3schools ajax example I am trying to make a delete call and then remove the corresponding row from a table. There are plenty of answers here about how to do it using JQuery but I am not doing that. I found this answer which made me write my JavaScript like this:

function deleteFullLicense(rowid, objectid) {
    var xhttp = new XMLHttpRequest();
    xhttp.onreadystatechange = function() {
      if (xhttp.readyState == 4 && xhttp.status == 204) {
        row = document.getElementById(rowid);
        row.parentNode.removeChild(row);
      }
      else {
        window.alert("Something went wrong. The delete failed.");
      }
    };
    xhttp.open("POST", "deleteLicense/" + objectid, true);
    xhttp.send({'csrfmiddlewaretoken': '{{ csrf_token }}'});
}

But I get the Forbidden (CSRF token missing or incorrect.) message. How should I send the token?

2
  • 1
    You need to set is as a header. Maybe this can help you: stackoverflow.com/questions/22063612/… Commented Apr 25, 2016 at 15:00
  • I have tried to set it as header using: xhttp.setRequestHeader("csrfmiddlewaretoken", '{{ csrf_token }}') but that makes no difference. Is there something more that needs to be done? Commented Apr 25, 2016 at 15:31

2 Answers 2

3

Turns out if I called it X-CSRFToken instead it worked. Found out about it here if you want to read more.

function deleteFullLicense(rowid, objectid) {
    var xhttp = new XMLHttpRequest();
    xhttp.onreadystatechange = function() {
      if (xhttp.readyState == 4 && xhttp.status == 204) {
        row = document.getElementById(rowid);
        row.parentNode.removeChild(row);
      }
    };
    xhttp.open("POST", "deleteLicense/" + objectid, true);
    xhttp.setRequestHeader("X-CSRFToken", '{{ csrf_token }}')
    xhttp.send();
}
Sign up to request clarification or add additional context in comments.

Comments

1

The header name X-CSRFToken actually comes from the parameter CSRF_HEADER_NAME in Django settings.py. When receiving frontend request (e.g. ajax call), Django internally checks header parameters and converts X-CSRFToken to HTTP_X_CSRFTOKEN which is default value of CSRF_HEADER_NAME .

The better approach would be to :

  • convert the value of CSRF_HEADER_NAME
  • render the converted value in previous step, to the HTML template
  • in the frontend code (e.g. the HTML template or separate js file), create a custom header with that value and the CSRF token on each ajax call for form submission.

Here's a quick example :

In settings.py

CSRF_HEADER_NAME = "HTTP_ANTI_CSRF_TOKEN"

In the view function of views.py

from django.conf import settings
from django.http.request import HttpHeaders

prefix =  HttpHeaders.HTTP_PREFIX
converted = settings.CSRF_HEADER_NAME[len(prefix):]
converted = converted.replace('_','-')
# so the value HTTP_ANTI_CSRF_TOKEN is converted to ANTI-CSRF-TOKEN,
return Response(context={'custom_csrf_header_name':converted})

In your HTML template (not good practice, since this is just quick example)

<script>
// Note that the value is 'ANTI-CSRF-TOKEN'. when this header name goes to
// backend server, Django will internally convert it back to 'HTTP_ANTI_CSRF_TOKEN'
var custom_csrf_header_name = "{{ custom_csrf_header_name }}";

// the ajax part is almost the same as described in the accepted answer
...
xhttp.setRequestHeader(custom_csrf_header_name, '{{ csrf_token }}')
...
</script>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.