Unauthorized response to POST request in Django Rest Framework with JWT Token
B

1

7

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.

Boule answered 18/10, 2019 at 10:3 Comment(0)
L
8

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.

Lowenstern answered 18/10, 2019 at 10:8 Comment(1)
Just did it for you @Boule (including an upvote to your question). You need at least 15 repo to be able to upvote. In the meantime you can mark the answer as accepted, you'll get +2 because the answer is not yours.Peg

© 2022 - 2024 — McMap. All rights reserved.