[Django]-POST method always return 403 Forbidden

3👍

Try putting RequestContext in the search_form view’s render_to_response:

context_instance=RequestContext(request)

20👍

I maybe wrong however I found the above solutions rather complex.

what worked for me was simply including my csrf token into my post request.

$.ajax({
    type: "POST",
    url: "/reports/",
    data: { csrfmiddlewaretoken: "{{ csrf_token }}",   // < here 
            state:"inactive" 
          },
    success: function() {
        alert("pocohuntus")
        console.log("prototype")
    }
})
👤laycat

13👍

This answer is for people that may encounter this same problem in the future.

The CSRF {{csrf_token}} template tag that is required for forms in Django prevent against Cross Site Request Forgeries. CSRF makes it possible for a malicious site that has been visited by a client’s browser to make requests to your own server. Hence the csrf_token provided by django makes it simple for your django server and site to be protected against this type of malicious attack. If your form is not protected by csrf_token, django returns a 403 forbidden page. This is a form of protection for your website especially when the token wasn’t left out intentionally.

But there are scenarios where a django site would not want to protect its forms using the csrf_token. For instance, I developed a USSD application and a view function is required to receive a POST request from the USSD API. We should note that the POST request was not from a form on the client hence the risk of CSRF impossible, since a malicious site cannot submit requests. The POST request is received when a user dials a USSD code and not when a form is submitted.

In other words, there are situations where a function will need to get a POST request and there would not be the need of {{csrf_token}}.

Django provides us with a decorator @csrf_exempt. This decorator marks a view as being exempt from the protection ensured by the middleware.

from django.views.decorators.csrf import csrf_exempt
from django.http import HttpResponse

@csrf_exempt
def my_view(request):
    return HttpResponse('Hello world')

Django also provides another decorator that performs the same function with {{csrf_token}}, but it doesn’t reject incoming request. This decorator is @requires_csrf_token. For instance:

@requires_csrf_token
def my_view(request):
    c = {}
    # ...
    return render(request, "a_template.html", c)

The last decorator that will be mentioned in this post does exactly the same thing as {{csrf_token}} and it is called @csrf_protect. However, the use of this decorator by itself is not best practice because you might forget to add it to your views. For instance:

@csrf_protect
def my_view(request):
    c = {}
    # ...
    return render(request, "a_template.html", c)

Below are some links that will guide and explain better.

https://docs.djangoproject.com/en/1.7/ref/contrib/csrf/#module-django.views.decorators.csrf

https://docs.djangoproject.com/en/1.7/ref/contrib/csrf/

http://www.squarefree.com/securitytips/web-developers.html#CSRF

5👍

The easiest way to avoid such problems is to use the render shortcut.

from django.shortcuts import render
# .. your other imports

def search_form(request):
    return render(request, 'library/search_form.html')

def search(request):
    q = request.GET.get('q')
    results = BookModel.objects.all()
    if q:
        results = results.filter(title__icontains=q)
    return render(request, 'library/search.html', {'result': results})

2👍

The response is 403 bcoz,
django requires a csrf token (included in the post data) in every POST request you make.

There are various ways to do this such as:

Acquiring the token from cookie and the method has been explained in article enter link description here

or

You can access it from DOM using {{ csrf_token }}, available in the template

So now using the second method:

var post_data = {
  ...
  'csrfmiddlewaretoken':"{{ csrf_token }}"
  ...
}
$.ajax({
  url:'url',
  type:'POST'
  data:post_data,
  success:function(data){
    console.log(data);
  },
  error:function(error){
    console.log(error);
  }
});
👤Hiro

1👍

You need to use RequestContext with your response

for example
in view.py file

from django.template import RequestContext

def home(request):
    return render_to_response('home.html',RequestContext(request, {}))

0👍

You also can use

direct_to_template(request, 'library/search.html', result) 

instead of

render_to_response('library/search.html', result, context_instance=RequestContext(request))

because direct_to_template adds RequestContext automatically. But note that direct_to_template is going to be deprecated and django offers to use CBV TemplateView instead.

RequestContext allows you to use context processors. And this is your mistake: {% csrf_token %} outputed empty string and you got 403.

👤San4ez

0👍

This solved it for me. As the Django documentation says, there is some processing that needs to be done before being able to directly make POST method to your RESTAPI. Here is the code :

function getCookie(name) {
    let cookieValue = null;
    if (document.cookie && document.cookie !== '') {
        const cookies = document.cookie.split(';');
        for (let i = 0; i < cookies.length; i++) {
            const cookie = cookies[i].trim();
            // Does this cookie string begin with the name we want?
            if (cookie.substring(0, name.length + 1) === (name + '=')) {
                cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                break;
            }
        }
    }
    return cookieValue;
}

const csrftoken = getCookie('csrftoken');
console.log(csrftoken)





$.ajax({
    method:'POST',
    url:"//127.0.0.1:8000/app/homepage/", /*change it to your api endpoint*/
    headers: {'X-CSRFToken': csrftoken},
    data : { "data" : "3"}
    
   
})

One thing I cannot assure with this solution, is the security aspect.

Leave a comment