Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to return custom data with Access and Refresh Tokens to identify users in Django Rest Framework simple JWT?

In Django, superuser can add more user according to their roll. I'm using simple JWT with DRF for authentication. But it is impossible to detect the type of user only by seeing the Access and Refresh Tokens.

Here are my settings.py file

REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES': ('rest_framework.permissions.IsAuthenticated',),
    'DEFAULT_AUTHENTICATION_CLASSES': ('rest_framework_simplejwt.authentication.JWTAuthentication',),


}

urls.py

from django.contrib import admin
from django.urls import path, include
from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView


urlpatterns = [

    path('admin/', admin.site.urls),
    path('', include('Manage_Merchants.urls')),

    path('api-auth', include('rest_framework.urls')),
    path('api/token/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
    path('api/token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),


]

when I hit on 127.0.0.1:8000/api/token/ through Postman it asks for username and password. When I put Username and Password it generates a Refresh and Access Token. Generate JWT with DRF using Postman

So how can I identify the token is generated for super user or other user created bu superuser? How can I pass more value as a dictionary along with Access and Refresh Tokens to identify the type of user?

like image 267
deepto Avatar asked Nov 26 '18 12:11

deepto


People also ask

How JWT token works in Django REST framework?

JWT, short for JSON Web Token is an open standard for communicating authorization details between server and client. Unlike TokenAuthentication where the token is randomly generated and the authentication details are stored on the server, JWT is self-contained.


3 Answers

In the version djangorestframework-simplejwt==4.4.0 it's the method validate instead of to_representation, meaning:

In your serializer.py you need to override the TokenObtainPairSerializer in order to include all the data you want to send in the response

from rest_framework_simplejwt.serializers import TokenObtainPairSerializer


class CustomTokenObtainPairSerializer(TokenObtainPairSerializer):
    def validate(self, attrs):
        # The default result (access/refresh tokens)
        data = super(CustomTokenObtainPairSerializer, self).validate(attrs)
        # Custom data you want to include
        data.update({'user': self.user.username})
        data.update({'id': self.user.id})
        # and everything else you want to send in the response
        return data

Now in your views.py you need to override the TokenObtainPairView in order to pair it with the new serializer.

from .serializers import CustomTokenObtainPairSerializer


class CustomTokenObtainPairView(TokenObtainPairView):
    # Replace the serializer with your custom
    serializer_class = CustomTokenObtainPairSerializer

Now map your it in your url.py

from rest_framework_simplejwt.views import TokenRefreshView, TokenVerifyView
from . import views

urlpatterns = [
    # This one now has the custom view mapped with the custom serializer that includes the desired data
    path('token/', views.CustomTokenObtainPairView.as_view(), name='token_obtain_pair'),
    path('token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
    path('token/verify/', TokenVerifyView.as_view(), name='token_verify')
]

like image 99
Emmanuel Valdez Avatar answered Oct 11 '22 08:10

Emmanuel Valdez


Like kumar said, you should override TokenObtainPairView. Let me get deeper in it:

Create a new classView in your core app views.py, or if you want to have a cleaner code, you could create a new app for example called jwt_token_patched and create a views.py file in it. Now add below code to it:

class TokenObtainPairPatchedView(TokenObtainPairView):
    """
    Takes a set of user credentials and returns an access and refresh JSON web
    token pair to prove the authentication of those credentials.
    """
    serializer_class = serializers.TokenObtainPairPatchedSerializer

    token_obtain_pair = TokenObtainPairView.as_view()

Now for serializer add this:

class TokenObtainPairPatchedSerializer(TokenObtainPairSerializer):
     def to_representation(self, instance):
         r = super(TokenObtainPairPatchedSerializer, self).to_representation(instance)
         r.update({'user': self.user.username})
         return r

method to_representation() is called when serializer is returning data in json format, so you could add anything that you want in there. remember I just put username in user field value, you can add any item value of user that you want in it.

Also create a url for this and from now on use that method for getting token. Feel free to ask any questions if you want. hope it was usefull :)

like image 10
Reza Torkaman Ahmadi Avatar answered Oct 11 '22 08:10

Reza Torkaman Ahmadi


For customizing refresh token the best thing you can do is override the "TokenRefreshSerializer" which is shown below. However if you want to get any field form the model we have to decode the token to get the UUID of the user. This can be done using token_backend

Note: do make sure you're using "rest_framework_simplejwt" not "djangorestframework-jwt" since it's been deprecated

from rest_framework_simplejwt.serializers import TokenRefreshSerializer
from rest_framework_simplejwt.state import token_backend

class CustomTokenRefreshSerializer(TokenRefreshSerializer):
    def validate(self, attrs):
        data = super(CustomTokenRefreshSerializer, self).validate(attrs)
        decoded_payload = token_backend.decode(data['access'], verify=True)
        user_uid=decoded_payload['user_id']
        # add filter query
        data.update({'custom_field': 'custom_data')})
        return data

And then use this serializer as shown below with "CustomTokenRefreshView" which inherits "TokenRefreshView"

from rest_framework_simplejwt.views import TokenRefreshView
class CustomTokenRefreshView(TokenRefreshView):
    """
    Custom Refresh token View
    """
    serializer_class = CustomTokenRefreshSerializer

And add this in urls

path('api/token/refresh/', CustomTokenRefreshView.as_view(), name='token_refresh'),
like image 1
Raj Chhatbar Avatar answered Oct 11 '22 08:10

Raj Chhatbar