djangodjango-rest-frameworkdjango-viewsjwtdjango-validation

How to validate and return access and refresh tokens after user.save()


I'm verifying the user OTP to change password and after change password I'm unable to create access and refresh token using JWT ,

Normally when user get log in I use following method MyTokenObtainPairView which return both access and refresh token with all other stuff to UserSerializerWithToken.

class MyTokenObtainPairSerializer(TokenObtainPairSerializer):
    def validate(self, attrs):
        data = super().validate(attrs)

        serializer = UserSerializerWithToken(self.user).data
        for k, v in serializer.items():
            data[k] = v

        return data


class MyTokenObtainPairView(TokenObtainPairView):
    serializer_class = MyTokenObtainPairSerializer

I coppied similar appraoch to return UserSerializerWithToken after set_password and user.save()

UserSerializerWithToken is

class UserSerializerWithToken(UserSerializer):
    token = serializers.SerializerMethodField(read_only=True)

    class Meta:
        model = CustomUser
        fields = ['id',
                  'isAdmin',
                  'token']

    def get_token(self, obj):
        token = RefreshToken.for_user(obj)
        return str(token.access_token)

and the problematic function is

@api_view(['PUT'])
def reset_password(request):
    data = request.data
    email = data['email']
    otp_to_verify = data['otp']
    new_password = data['password']
    user = CustomUser.objects.get(email=email)
    serializer = UserSerializerWithToken(user, many=False)
    if CustomUser.objects.filter(email=email).exists():
        if otp_to_verify == user.otp:
            if new_password != '':
                user.set_password(new_password)
                user.save() # here password gets changed 
                return Response(serializer.data) # 
            else:
                message = {
                'detail': 'Password cant be empty'}
                return Response(message, status=status.HTTP_400_BAD_REQUEST)
    else:
        message = {
            'detail': 'Something went wrong'}
        return Response(message, status=status.HTTP_400_BAD_REQUEST)

I receive the toke but not getting access and refresh toke to use it to login next time. I'm assuming user.save() dosnt create refresh and access token here. Can anybody identify why this is happening and how to fix that


Solution

  • user.save() does not create the tokens

    token = RefreshToken.for_user(obj) return str(token.access_token)

    These lines create the token.

    In my opinion, you dont need the serializer here.

    @api_view(['PUT'])
    def reset_password(request):
        data = request.data
        email = data['email']
        otp_to_verify = data['otp']
        new_password = data['password']
        user = CustomUser.objects.get(email=email)
        if CustomUser.objects.filter(email=email).exists():
            otp_to_verify == user.otp
            if new_password != '':
                user.set_password(new_password)
                user.save() # here password gets changed 
                token = RefreshToken.for_user(user)
                response = { "refresh_token": str(token),
                             "access_token": str(token.access_token)
                           }
                return Response(response)
            else:
                message = {
                    'detail': 'Password cant be empty'}
                return Response(message, status=status.HTTP_400_BAD_REQUEST)
        else:
            message = {
                'detail': 'Something went wrong'}
            return Response(message, status=status.HTTP_400_BAD_REQUEST)