53

when I'm using following Python code to send a POST request to my Django website I'm getting 403: Forbidden error.

url = 'http://www.sub.example.com/'
values = { 'var': 'test' }

try:
    data = urllib.urlencode(values, doseq=True)
    req = urllib2.Request(url, data)
    response = urllib2.urlopen(req)
    the_page = response.read()
except:
    the_page = sys.exc_info()
    raise

When I'm opening any other website it works properly. example.com is Django website too, and it works properly too. I think, that's Django config problem, can anyone tell me what should I do to provide access to my script?

Stephen Ostermiller
  • 23,933
  • 14
  • 88
  • 109
Djent
  • 2,877
  • 10
  • 41
  • 66

7 Answers7

51

Look here https://docs.djangoproject.com/en/dev/ref/csrf/#how-to-use-it.

Try marking your view with @csrf_exempt. That way, Django's CSRF middleware will ignore CSRF protection. You'll also need to use from django.views.decorators.csrf import csrf_exempt. See: https://docs.djangoproject.com/en/dev/ref/csrf/#utilities

Please be advised that by disabling CSRF protection on your view, you are opening a gate for CSRF attacks.

If security is vital to you then consider using @csrf_exempt followed by @requires_csrf_token (see: https://docs.djangoproject.com/en/dev/ref/csrf/#unprotected-view-needs-the-csrf-token). Then, in your script pass this token and that's it.

bx2
  • 6,356
  • 5
  • 36
  • 40
  • 1
    Thank you so very much for sharing above two links. My code is running perfectly fine after adding this import statement from django.views.decorators.csrf import csrf_protect and after making specific function exempted like this @csrf_exempt Once again thanks alot. – Anil Chahal Jun 04 '15 at 13:10
36

Does the view that you are posting to have a Django Form on it? If so, I wonder if it's giving a csrf error. I think that manifests itself as a 403. In that case, you'd need to add the {{ csrf_token }} tag. Just a thought.

Joe J
  • 9,985
  • 16
  • 68
  • 100
  • Where have I to add that tag? If in template - it doesn't work. Here's my view: http://dpaste.com/575405/, t.html is simply {{ form }} – Djent Jul 23 '11 at 15:13
  • 2
    can you update the original question to inclue your code(view, urls, form) and html instead of linking off to dpaste? – Ken Cochrane Jul 23 '11 at 15:37
  • @Djent why is t.html only a {{form}} is it included into other pages? if you just put {{form}} it isn't a valid webpage, and not even a valid form since {{form}} just puts the form elements you still need to add the form tags around it. – Ken Cochrane Jul 23 '11 at 15:39
  • 1
    If it is a csrf problem you can try to disable csrf temporarliy on the view and see if that works, and if so then you know what the issue is. see this documentation for more help. https://docs.djangoproject.com/en/1.3/ref/contrib/csrf/#exceptions – Ken Cochrane Jul 23 '11 at 15:43
  • Correct answer. – hygull Jun 09 '19 at 07:26
3

The response is 403 because 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);
  }
});
chrki
  • 6,143
  • 6
  • 35
  • 55
Hiro
  • 2,992
  • 1
  • 15
  • 9
2

Or you can allow the permission to make this post request.

Note: Should be used in the cases where you don't need to authenticate the users for posting anything on our server, say, when a new user registers for the first time.

from rest_framework.permissions import AllowAny

class CreateUser(APIView):
    permission_classes = (AllowAny,)
    def post(self, request, format=None):
        return(Response("hi"))

Further Note that, If you want to make that post request form a different domain (in case when the front of the application is in React or angular and the backend is in Django), make sure the add following in the settings file:

  1. Update the INSTALLED_APPS to use 'coreHeaders' :

    INSTALLED_APPS = [
    'corsheaders',
    ]

  2. White list your front end domain by adding following to settings file again:

    CORS_ORIGIN_WHITELIST = ( 'localhost:8080', )

Santosh Pillai
  • 8,169
  • 1
  • 31
  • 27
1

Django documentation provides several ways to ensure that CSRF tokens are included. See https://docs.djangoproject.com/en/1.11/ref/csrf/ for details.

polarise
  • 2,303
  • 1
  • 19
  • 28
1

I got this error when an authentication Token was expired or when no Token was sent with the request. Using a renewed token fixed the problem.

curl -X POST -H "Authorization: Token mytoken" -d "name=myname&age=0" 127.0.0.1:8000/myapi/

or

curl -X POST -H "Authorization: JWT mytoken" -d "name=myname&age=0" 127.0.0.1:8000/myapi/

depending on Token type.

DevB2F
  • 4,674
  • 4
  • 36
  • 60
0

I too had this problem, because I Tried to access the Main endpoint from another endpoint using '../url' URL Jumping. My Solution was to add another path for the same viewset;

router.register('main/url',ViewSet,'name');
router.register('secondary/url',ViewSet,'name')

But in Your Case You are Trying to access it from a completely different Location, From Django's Point of view So You need to mark you ViewSet with @crsf_exempt middleware which will Disable Security Protocols Related to CRSF.

ax39T-Venom
  • 32
  • 1
  • 5