uyarc
uyarc

Reputation: 616

Simple JWT add extra field to payload data in token

I use djoser and rest_framework_simplejwt. This my user model;

class userProfile(models.Model):

    user=models.OneToOneField(User,on_delete=models.CASCADE,related_name="profile")
    date_joined=models.DateTimeField(auto_now_add=True)
    updated_on=models.DateTimeField(auto_now=True)

    def __str__(self):
        return self.user.username

My views.py to get token for users give in below;

class CustomTokenObtainPairView(TokenObtainPairView):

serializer_class = CustomTokenObtainPairSerializer
token_obtain_pair = TokenObtainPairView.as_view()

This is the serializer.py;

class CustomTokenObtainPairSerializer(TokenObtainPairSerializer):
def validate(self, attrs):
    data = super(CustomTokenObtainPairSerializer, self).validate(attrs)
    data.update({'user': self.user.username})
    data.update({'id': self.user.id})
    data.update({'first_name': self.user.first_name})
    data.update({'last_name': self.user.last_name})
    data.update({'is_superuser': self.user.is_superuser})
    return data

I can get access and refresh token like this.

    {
    "refresh": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTU4ODQxMDY0OCwianRpIjoiNTY2MDhhOGVjYzRiNDZhMmFjYjc0Y2VmMzE2ZGE4YTkiLCJ1c2VyX2lkIjo3fQ.gXk9y3Vq0NlB8ZpU9SFcLWAMplr4_ECTeBg5WTMAuNY",
    "access": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNTg4NDA5NzQ4LCJqdGkiOiIxM2VlYzQ1MjZkMTQ0ODI4YjgxNjVkZTA0MzlmYjBmMSIsInVzZXJfaWQiOjd9.sQ1G3rur1h3yqj79ZYvzHK1o6mgtHYuzJZlh5OCyg84",
    "user": "x",
    "id": 5,
    "first_name": "x",
    "last_name": "x",
    "is_superuser": false,

}

When encode token using jwt.io payload data is;

{
  "token_type": "access",
  "exp": 1588329561,
  "jti": "944f97343b42448fbaf5461295eb0548",
  "user_id": 5
}

I want to add users first_name, last_name in payload in access token and ı want to get;

    {
          "token_type": "access",
          "exp": 1588329561,
          "jti": "944f97343b42448fbaf5461295eb0548",
          "user_id": 5,
          "user": "x",
          "first_name": "x",
          "last_name": "x",
          "is_superuser": false,
 }

Upvotes: 14

Views: 9458

Answers (3)

Sharukh Rahman
Sharukh Rahman

Reputation: 521

To add extra fields to the JWT payload or include additional information in the token response, you can customize the TokenObtainPairSerializer. Below is an implementation with clear separation of responsibilities:

  • Adding extra fields to the JWT payload itself: Override the get_token method.
  • Adding extra fields to the token response: Override the validate method.

Here’s a complete example:

from rest_framework_simplejwt.serializers import TokenObtainPairSerializer
class MyTokenObtainPairSerializer(TokenObtainPairSerializer)
    def validate(self, attrs):
        data = super().validate(attrs)
        user= self.user
        # Include additional data in the response (not encoded in the token)
        data['user'] = {
            'id': user.id,
            'email': user.email,
        }
        return data

When you authenticate using this serializer, the response will look like this:

{
    "refresh": "<refresh_token>",
    "access": "<access_token>",
    "user": {
        "id": 1,
        "email": "[email protected]",
    }
}

Now overriding get_token() method:

from rest_framework_simplejwt.serializers import TokenObtainPairSerializer
class MyTokenObtainPairSerializer(TokenObtainPairSerializer):
    @classmethod
    def get_token(cls, user):
        token = super().get_token(user)
        # Add custom fields to the JWT payload
        token['user'] = {
            'id': user.id,
            'email': user.email,
        }
        return token

When you authenticate using this serializer, the response will look like this:

{
    "refresh": "<refresh_token_with_your_user_payload>",
    "access": "<access_token_with_your_user_payload>",
}

Key Points:

  1. get_token: Adds custom fields to the JWT payload. These fields will be part of the token and accessible wherever the token is decoded.

  2. validate: Appends user-related details to the response. These fields are not part of the token but are included in the response after successful authentication.

Upvotes: 0

timotaoh
timotaoh

Reputation: 330

You can also add the data to the body of your response if you don't want to decode the JWT.

class CustomTokenObtainPairSerializer(TokenObtainPairSerializer):
    def validate(self, attrs):
        data = super().validate(attrs)
        data['first_name'] = self.user.first_name
        data['last_name'] = self.user.last_name
        data['username'] = self.user.username
        data['is_superuser'] = self.user.is_superuser
        return data

Upvotes: 1

uyarc
uyarc

Reputation: 616

I change my CustomTokenObtainPairSerializer to:

class CustomTokenObtainPairSerializer(TokenObtainPairSerializer):
    @classmethod
    def get_token(cls, user):
        token = super().get_token(user)
        token['first_name'] = user.first_name
        token['last_name'] = user.last_name
        token['username'] = user.username
        token['is_superuser'] = user.is_superuser
        return token

Upvotes: 18

Related Questions