The Django REST Framework returns a 403 status code in several cases:
- If you do not have the required permission level (for example, if the API request is not authenticated, if
DEFAULT_PERMISSION_CLASSES - ('rest_framework.permissions.IsAuthenticated',) . - When you execute an unsafe type of request (POST, PUT, PATCH or DELETE request, which should have side effects), you use
rest_framework.authentication.SessionAuthentication , and you did not include CSRFToken in the request. - When you execute an unsafe type of request and the CSRFToken that you turned on is no longer valid.
I am going to make some demo requests against the test API to give an example of each of them to help you diagnose what problem you have and show how to solve it. I will use the requests library.
Test API
I installed a very simple DRF API with one model, Life , which contains one field ( answer with a default value of 42 ). Everything that happens here is fairly straightforward; I installed ModelSerializer - LifeSerializer , a ModelViewSet - LifeViewSet and a DefaultRouter on the URL /life route. I configured DRF to require user authentication to use the API and use SessionAuthentication .
API enable
import json import requests response = requests.get('http://localhost:8000/life/1/') # prints (403, '{"detail":"Authentication credentials were not provided."}') print response.status_code, response.content my_session_id = 'mph3eugf0gh5hyzc8glvrt79r2sd6xu6' cookies = {} cookies['sessionid'] = my_session_id response = requests.get('http://localhost:8000/life/1/', cookies=cookies) # prints (200, '{"id":1,"answer":42}') print response.status_code, response.content data = json.dumps({'answer': 24}) headers = {'content-type': 'application/json'} response = requests.put('http://localhost:8000/life/1/', data=data, headers=headers, cookies=cookies) # prints (403, '{"detail":"CSRF Failed: CSRF cookie not set."}') print response.status_code, response.content # Let grab a valid csrftoken html_response = requests.get('http://localhost:8000/life/1/', headers={'accept': 'text/html'}, cookies=cookies) cookies['csrftoken'] = html_response.cookies['csrftoken'] response = requests.put('http://localhost:8000/life/1/', data=data, headers=headers, cookies=cookies) # prints (403, '{"detail":"CSRF Failed: CSRF token missing or incorrect."}') print response.status_code, response.content headers['X-CSRFToken'] = cookies['csrftoken'] response = requests.put('http://localhost:8000/life/1/', data=data, headers=headers, cookies=cookies) # prints (200, '{"id":1,"answer":24}') print response.status_code, response.content
source share