Reputation: 904
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?
Upvotes: 1
Views: 2840
Reputation: 76
There is a new update in the django rest framework simpljwt (v5.3.1) package that resolved this issue easily.
You can add this settings to the SIMPLE_JWT django settings variable:
SIMPLE_JWT = {
...,
"CHECK_REVOKE_TOKEN": True
}
And it will automatically invalidate the access token once a user change his password.
And also the refresh token will be invalid but without errors, I mean you will get a new access token each time you request it by the refresh but it will be invalid.
You can check the pull request of this solution if you need to know more about how this is implemented in the package code.
Upvotes: 0
Reputation: 904
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
Upvotes: 6