djangodjango-rest-frameworkdjango-rest-framework-jwt

How to revoke refresh token on password reset?


I am using django-rest-framework-simplejwt to get access token and refresh token .

The problem is that refresh token is not becoming invalid if I change the password of the user. Basically I can continue to send refresh token and get new access tokens even after user has changed password.

What I would like instead is to ask user to re-submit the username and new password to get a new pair of access and refresh tokens.

How would I accomplish this?



PS: Just because I am curious, shouldn't this be the default behaviour of the library? In what case would we want to retain the refresh token after credentials have changed?


Solution

  • I figured how to get this working.
    What I am did is put a signal that tracks if any required parameter has changed. If so, it blacklists all the refresh tokens associated with that user.
    Here is the code:

    First add 'rest_framework_simplejwt.token_blacklist' in installed apps. Then:

    @receiver(signals.pre_save, sender=User)
    def revoke_tokens(sender, instance, update_fields, **kwargs):
        if not instance._state.adding: #instance._state.adding gives true if object is being created for the first time
            existing_user = User.objects.get(pk=instance.pk)
            if instance.password != existing_user.password or instance.email != existing_user.email or instance.username != existing_user.username:
            # If any of these params have changed, blacklist the tokens
                  outstanding_tokens = OutstandingToken.objects.filter(user__pk=instance.pk)
                  # Not checking for expiry date as cron is supposed to flush the expired tokens
                  # using manage.py flushexpiredtokens. But if You are not using cron, 
                  # then you can add another filter that expiry_date__gt=datetime.datetime.now()
    
                  for out_token in outstanding_tokens:
                       if hasattr(out_token, 'blacklistedtoken'):
                           # Token already blacklisted. Skip
                           continue
    
                           BlacklistedToken.objects.create(token=out_token)
    

    WHat this code basically does is , gets all outstanding tokens for the user, then adds all of them to blacklist. You can get more info on outstanding/blacklisted tokens here. https://github.com/davesque/django-rest-framework-simplejwt#blacklist-app