Hello! Welcome back to our backend engineering course.
In our last lesson, we explored the theory behind JSON Web Tokens (JWTs). We learned that they are stateless, self-contained tokens whose integrity is verified cryptographically, making them a powerful tool for building scalable, modern APIs. You now understand the structure of a JWT (Header, Payload, Signature) and the crucial role of the signature in preventing tampering.
Today, we move from theory to practice. This lesson is all about implementing JWT-based authentication in our Django REST Framework application. We will replace our previous stateful token system with a more robust, stateless JWT implementation using a popular and well-maintained library. By the end of this lesson, you'll have a fully functional JWT authentication flow in your API.
1. The Access and Refresh Token Strategy
In a typical JWT implementation, we don't just issue one token. Instead, we issue two: an Access Token and a Refresh Token. This pattern is a security best practice.
- Access Token: This is a short-lived token (e.g., 15 minutes) that is sent with every API request to prove authentication. Because it's short-lived, the risk is minimized if it's ever compromised.
- Refresh Token: This is a long-lived token (e.g., several days) that is stored securely by the client. Its only purpose is to request a new access token when the old one expires. It is never sent to access data endpoints.
This two-token system provides a good balance between security and user experience, as the user doesn't need to log in with their password every 15 minutes.
How to use JWT Authentication with Django REST ...
To understand this workflow better, let's read a short section from the article 'How to use JWT Authentication with Django REST Framework' by Remote Inning.
Read the section titled 'JWT Authentication Workflow'. It clearly explains the roles of the access and refresh tokens and how they interact in a typical authentication flow.
2. Setting Up djangorestframework-simplejwt
The most popular library for adding JWT support to DRF is djangorestframework-simplejwt. It's powerful, customizable, and handles the complexities of token generation and verification for us.
We'll follow a clear, three-step process: install the library, configure it in settings.py, and set up the necessary URL endpoints.
Django REST Framework - JWT Authentication with djangorestframework-simplejwt
This video from the BugBytes channel provides an excellent, concise walkthrough of the entire setup process. We will follow it to get our basic JWT implementation working.
Watch from 05:33 to 08:49. Follow along with the video to install the package and configure your settings.py and urls.py files.
Let's break down the steps from the video for clarity:
Step 1: Install the Package
In your activated virtual environment, run:
pip install djangorestframework-simplejwt
Step 2: Configure settings.py
You need to tell DRF to use simplejwt as its default authentication method. Modify your REST_FRAMEWORK dictionary:
# in settings.py
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework_simplejwt.authentication.JWTAuthentication',
# Keep other authentication classes if needed, e.g., for the browsable API
'rest_framework.authentication.SessionAuthentication',
),
# ... other settings
}
DRF attempts to authenticate using each class in this list in order. By placing JWTAuthentication first, we make it the primary method for our API.
Step 3: Configure urls.py
The library provides built-in views for obtaining and refreshing tokens. We just need to wire them up in our project's main urls.py.

