Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Adding information to JWT token body using django rest framework jwt

Im using django rest framework and the djangorestframework-jwt package to creat JWT tokens for authorization.

On the frontend I can decode the token and get the username, email and user_id. However I would like to retrieve some extra information. For example it would be very convenient if I could get kind which is a field on our authorization model (user model).

I can ofcourse make a separate request to get the user info via a regular APIView. But I'm wondering if it's possible to add some extra params in the JWT body?

like image 586
Erik Svedin Avatar asked Apr 29 '16 12:04

Erik Svedin


People also ask

What is JWT token in Django REST framework?

Simple JWT provides a JSON Web Token authentication backend for the Django REST Framework. It aims to cover the most common use cases of JWTs by offering a conservative set of default features. It also aims to be easily extensible in case a desired feature is not present.


2 Answers

Using the djangorestframework_simplejwt library

  1. Specify in settings.py the USER_ID_FIELD and ALGORITHM

    SIMPLE_JWT = {
        'USER_ID_FIELD': 'user_id',
        'ALGORITHM': 'HS512',
    }
    

Let's say you want to add fields to the body of TokenObtainPairView which has the following body

Token Obtain Pair body

{
    "refresh": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTU5MDk5ODAwMSwianRpIjoiMjZhZThhYTU4YTJiNDU3M2JlMDgxNTMzMzU1ODg4ZmUiLCJ1c2VyX2lkIjoxMX0.-jUCnfpTF-RsqHnuoEgctPpHf1SfYNcYaPs8oo01RvrQBMcyhms5PfWipfYkaR0FlPHSTKncNeMxomwd4k7nyg",
    "access": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNTkwOTExOTAxLCJqdGkiOiI5NjZkOTFhNzEzNjg0NjMyOGUzYWU3NThiNzNiZmYxMyIsInVzZXJfaWQiOjExfQ.LiHrekmlHrM7_5187ghpIaA6mKcPCjDz4MDKPXHc4QAKVGvcJCJpCjrODCB4-pZn4Kuai5ht3YjWwYSirxpsXw"
}
  1. Add in your urls.py

    path('api/token/', MyTokenObtainPairView.as_view(), name='token_obtain'),
    
  2. Create the MyTokenObtainPairView

    class MyTokenObtainPairView(TokenObtainPairView):
        serializer_class = MyTokenObtainPairSerializer`
    
  3. Create the MyTokenObtainPairSerializer

    class MyTokenObtainPairSerializer(TokenObtainPairSerializer):
        def validate(self, attrs):
            data = super().validate(attrs)
            refresh = self.get_token(self.user)
            data['refresh'] = str(refresh)
            data.pop('refresh', None) # remove refresh from the payload
            data['access'] = str(refresh.access_token)
    
            # Add extra responses here
            data['user'] = self.user.username
            data['kind'] = self.user.kind
            data['date'] = datetime.date.today()
            return data
    

This way when you post to /api/token/ you'll get in the body something like this

{
    "access": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNTkwOTEwNTc0LCJqdGkiOiIwM2Q5MzA1NTZmNzk0NmFjODU1MzJlNTYzNjUwZDY0MCIsInVzZXJfaWQiOjExfQ.H0huO84qtzdbo4OkKhsW_vtNTGwInG67gum6f138h1y66EiyZ1BvxaxbfEE2oPG4pB0XjiWQrXc5PlR9C6UvfQ",
    "user": "tiago",
    "kind": "whatever_this_has"
    "date": "2020-05-31"
}
like image 180
Tiago Martins Peres Avatar answered Oct 13 '22 20:10

Tiago Martins Peres


As detailed in this github issue, I did this by subclassinng the ObtainJSONWebToken class from DRF-JWT:

from rest_framework_jwt import views as jwt_views
from .serializers import UserSerializer 

class UserLoginViewJWT(jwt_views.ObtainJSONWebToken):
    user_serializer_class = UserSerializer

    def post(self, request, *args, **kwargs):
        response =  super().post(request, *args, **kwargs)

        if response.status_code == status.HTTP_200_OK:
            user = get_user_model().objects.get(email=request.data[get_user_model().USERNAME_FIELD])
            serialized_user = self.user_serializer_class(user)
            response.data.update(serialized_user.data)
        return response

Note: the code above is probably missing some imports

A reply from @jpadilla also specified that

You can also do this with the JWT_RESPONSE_PAYLOAD_HANDLER setting. http://getblimp.github.io/django-rest-framework-jwt/#jwt_response_payload_handler

like image 32
Jad S Avatar answered Oct 13 '22 19:10

Jad S