Using djangorestframework_simplejwt library, when POST to a custom view
#urls.py
path('api/token/', MyTokenObtainPairView.as_view(), name='token_obtain'),
#views.py
class MyTokenObtainPairView(TokenObtainPairView):
serializer_class = MyTokenObtainPairSerializer
I'm able to get a the following access token
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNTkwOTEwNjg0LCJqdGkiOiI3M2MxYmZkOWNmMGY0ZjI3OTY4MGY0ZjhlYjA1NDQ5NyIsInVzZXJfaWQiOjExfQ.5vs0LmNGseU6rtq3vuQyApupxhQM3FBAoKAq8MUukIBOOYfDAV9guuCVEYDoGgK6rdPSIq2mvcSxkILG8OH5LQ
By going to https://jwt.io/ I can see the payload is currently
{
"token_type": "access",
"exp": 1590910684,
"jti": "73c1bfd9cf0f4f279680f4f8eb054497",
"user_id": 11
}
So, we can see that the second part of the token is the payload - containing the claims.
I've explored how to add more information to the Response body and now would like to know how to customize the Payload data by adding iat claim, username and today's date.
As you already created a subclass for the desired view (MyTokenObtainPairView) and a subclass for its corresponding serializer (MyTokenObtainPairSerializer), add the following to the serializer
class MyTokenObtainPairSerializer(TokenObtainPairSerializer):
...
@classmethod
def get_token(cls, user):
token = super().get_token(user)
# Add custom claims
token['iat'] = datetime.datetime.now()
token['user'] = user.username
token['date'] = str(datetime.date.today())
return token
Then, when you POST to that same location, you'll get an access token like this
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNTkwOTE0MTk4LCJqdGkiOiJhZDZmNzZhZjFmOGU0ZWJlOGI2Y2Y5YjQ4MGQzZjY2MiIsInVzZXJfaWQiOjExLCJpYXQiOjE1OTA5MTc0OTgsInVzZXIiOiJ0aWFnbyIsImRhdGUiOiIyMDIwLTA1LTMxIn0.-5U9P-WWmhlOenzCvc6b7_71Tz17LyNxe_DOMwwqH4RqrNsilVukEcZWFRGupLHRZjIvPya2QJGpiju9ujzQuw
Using JWT you can see the Payload changing accordingly
{
"token_type": "access",
"exp": 1590914198,
"jti": "ad6f76af1f8e4ebe8b6cf9b480d3f662",
"user_id": 11,
"iat": 1590917498,
"user": "tiago",
"date": "2020-05-31"
}
In your views.py
from rest_framework_simplejwt.tokens import RefreshToken
from rest_framework.response import Response
from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import AllowAny
from decouple import config
from django.contrib.auth import authenticate
import jwt
@api_view(['POST'])
@permission_classes([AllowAny])
def get_tokens_for_user(request):
username = request.POST.get("username")
password = request.POST.get("password")
user = authenticate(username=username, password=password);
if user is not None:
refreshToken = RefreshToken.for_user(user)
accessToken = refreshToken.access_token
decodeJTW = jwt.decode(str(accessToken), config('SECRET_KEY'), algorithms=["HS256"]);
# add payload here!!
decodeJTW['iat'] = '1590917498'
decodeJTW['user'] = 'tiago'
decodeJTW['date'] = '2020-05-31'
#encode
encoded = jwt.encode(decodeJTW, config('SECRET_KEY'), algorithm="HS256")
return Response({
'status': True,
'refresh': str(refreshToken),
'access': str(encoded),
})
else:
return Response({
'status': False
})
# No backend authenticated the credentials
In your urls.py
from django.urls import path, include
from .views import get_tokens_for_user
urlpatterns = [
path('login/', get_tokens_for_user, name="login"),
]
In your settings.py
from pathlib import Path
from datetime import timedelta
from decouple import config
...
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = config('SECRET_KEY')
# Application definition
INSTALLED_APPS = [
...
# Rest
'rest_framework',
...
]
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework_simplejwt.authentication.JWTAuthentication',
],
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.IsAuthenticated',
]
}
# JWT
# https://django-rest-framework-simplejwt.readthedocs.io/en/latest/settings.html
SIMPLE_JWT = {
'ACCESS_TOKEN_LIFETIME': timedelta(minutes=60),
'REFRESH_TOKEN_LIFETIME': timedelta(days=1),
'AUTH_HEADER_TYPES': ('Bearer',),
'SIGNING_KEY': config('SECRET_KEY'),
'VERIFYING_KEY': config('SECRET_KEY'),
'ALGORITHM': 'HS256',
}
In your root directory add .env
SECRET_KEY = 'ep@4ojr4m!h73y2j(stackoverflow)kra1*@tq$5el626wf@&p60)7u!6552+-'
Runtime values
decodeJTW = {
'token_type': 'access',
'exp': 1612651527,
'jti': '7f415b28610348468ce74ec0f480fad1',
'user_id': 2,
'iat': '1590917498',
'user': 'tiago',
'date': '2020-05-31'
}
encode = {
"status":true,
"refresh":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTYxMjczNDU0NywianRpIjoiMDQ0MDI3ZTQzMTc2NDFiNDhhOGI2MjU4MjE4ZGZjNDkiLCJ1c2VyX2lkIjoyfQ.Qf0YfJLAmdYuavDHVng7Bwjmka551G6c1Gi4e-UdRuc",
"access":"b'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNjEyNjUxNzQ3LCJqdGkiOiI2OWEzNjYwYjYxMTk0MzVjYjljZTA0OGQ3MmE1ODk1YSIsInVzZXJfaWQiOjIsImlhdCI6IjE1OTA5MTc0OTgiLCJ1c2VyIjoidGlhZ28iLCJkYXRlIjoiMjAyMC0wNS0zMSJ9.XUMvhL13zDZdbjYYPkYnwlZoHN6U7Zc3xUzXsKoVj2I'"
}
As I came here looking for a solution to add the token expiration to the response while working with dj-rest-auth and djangorestframework_simplejwt I found a solution in the code (apparently undocumented?):
There is a setting called JWT_AUTH_RETURN_EXPIRATION which, if set to True, adds the expiration to the response like so:
{
"access_token": "ACCESS_TOKEN_STRING",
"refresh_token": "REFRESH_TOKEN_STRING",
"user": {
"pk": PK,
"email": "USER_EMAIL"
},
"access_token_expiration": "2021-02-10T10:40:46.883715Z",
"refresh_token_expiration": "2021-02-11T10:35:46.883728Z"
}
and same for refresh:
{
"access": "ACCESS_TOKEN_STRING",
"access_token_expiration": "2021-02-10T10:47:57.325545Z"
}