17

I use the getCookie function from the django documentation to get the csrfmiddlewaretoken value.

I have the following ajax call:

var url = reverse_removeprofile.replace(/deadbeef/, key);
$.ajax({
    type:          "DELETE",
    url:           url,
    data:          "csrfmiddlewaretoken=" + getCookie("csrftoken"),
    success:       function() { ... },
});

When this code gets executed then django raises a 403 exception telling me that the CSRF verification failed. However, if I change the type from DELETE to POST then django is happy about it and doesn't complain at all.

I was not really able to find something useful in Google about this, but I've found this (now closed and fixed) ticket: https://code.djangoproject.com/ticket/15258

If I understand it correctly then this issue has been fixed in the 1.4 milestone. I use django 1.4 but still I cannot verify the CSRF token with a DELETE request.

Am I missing something here?

Pablo
  • 13,271
  • 4
  • 39
  • 59

2 Answers2

41

This appears to be a jQuery bug, caused by some confusion as to whether DELETE data should be attached to the URL (like a GET request) or the request body (like a POST)

See this bug report.

You can probably get around this by using the alternative CSRF method for AJAX calls, setting an X-CSRFToken header on the request. Try changing your AJAX call to look like this:

$.ajax({
    type: "DELETE",
    url: url,
    beforeSend: function(xhr) {
        xhr.setRequestHeader("X-CSRFToken", getCookie("csrftoken"));
    },
    success: function() { ... },
});
slumtrimpet
  • 3,159
  • 2
  • 31
  • 44
Ian Clelland
  • 43,011
  • 8
  • 86
  • 87
  • thank's a lot! This solved the problem :) and there I was blaming the csrf-middleware stuff. – Pablo Oct 26 '12 at 17:31
  • Wow. I never would have figured that out on my own. Thanks. – Nostalg.io Sep 24 '15 at 08:01
  • 1
    I just faced this issue in 2019. The solution still works! I was also adding the csrftoken in the 'data' attribute of the AJAX call, but I guess, this is not attached in the request when the 'DELETE' method is being used, so the backend never receives the token. – Utkarsh Sinha Nov 08 '19 at 16:24
  • This is still an issue in 2020. If you use `$.ajax` for `POST` and for `DELETE` you must pass the csrf this way. Also, pycharm does not recognize that `beforeSend` is being used. It suggests remove unused property, even though it is required. – Rob May 26 '20 at 14:48
1

Please note, when it comes to DELETE requests DJango does not check for csrfmiddlewaretoken in the request body. Rather it looks for X-CSRFToken header

Coming to working of DJango CSRFMiddleware you can see the source code of django > middleware > csrf.py > CsrfViewMiddleware in which it is very clear that DJango does not scan for csrfmiddlewaretoken in request body if the request is of DELETE type:

        # Check non-cookie token for match.
        request_csrf_token = ""
        if request.method == "POST":
            try:
                request_csrf_token = request.POST.get('csrfmiddlewaretoken', '')
            except OSError:
                # Handle a broken connection before we've completed reading
                # the POST data. process_view shouldn't raise any
                # exceptions, so we'll ignore and serve the user a 403
                # (assuming they're still listening, which they probably
                # aren't because of the error).
                pass

        if request_csrf_token == "":
            # Fall back to X-CSRFToken, to make things easier for AJAX,
            # and possible for PUT/DELETE.
            request_csrf_token = request.META.get(settings.CSRF_HEADER_NAME, '')
Akhil Kokani
  • 109
  • 1
  • 13