2

I have a problem with the CSRF token mechanism in Django that only occurs in Firefox and Internet Explorer (Chrome seems to work just fine). My site serves a page which performs an AJAX call once the page is ready(). When the AJAX call is issued, I get a 403 Forbidden error stating CSRF verification failed. Request aborted. The reason given by the error page is CSRF cookie not set.

I've already looked at Django CSRF check failing with an Ajax POST request, and I'm following the accepted answer there. However, I still see problems in 2 out of 3 browsers.

When I inspect the headers for this call, I see the csrftoken being set properly, but the value doesn't match the value set in the page! (I was wrong about the values not matching. The "View Source" option in Firefox apparently reloads the page, rather than show the source of the page you're viewing.)

My server was set up by following this article, though I'm using SQLite at the moment over Postgres. Why should I be getting 403 errors when the token is being passed properly?

Here's my AJAX call:

$.ajax({
    beforeSend: function(xhr, settings) {
        csrftoken = getCookie('csrftoken');
        if(!csrfSafeMethod(settings.type) && !this.crossDomain) {
            xhr.setRequestHeader("X-CSRFToken", csrftoken);
        }
    },
    url: "{% url 'cap_plan:ajax_get_chart_data' %}",
    type: "POST",
    success: drawChart,
    error: function(xhr, errmsg, err) {
        // TODO: Do something better in the error case
        console.log("AJAX Error!");
        console.log(xhr.status + ": " + xhr.responseText);
    }
});

The getCookie() and csrfSafeMethod routines are the exact ones listed in the official CSRF documentation.

Here's the URL rule that's put into play for this call:

url(r'^ajax/get_chart_data/$', ajax_get_chart_data, name='ajax_get_chart_data'),

And here's a simplified look at the respective view for the overall page:

@ensure_csrf_cookie
def cap_plan_overview(request):
    return render_to_response('cap-plan-overview.html',
      {}, context_instance=RequestContext(request))

And the view for the AJAX call itself (again, simplified):

def ajax_get_chart_data(request):
    if request.method == 'POST':
        // Do a bunch of work getting data; put it in the response dict
        return HttpResponse(
            json.dumps(response),
            content_type="application/json"
        )
    else:
        return HttpResponse(
            json.dumps({error: "Invalid AJAX call to ajax_get_chart_data"}),
            content_type="application/json"
Community
  • 1
  • 1
Jonah Bishop
  • 12,279
  • 6
  • 49
  • 74
  • duplicate? check this: http://stackoverflow.com/questions/5100539/django-csrf-check-failing-with-an-ajax-post-request – Bogdan Goie Jul 08 '15 at 15:27
  • I found that question, and my code implements that exact solution that was accepted, but I still get 403. My problem also appears to be browser specific, for reasons I don't understand. :-( – Jonah Bishop Jul 08 '15 at 15:29
  • hmm, did you add the entire code from that answer ($.ajaxSetup...) before doing anything in your ajax call? you should have that code to set up ajax and afterwards do your ajax call (but remove beforeSend from your $.ajax, it should be in $.ajaxSetup ) – Bogdan Goie Jul 08 '15 at 15:35
  • According to the official jQuery documentation, use of `ajaxSetup()` is not recommended. The `ajax()` call allows you to set up a `beforeSend` function per call, which is what I'm doing here. – Jonah Bishop Jul 08 '15 at 15:49
  • why is it not recommended? I use ajaxSetup() instead of ajax() and I have almost exact code with no 403. – Camron_Godbout Jul 08 '15 at 16:52

0 Answers0