Home > Mobile >  How to customise the error code and message for inactive accounts in simple jwt authentication - Dja
How to customise the error code and message for inactive accounts in simple jwt authentication - Dja

Time:05-06

I want to customize the default_user_authentication_rule used by simple jwt authentication. The usual process that it follows is that it checks if the user account for which it has received the credentials is active or not. If is_active is true then it goes on with the authentication else it throws the Unauthorised error. I want to customise this function so that I get the Unauthorised error only when the user account does not exist at all or the credentials are invalid. If the user exists and is_active = False I want to return something like not-active so I can do something with it I have planned.

Please suggest to me what should I do as I have found no documentation regarding the same. Below is the Simple JWT settings

Update

What I wanted basically to get a different error code and message for inactive accounts.

SIMPLE_JWT = {
    'ACCESS_TOKEN_LIFETIME': timedelta(seconds=3),
    'REFRESH_TOKEN_LIFETIME': timedelta(days=7),
    'ROTATE_REFRESH_TOKENS': True,
    'BLACKLIST_AFTER_ROTATION': True,
    'UPDATE_LAST_LOGIN': False,

    'ALGORITHM': 'HS256',
    'SIGNING_KEY': SECRET_KEY,
    'VERIFYING_KEY': None,
    'AUDIENCE': None,
    'ISSUER': None,
    'JWK_URL': None,
    'LEEWAY': 0,

    'AUTH_HEADER_TYPES': ('Bearer',),
    'AUTH_HEADER_NAME': 'HTTP_AUTHORIZATION',
    'USER_ID_FIELD': 'id',
    'USER_ID_CLAIM': 'user_id',
    'USER_AUTHENTICATION_RULE': 'rest_framework_simplejwt.authentication.default_user_authentication_rule', # this is what I was talking about

    'AUTH_TOKEN_CLASSES': ('rest_framework_simplejwt.tokens.AccessToken',),
    'TOKEN_TYPE_CLAIM': 'token_type',
    'TOKEN_USER_CLASS': 'rest_framework_simplejwt.models.TokenUser',

    'JTI_CLAIM': 'jti',

    'SLIDING_TOKEN_REFRESH_EXP_CLAIM': 'refresh_exp',
    'SLIDING_TOKEN_LIFETIME': timedelta(minutes=5),
    'SLIDING_TOKEN_REFRESH_LIFETIME': timedelta(days=1),
}

CodePudding user response:

After lot of searching and trying different methods. I came across this post Customize default message djangorestframework-simplejwt retrieved when the user is not active? and have found a way to achieve at least a different message for inactive accounts instead of a different error code. I am putting up this answer for anyone who faces the same problem. I have written the explanations about what I have done as comments in the code itself.

from rest_framework import status, exceptions
from django.utils.translation import gettext_lazy as _
from rest_framework_simplejwt.serializers import TokenObtainPairSerializer, TokenObtainSerializer


class CustomTokenObtainPairSerializer(TokenObtainPairSerializer, TokenObtainSerializer):
    
  
    # Overiding validate function in the TokenObtainSerializer  
    def validate(self, attrs):
        authenticate_kwargs = {
            self.username_field: attrs[self.username_field],
            'password': attrs['password'],
        }
        try:
            authenticate_kwargs['request'] = self.context['request']
        except KeyError:
            pass

        # print(f"\nthis is the user of authenticate_kwargs {authenticate_kwargs['email']}\n")
       
        
        '''
        Checking if the user exists by getting the email(username field) from authentication_kwargs.
        If the user exists we check if the user account is active.
        If the user account is not active we raise the exception and pass the message. 
        Thus stopping the user from getting authenticated altogether. 
        
        And if the user does not exist at all we raise an exception with a different error message.
        Thus stopping the execution righ there.  
        '''
        try:
         user = CustomUser.objects.get(email=authenticate_kwargs['email'])
         if not user.is_active:
             self.error_messages['no_active_account']=_(
                 'The account is inactive'
             )
             raise exceptions.AuthenticationFailed(
                 self.error_messages['no_active_account'],
                 'no_active_account',
             )
        except CustomUser.DoesNotExist:
          self.error_messages['no_active_account'] =_(
              'Account does not exist')
          raise exceptions.AuthenticationFailed(
              self.error_messages['no_active_account'],
              'no_active_account',
          )
          
        '''
        We come here if everything above goes well.
        Here we authenticate the user.
        The authenticate function return None if the credentials do not match 
        or the user account is inactive. However here we can safely raise the exception
        that the credentials did not match as we do all the checks above this point.
        '''
        
        self.user = authenticate(**authenticate_kwargs)
        if self.user is None:
            self.error_messages['no_active_account'] = _(
                'Credentials did not match')
            raise exceptions.AuthenticationFailed(
                self.error_messages['no_active_account'],
                'no_active_account',
            )
        return super().validate(attrs)


This is the source code of the djangorestframework-simplejwt serializer.py incase anyone wants to have a look https://github.com/jazzband/djangorestframework-simplejwt/blob/master/rest_framework_simplejwt/serializers.py

CodePudding user response:

The default user authentication rule is defined in authentication.py in simpleJWT. You should be able to define a custom rule and point USER_AUTHENTICATION_RULE in settings to that.

  • Related