A Beginner’s Guide to JWT Authentication in Django REST Framework
Django REST Framework (DRF) is a powerful tool for building APIs in Django. In this tutorial, we’ll walk through the process of setting up JWT authentication with DRF. JWT authentication can provide a secure and stateless way to authenticate users without relying on traditional sessions.
🤔 What is JWT Authentication?
JWT stands for JSON Web Tokens. JWTs are a way of securely transmitting information between parties in a compact, self-contained way. JWTs can be used to authenticate users, among other things.
A JWT consists of three parts: a header, a payload, and a signature. The header and payload are base64-encoded JSON objects, and the signature is calculated based on a secret key.
When a user logs in, they receive a JWT from the server. The JWT contains information about the user, such as their ID and username. When the user makes a request to an authenticated endpoint, they include the JWT in the request header. The server can then verify the JWT’s signature and use the information in the payload to authenticate the user.
🛠 Setting up JWT Authentication in DRF
To use JWT authentication in DRF, we’ll need to install the djangorestframework-jwt
package. We can do this using pip:
pip install djangorestframework-jwt
Next, we’ll need to add rest_framework_jwt.authentication.JSONWebTokenAuthentication
to the DEFAULT_AUTHENTICATION_CLASSES
setting in our Django settings file:
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
),
}
This tells DRF to use JWT authentication for all API endpoints.
👨💻 Creating a Token View
To generate JWTs for users, we’ll need to create a token view. This view will take a username and password and return a JWT if the user is authenticated.
We can create a new view in one of our app’s views files:
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework_jwt.settings import api_settings
from rest_framework_jwt.views import ObtainJSONWebToken
class TokenObtainView(ObtainJSONWebToken):
def post(self, request, *args, **kwargs):
response = super(TokenObtainView, self).post(request, *args, **kwargs)
token = response.data['token']
return Response({'token': token})
obtain_jwt_token = TokenObtainView.as_view()
This view extends the ObtainJSONWebToken
view from DRF's JWT authentication package. We override the post
method to return just the token instead of the full response.
We’ll also need to add a URL pattern to our app’s urls.py
file to map to this view:
from django.urls import path
from . import views
urlpatterns = [
path('api-token-auth/', views.obtain_jwt_token),
# Other API endpoints go here
]
This will create a URL pattern for our token view at /api-token-auth/
.
💻 Testing Authentication
Now that we’ve set up JWT authentication, let’s test it out. We can use a tool like Postman to make requests to our API.
First, let’s generate a JWT for a user. We can make a POST request to the /api-token-auth/
endpoint with a username and password in the request body:
POST /api-token-auth/
Content-Type: application/json
{
"username": "user1",
"password": "password123"
}
This should return a JSON object with a token
key.
Once we have a JWT, we can use it to authenticate requests to our API. We’ll need to include the JWT in the Authorization
header of our requests.
GET /api/endpoint/
Authorization: JWT eyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9.eyJ1c2VybmFtZSI6ICJ1c2VyMSIsICJleHAiOiAxNjMwNjcyMjk3fQ.AxrLq3jKQnGvaDjRvRlWnX8CvxJzybrjD6wQUQ6bhgI
This should return a response with the requested data. If the JWT is invalid or expired, the server will return a 401 Unauthorized response.
🤝 Refreshing Tokens
By default, JWTs have a short lifespan, usually around 15–30 minutes. After this time, the user will need to log in again to generate a new token.
To avoid this inconvenience, we can implement token refreshing. This allows users to refresh their JWT without logging in again.
To enable token refreshing, we’ll need to add rest_framework_jwt.authentication.JSONWebTokenAuthentication
to the DEFAULT_AUTHENTICATION_CLASSES
setting in our Django settings file, along with rest_framework_jwt.serializers.RefreshJSONWebTokenSerializer
and rest_framework_jwt.views.RefreshJSONWebToken
.
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
),
}
JWT_AUTH = {
'JWT_ALLOW_REFRESH': True,
'JWT_REFRESH_EXPIRATION_DELTA': timedelta(days=7),
'JWT_AUTH_HEADER_PREFIX': 'Bearer',
'JWT_AUTH_COOKIE': None,
'JWT_AUTH_TOKEN_CLASSES': (
'rest_framework_jwt.tokens.AccessToken',
'rest_framework_jwt.tokens.RefreshToken',
),
}
The JWT_ALLOW_REFRESH
setting allows token refreshing. The JWT_REFRESH_EXPIRATION_DELTA
setting determines how long a refresh token is valid. The JWT_AUTH_HEADER_PREFIX
setting specifies the prefix for the Authorization
header. The JWT_AUTH_COOKIE
setting specifies the name of the cookie used for authentication. The JWT_AUTH_TOKEN_CLASSES
setting specifies the types of tokens that can be used for authentication.
We’ll also need to create a view for refreshing tokens:
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework_jwt.settings import api_settings
from rest_framework_jwt.views import RefreshJSONWebToken
class TokenRefreshView(RefreshJSONWebToken):
def post(self, request, *args, **kwargs):
response = super(TokenRefreshView, self).post(request, *args, **kwargs)
token = response.data['token']
return Response({'token': token})
refresh_jwt_token = TokenRefreshView.as_view()
This view extends the RefreshJSONWebToken
view from DRF's JWT authentication package. We override the post
method to return just the token instead of the full response.
We’ll also need to add a URL pattern to our app’s urls.py
file to map to this view:
from django.urls import path
from . import views
urlpatterns = [
path('api-token-auth/', views.obtain_jwt_token),
path('api-token-refresh/', views.refresh_jwt_token),
# Other API endpoints go here
]
This will create a URL pattern for our token refreshing view at /api-token-refresh/
.
To refresh a token, we can make a POST request to the /api-token-refresh/
endpoint with the old token in the Authorization
header:
POST /api-token-refresh/
Authorization: JWT eyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9.eyJ1c2VybmFtZSI6ICJ1c2VyMSIsICJleHAiOiAxNjMwNjcyMjk3fQ.AxrLq3jKQnGvaDjRvRlWnX8CvxJzybrjD6wQUQ6bhgI
The response should include a new JWT:
HTTP 200 OK
Allow: POST, OPTIONS
Content-Type: application/json
Vary: Accept
{
"token": "eyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9.eyJ1c2VybmFtZSI6ICJ1c2VyMSIsICJleHAiOiAxNjMwNzA1NjE1fQ.BhnwBQokxTULjQd0Byr6LTYj1R43G64_LJ0DmBodmZM"
}
We can then use this new token to authenticate future requests.
👋 Conclusion
JWT authentication is a powerful tool for securing Django REST Framework APIs. With just a few configuration changes, we can implement token-based authentication and authorization for our API endpoints. By understanding the basics of JWTs and their usage in DRF, we can build more secure and scalable web applications.
🎉 Thanks for reading
Hey there — I hope you found this article informative and helpful. If you have any questions or comments, please feel free to reach out to me via email (alisheikh1114@gmail.com). I am always eager to connect with readers and help them with any technical challenges they may be facing.
👨💻 Let’s connect on social media
Don’t forget to follow me on Medium if you are interested in reading about Web Dev Stacks, Big Data, and Open Source.
Find me online: GitHub • LinkedIn • Twitter • Facebook • Instagram
🤝 Share the knowledge
If you found this article useful, please consider sharing it with your friends and colleagues who might benefit from it. Sharing is caring, and it helps spread knowledge and insights to those who need it the most.