Your urls.py should include these patterns:
# in your project's urls.py
from django.urls import path, include
from rest_framework_simplejwt.views import (
TokenObtainPairView,
TokenRefreshView,
)
urlpatterns = [
# ... your other urls
path('api/token/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
path('api/token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
]
With these three steps, your backend is now ready to issue and verify JWTs.
3. JWT in Action: The Authentication Flow
Now, let's use the endpoints we just created.
Django REST Framework - JWT Authentication with djangorestframework-simplejwt
Let's continue with the BugBytes video, which demonstrates how to use these new endpoints with a REST client and how to use the generated token.
Watch from 08:49 to 13:00. Pay attention to how a POST request with user credentials returns tokens, and how the 'Bearer' token is then used in the Authorization header for subsequent requests.
Here is a summary of the flow shown in the video:
-
Obtain Tokens: Send a
POSTrequest to your/api/token/endpoint with the user's credentials in the request body.- Request Body:
{"username": "your_username", "password": "your_password"} - Successful Response: The server will return a JSON object containing
accessandrefreshtokens.
- Request Body:
-
Decode the Token (Optional but Recommended): Copy the
accesstoken and paste it into the debugger on jwt.io. This is a great way to visually confirm the concepts from our previous lesson. You will see the decoded header and payload, including claims likeuser_idand the expiration time (exp). This reinforces that the token is self-contained but not encrypted. -
Access a Protected Endpoint: To access a protected view, include the access token in the
Authorizationheader of your request, prefixed with "Bearer".- Header:
Authorization: Bearer <your_access_token> - If the token is valid, DRF will authenticate the user and grant access. If the token is missing, expired, or tampered with, you will receive a
401 Unauthorizederror.
- Header:
Test your understanding!
You've configured your SIMPLE_JWT settings in settings.py to have an ACCESS_TOKEN_LIFETIME of 5 minutes. A user logs in and gets their tokens. They use the API successfully for 4 minutes. At the 6-minute mark, they make another request to a protected endpoint using the same access token.
What HTTP status code should they expect to receive, and what is the very next action their client-side application should take?
Show answer
They should expect a 401 Unauthorized status code because the access token has expired.
The very next action the client application should take is to use the refresh token to make a POST request to the /api/token/refresh/ endpoint. This will return a new, valid access token, which can then be used to retry the original failed request.
4. Customizing Token Behavior
simplejwt is highly configurable. You can control token lifetimes, signing algorithms, and more through a SIMPLE_JWT dictionary in your settings.py. Your background in building complex systems will make you appreciate this level of control.
Django Rest Framework Series - JWT Token Authentication with React - Part-3
The Very Academy channel has a detailed video covering the various configuration options available. This will give you a deeper understanding of how to tailor the JWT behavior to your needs.
Watch from 37:02 to 41:42. Focus on understanding the ACCESS_TOKEN_LIFETIME and REFRESH_TOKEN_LIFETIME settings, as these are the most common ones to customize.
A common configuration looks like this:
# in settings.py
from datetime import timedelta
SIMPLE_JWT = {
"ACCESS_TOKEN_LIFETIME": timedelta(minutes=5),
"REFRESH_TOKEN_LIFETIME": timedelta(days=1),
"ROTATE_REFRESH_TOKENS": False,
"BLACKLIST_AFTER_ROTATION": False,
"UPDATE_LAST_LOGIN": False,
"ALGORITHM": "HS256",
"SIGNING_KEY": SECRET_KEY,
"AUTH_HEADER_TYPES": ("Bearer",),
}
Here, we've set access tokens to expire in 5 minutes and refresh tokens to expire in 1 day.
5. Advanced Topic: Security with Blacklisting
What happens if a refresh token is stolen? The attacker could use it to generate new access tokens until it expires. To mitigate this, we can implement token blacklisting. When a user logs out, we add their refresh token to a "blacklist" so it can no longer be used.
Build a Blog API With JWT Authentication Using Django ...
This article from dev.to explains how to set up token blacklisting with simplejwt. This is a critical security feature for a production application.
First, read the small subsection within the 'JWT Authentication' section that explains ROTATE_REFRESH_TOKENS and BLACKLIST_AFTER_ROTATION. This covers adding 'rest_framework_simplejwt.token_blacklist' to INSTALLED_APPS and running migrate. Then, jump to the 'User Registration and Login Endpoints' section and examine the code for UserLogoutAPIView. This view shows exactly how to blacklist a token upon logout.
The process involves three steps:
- Add to
INSTALLED_APPS: Add'rest_framework_simplejwt.token_blacklist'to yourINSTALLED_APPSinsettings.py. - Migrate: Run
python manage.py migrate. This creates the database table to store blacklisted tokens. - Create a Logout View: Implement a view that takes a refresh token from the request body and adds it to the blacklist.
Here is an example of a logout view, as shown in the article:
# in your views.py
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from rest_framework.permissions import IsAuthenticated
from rest_framework_simplejwt.tokens import RefreshToken
class LogoutView(APIView):
permission_classes = (IsAuthenticated,)
def post(self, request):
try:
refresh_token = request.data["refresh"]
token = RefreshToken(refresh_token)
token.blacklist()
return Response(status=status.HTTP_205_RESET_CONTENT)
except Exception as e:
return Response(status=status.HTTP_400_BAD_REQUEST)
When a user logs out, the client sends their refresh token to this endpoint, effectively invalidating it for future use.
Conclusion
Congratulations! You've successfully implemented a modern, stateless JWT authentication system in your Django REST Framework API. You've moved beyond the basic built-in tools to a solution that is robust, scalable, and secure.
Key Takeaways:
- Implementation: We use
djangorestframework-simplejwtto handle JWTs in DRF. The setup involves installing the package, and configuringsettings.pyandurls.py. - Token Flow: Users authenticate with credentials at
/api/token/to get an access and refresh token pair. - Authorization: The short-lived access token is sent in the
Authorization: Bearer <token>header to access protected resources. - Token Refresh: When the access token expires, the long-lived refresh token is sent to
/api/token/refresh/to get a new access token. - Security: Token lifetimes can be configured for a balance of security and usability. Blacklisting refresh tokens on logout is a critical step to prevent misuse of stolen tokens.
Preview of the Next Lesson:
So far in this module, we've focused on authentication—the process of verifying who a user is. Now that we have a solid authentication system, the next logical step is authorization: controlling what an authenticated user is allowed to do. In the next module, we will dive into Django's and DRF's permission systems to implement role-based access control and secure our API endpoints even further.