5

I'm using Django Rest Framework and django-rest-framework-simplejwt for authentication. The data being sent is being consumed by react.

So far I've been able to subclass the TokenObtainPairSerializer to return both the username and ID when logging in / getting a new token.

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

        data.update({'user': self.user.username})
        data.update({'id': self.user.id})

        return data

I'm trying to have a users username and id returned when the token is refreshed as well. This, however, does not work:

class MyTokenRefreshSerializer(TokenRefreshSerializer):

    def validate(self, attrs):
        data = super(MyTokenRefreshSerializer, self).validate(attrs)
        user = self.context['request'].user
        data.update({'user': user.username})
        data.update({'id': user.id})

        return data  

Here, the username is always returned as an empty string and the ID is always returned as null.

I've tried many different ways, including trying to update this information in the view itself, but can't seem to get it to work. I've noticed that TokenRefreshSerializer subclasses serializers.Serializer while TokenObtainPairSerializer subclasses TokenObtainSerializer which itself authenticates a user using Django authentication. This appears to require a password (like when a user logs in) but obviously that wouldn't be provided when simply refreshing a token.

My question is, how can I return the username and id (or any arbitrary information) about the current user when the token is refreshed?

The follow-on question would be, is it more practical to simply save that information to localStorage on the front end when the user first logs in and have the state re-populate that data on each subsequent visit (until the user logs out, or the refresh token is no longer valid)?

Please Note: This is not a repost of similar questions such as this one, because I am targeting the REFRESHING of tokens. The initial TokenObtainPairView was straightforward to subclass and implement.

Hanzy
  • 394
  • 4
  • 17
  • As in the post you'd referred, override the **`to_representation()`** method of `MyTokenRefreshSerializer` class – JPG Apr 10 '20 at 15:46
  • @ArakkalAbu in the linked post it says that answer is out of date and we need to override the validate method. Is that incorrect? Just curious because I stayed away from that if it’s out of date. – Hanzy Apr 10 '20 at 15:49
  • @ArakkalAbu I don't think that will work when looking through the source code and from the errors I've been seeing. Specifically because there won't be a `self.user` on `MyTokenRefreshSerializer`. Trying to access it will cause an error. Assigning it simply returns an empty string (if using the `request.user` to assign the value). – Hanzy Apr 10 '20 at 16:04
  • To get around this, I’m just creating a custom token claim with the info I need and decoding it in the browser. But there should probably be a way to simply send the data in the response directly? – Hanzy Apr 10 '20 at 18:08
  • As the refresh token endpoint does not set authenticated permission all you are left with to get user info is the refresh token. So i dont think there is any other way except to decode that token and get the data. You could probably do the decoding in the backend, which automatically answers your follow up question(yes you should) whether you should save user info on localstorage and refresh it with subsequent hit to a protected api that uses access token as the request.user field would now be set and you could fetch user data and refresh your localstorage in case some user update happened. – Dipendra bhatt Apr 11 '20 at 11:38
  • @dipenbhatt ok thanks. After fighting the issue for a whole day I did just make a custom token claim and decode it on the client to get the info. Then decided no need to store anything besides token in local storage since I can decode it and get it again on revisit. But I do appreciate you confirming I’m not crazy! – Hanzy Apr 11 '20 at 11:49
  • @dipenbhatt is it possible to give an example of how to subclass the endpoint and set user authenticates permission? – Hanzy Apr 11 '20 at 11:55
  • @hanzy. you mean you want the refresh token end point to be protected? – Dipendra bhatt Apr 11 '20 at 12:05
  • @dipenbhatt hmm, no I just meant to make it authenticate a user after the token was refreshed. Maybe that would require redirecting to another route though. – Hanzy Apr 11 '20 at 12:07
  • Doesnt see the sense in doing that. Because once you hit the refresh end point your access token is updated, and then routing to the login page means you have to again put login credentials which would then again regerate the token pair. So repeating the same thing. Doesnt see much benefit in that. – Dipendra bhatt Apr 11 '20 at 12:30
  • @dipenbhatt I understand; was hoping It could be done without the password but yeah - no sense in the extra loop. – Hanzy Apr 11 '20 at 12:36

1 Answers1

4

As the refresh token endpoint does not set authenticated permission all you are left with to get user info is the refresh token. So i dont think there is any other way except to decode that token and get the data. You could probably do the decoding in the backend, which automatically answers your follow up question(yes you should) whether you should save user info on localstorage and refresh it with subsequent hit to a protected api that uses access token as the request.user field would now be set and you could fetch user data and refresh your localstorage in case some user update happened.

Dipendra bhatt
  • 729
  • 5
  • 14