Search code examples
ajaxdjango-csrfcsrf-protection

Ajax POST with csrfmiddlewaretoken and csrftoken cookie set still gets django 403 Forbidden


I've read that both the csrfmiddlewaretoken and the csrftoken cookie have to be the correct value for a django POST request to succeed (django: csrftoken COOKIE vs. csrfmiddlewaretoken HTML Form value). This is the case for me yet I still get a 403:

In the chrome console:

document.cookie

returns

"csrftoken=Wt9eeJop5Vb3OmeNTvogegckm1pVM5MD"

but

$.get('https://learningdollars.fwd.wf/csrftoken/', function(data){
    console.log(data)
    token = $.parseHTML(data)[0].value
    console.log(token)
    $.ajax({
        type: "POST",
        url: 'https://learningdollars.fwd.wf/confirmemail/',
        data: {email: '[email protected]', csrfmiddlewaretoken: token},
        contentType: "application/json"
    })
    .done(function(response) {
        console.log('done!')
    })
    .fail(function(error) {
        console.log('fail!')
    })
})

returns

> Object {readyState: 1, getResponseHeader: function, getAllResponseHeaders: function, setRequestHeader: function, overrideMimeType: function…}
> <input type='hidden' name='csrfmiddlewaretoken' value='Wt9eeJop5Vb3OmeNTvogegckm1pVM5MD' />
> Wt9eeJop5Vb3OmeNTvogegckm1pVM5MD
> POST https://learningdollars.fwd.wf/confirmemail/ 403 (Forbidden)
> fail! 

I have

'django.middleware.csrf.CsrfViewMiddleware',

activated in my django middleware.

My root urls.py contains:

url(r'^csrftoken/$', views.get_csrf_token),
url(r'^confirmemail/$', views.confirm_email, name='confirm_email'),

And, my views are:

def get_csrf_token(request):
    c = {}
    c.update(csrf(request))
    print c
    return render_to_response('csrf.html', c)

def confirm_email(request):
    print 'here'
    return JsonResponse({'response': 0})

And by the way, the contents of csrf.html are just the csrftoken (inside an input tag):

{% csrf_token %}

What am I doing wrong?


Solution

  • Well, I found a solution. It was just sending in the data as a URI rather than as json. (I by the way tried specifying dataType: 'json' in the above to no avail.) The following is in the chrome console:

    > email = '[email protected]'
    < "[email protected]"
    
    > csrftoken = 'L2MxD1XQIF1Xto5NkzUgGUYiHPyyz3K5'
    < "L2MxD1XQIF1Xto5NkzUgGUYiHPyyz3K5"
    
    > $.ajax({
        type: "POST",
        url: 'https://learningdollars.fwd.wf/confirmemail/',
        data: "email="+ encodeURI(email) + "&csrfmiddlewaretoken=" + encodeURI(csrftoken),
        success: function(data) { console.log(data); }
    })
    
    < Object {response: 1}
    

    Still unsure what I was doing wrong on the json side, but the following is what I tried:

    $.ajax({
        type: "POST",
        url: "https://learningdollars.fwd.wf/confirmemail/",
        data: JSON.stringify({ email: email, csrfmiddlewaretoken: csrftoken }),
        contentType: "application/json; charset=utf-8",
        dataType: "json",
        success: function(data){
            alert(data);
        },
        failure: function(errMsg) {
            alert(errMsg);
        }
    });