djangorestframework-simplejwt
djangorestframework-simplejwt copied to clipboard
Extending RefreshToken method to use customized token claims
I used the docs straightforward instructions on how to extend the get_token method of MyTokenObtainSerializer to include a custom claim in the JWT token it produced. However, I am trying to extend the RefreshToken.for_user() method in the same way and I'm not sure how to go about doing it. Admittedly, my understanding of inheritance in python is tenuous.
This is the same as my question.
Solution from @jayps
Summary: Change RefreshToken.for_user(user)
to CustomTokenObtainPairSerializer.get_token(user)
For anyone else finding this: I achieved by using a custom serializer as described in the docs. I have my serializer like this:
class AuthTokenObtainPairSerializer(TokenObtainPairSerializer): @classmethod def get_token(cls, user): token = super().get_token(user) token['name'] = user.first_name # Add other claims here as required return token
And then in my view where I manually create a new token:
user = User.objects.get(username='example') # Optionally perform some operations against the user. refresh = AuthTokenObtainPairSerializer.get_token(user) return Response(data={'refresh': str(refresh), 'access': str(refresh.access_token)})
In my case, this successfully returns a fresh token with new claims.
in RefreshToken.for_user(user), can't I pass any other parameter I want to include in the payload?
I'm having the same problem. I have 2 problems with the solution of overriding the serializer:
- The custom claims are not stored in the
OutstandingToken
- The doc has a section explaining how to manually create a token. Which seems clean (I need it for unit test purpose on my side), but the problem is the custom claims added from the serializer are therefore not included, making this unusable.
So, I thought about Subclassing RefreshToken.for_user
to add my custom claims, but again, the OutstandingToken
does not include the custom claims.
From my point of view, the easier solution would be add a hook at the end of the for_user
method which would only be made for custom claims injection.
Something like:
@classmethod
def for_user(cls, user):
"""
Returns an authorization token for the given user that will be provided
after authenticating the user's credentials.
"""
user_id = getattr(user, api_settings.USER_ID_FIELD)
if not isinstance(user_id, int):
user_id = str(user_id)
token = cls()
token[api_settings.USER_ID_CLAIM] = user_id
token = cls.for_user_post_hook(user, token)
return token
def for_user_post_hook(cls, User, token):
# does nothing by default, but allows custom behaviours
return token
What do you think about it?
That being said, I believe storing the full tokens in DB seems like a security risk, as someone already pointed out. I believe we should only store the jti and token expiration, and maybe the sub
for filtering purpose? But that's another subject.
I'd be happy to make a PR for that if you'd like.