cryptographypemdjango-rest-framework-simplejwtdjango-rest-framework-jwtdjango-4.0

Implementing Custom TokenBackend for rest_framework_simplejwt


I am migrating our Django code that uses djangorestframework-jwt to the latest version of djangorestframework-simplejwt(5.2.2) in Django 4.0.8. I am having an issue while trying to verify the token.

The issue is because of the fact that our pem file for retrieving public and private keys is hosted on an Amazon S3 bucket. The framework requires passing SIGNING_KEY and VERIFYING_KEY statically or using JWK_URL for dynamically injecting these keys. Is there a way to provide these keys dynamically without using JWK_URL?

The djangorestframework-jwt framework used to provide handlers for decoding (JWT_DECODE_HANDLER) and encoding (JWT_ENCODE_HANDLER) the JWT payload. The djangorestframework-simplejwt has built-in functions to decode/encode inside the TokenBackend class. I also see that TOKEN_BACKEND_CLASS is part of REMOVED_SETTINGS in api_settings. I am having difficulty trying to write a custom backend by overriding decode() and encode() functions. How can I accomplish this?


Solution

  • You can achieve this by overriding your serializer in the following fashion.

    from rest_framework_simplejwt.serializers import TokenVerifySerializer
    from rest_framework_simplejwt.exceptions import (
        InvalidToken,
        AuthenticationFailed,
        TokenBackendError,
        TokenError
    )
    class MyTokenVerifySerializer(TokenVerifySerializer):
        """
        Check the veracity of an access token.
        """
    
        def validate(self, attrs):
            token = attrs['token']
        
            payload = {}
            # Decode Token 
            try:
                payload = jwt_decode_handler(token) # Your Decode handler
            except TokenBackendError:
                raise TokenError(_("Token is invalid or expired"))
    
            user = self.get_user(payload=payload)
    
            return {'token': token, 'user': user}
    
        def get_user(self, payload):
            """
            Attempts to find and return a user using the given validated token.
            """
            from rest_framework_simplejwt.settings import api_settings
            from django.contrib.auth import get_user_model
            from django.utils.translation import gettext_lazy as _
    
            try:
                user_id = payload[api_settings.USER_ID_CLAIM]
            except KeyError:
                raise InvalidToken(_("Token contained no recognizable user identification"))
    
            user_model = get_user_model()
            try:
                user = user_model.objects.get(**{api_settings.USER_ID_FIELD: user_id})
            except self.user_model.DoesNotExist:
                raise AuthenticationFailed(_("User not found"), code="user_not_found")
    
            if not user.is_active:
                raise AuthenticationFailed(_("User is inactive"), code="user_inactive")
    
            return user
    

    Hope this helps! Cheers