I am building a REST API with Django Rest Framework. I currently have an issue where some of my endpoints return HTTP 401 Unauthorized, whereas the vast majority of my endpoints return correct responses. For authentication I am using JWT tokens with djangorestframework-simplejwt.
I've configured Django to use token auth with djangorestframework-simplejwt.
# rest framework config settings
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.IsAuthenticated',
# 'rest_framework.permissions.AllowAny',
],
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.SessionAuthentication',
'rest_framework.authentication.TokenAuthentication',
'rest_framework_simplejwt.authentication.JWTAuthentication',
],
The vast majority of my endpoints return valid data when I pass a valid access token in the request. If I do not send a valid token, I receive a HTTP 403.
On the other hand, I have some custom API views which return a HTTP 401 regardless of whether I pass a valid token or not.
I have included the code to one of my problematic views below.
class CheckDifferentialView(generics.GenericAPIView):
permission_classes = [IsAuthenticated]
authentication_classes = [TokenAuthentication]
serializer_class = QuizDifferentialSerializer
def post(self, request, *args, **kwargs):
"""
A function to check a quiz question and to update a user's record of questions answered
"""
print(request.META)
if 'answer' not in request.data:
return JsonResponse({'Error': 'answer not found in request'}, status=status.HTTP_400_BAD_REQUEST)
answer = get_object_or_404(Differential, pk=request.data['answer'])
serializer = QuizDifferentialSerializer(answer)
if answer.is_correct:
pass
# record correct results
else:
pass
# record failed result
return Response(serializer.data, status=status.HTTP_200_OK)
And here is my script which I am using to test my API
import requests
import json
POST_LOGIN_URL = 'http://localhost:8000/api/v1/token/'
POST_URL= 'http://localhost:8000/api/v1/check_differential'
REQUEST_URL = 'http://localhost:8000/api/v1/users'
with requests.Session() as session:
post = session.post(POST_LOGIN_URL, json={"username": "j", "monkey": "aphextwin21"})
token = json.loads(post.text)['access']
headers = {'Authorization': 'Bearer ' + token}
r = session.post(POST_URL, headers=headers, json={"answer": "2"})
# r = session.get(REQUEST_URL, headers=headers)
print(token)
print(r.text, r.status_code)
The desired behaviour is that if I send a POST request with a valid token to this endpoint that is would authorise me and carry on with its day. If no Authorization header with a valid access token is given, then I expect it to deny the request.
Update
Enthusiastic Martin kindly point out that
authentication_classes = [TokenAuthentication]
Was overriding the defaults found in my settings file. I was not aware that as far as Django is concerned TokenAuthentication and JWTAuthentication are treated differently. Now I know.
After removing the authentication_classess = [TokenAuthentication] from my views, the views are working as they should.
Simple JWT provides a JSON Web Token authentication backend for the Django REST Framework. It aims to cover the most common use cases of JWTs by offering a conservative set of default features. It also aims to be easily extensible in case a desired feature is not present.
The view's authentication class is explicitly set to TokenAuthentication only. It wont work with JWT token.
authentication_classes = [TokenAuthentication]
You either remove this to let the default classes handle it or change it to accept JWTAuthentication.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With