Search code examples
djangoapipython-requestscsrfdjango-middleware

Django CSRF Token present but still getting 403 Forbidden Error


I am trying to set up a Django API that receives POST requests with some JSON data and basically sends emails to a list of recipients. The logic is rather simple:

  • First I have the view for when I create a blog post. In the template, I include the csrf_token as specified on the Django Documentation. When I hit the submit button, behind the scene the create-post view, in addition to creating the post, makes a request (I am using the requests module) to the API which is charged with sending the emails. This is the piece of logic the sends the request to the API:

    data = {
              "title": new_post.title,
              "summary": new_post.summary,
              "link": var["BASE_URL"] + f"blog/post/{new_post.slug}"
          }
    
    csrf_token = get_token(request)
    # print(csrf_token)
    headers = {"X-CSRFToken": csrf_token}
    
    requests.post(var["BASE_URL"] + "_api/send-notification/", json=data, headers=headers)
    

As you can see I am adding the X-CSRFToken to the headers which I generate through the get_token() method, as per the Django docs. However, the response in the API is a 403 Forbidden status CSRF Token not set.

I have checked the headers in the request and the token is indeed present. In addition, I have been providing other routes to the API and I have been using it for AJAX calls which again is very simple just follow the Django docs and they work perfectly well.

The problem seems to arise when I make the call from within the view, AJAX calls are handle by Javascript static files, and as I said they work fine.

I have thought that Django didn't allow the use of 2 CSRF tokens on the same page (one for the submit form and the other in the view by get_token()), but that's not the problem. This is typically the error I get:

>>> Forbidden (CSRF cookie not set.): /_api/send-notification/
>>> "POST /_api/send-notification/ HTTP/1.1" 403 2864

I have read several similar questions on SO but they mostly involved using the csrf_exempt decorator, which in my opinion is not really a solution. It just gets rid of the CRSF token usefulness altogether.

Does anyone have any idea what might be causing this problem? Thanks


Solution

  • Error tries to tell you that you need to add token into cookie storage like that:

    cookies = {'csrftoken': csrf_token}
    requests.post(var["BASE_URL"] + "_api/send-notification/", json=data, headers=headers, cookies=cookies)