JWT Authentication0%
JWT Authentication
Beginner12 min read•Updated: Jul 11, 2026
DRF JWT Authentication with SimpleJWT
While standard database tokens require an SQL query on every single HTTP request, JSON Web Tokens (JWT) provide stateless, cryptographically signed authentication. The enterprise standard library for JWT in Django is djangorestframework-simplejwt. It implements short-lived Access Tokens and long-lived Refresh Tokens with built-in token rotation.
1. Dual-Token JWT Architecture
Output
1. Client POST /api/token/ (credentials) ──► Returns: { access: "...", refresh: "..." }
2. Client calls API with: Authorization: Bearer <access_token> (Valid for 5-15 mins)
3. Access token expires (401 Unauthorized)
4. Client POST /api/token/refresh/ (refresh_token) ──► Returns fresh <access_token>
2. Installation & Setup
Bash / Terminal
pip install djangorestframework-simplejwt
Configure JWTAuthentication in settings.py:
Python
# config/settings.py
REST_FRAMEWORK = {
"DEFAULT_AUTHENTICATION_CLASSES": [
"rest_framework_simplejwt.authentication.JWTAuthentication",
],
}
3. Registering JWT Endpoints in urls.py
Python
# config/urls.py
from django.urls import path
from rest_framework_simplejwt.views import (
TokenObtainPairView,
TokenRefreshView,
TokenVerifyView,
)
urlpatterns = [
# 1. Login / Obtain token pair
path("api/token/", TokenObtainPairView.as_view(), name="token_obtain_pair"),
# 2. Silent refresh
path("api/token/refresh/", TokenRefreshView.as_view(), name="token_refresh"),
# 3. Verify validity
path("api/token/verify/", TokenVerifyView.as_view(), name="token_verify"),
]
4. Customizing JWT Lifetimes & Rotation Settings
Python
# config/settings.py
from datetime import timedelta
SIMPLE_JWT = {
"ACCESS_TOKEN_LIFETIME": timedelta(minutes=15), # Short-lived access
"REFRESH_TOKEN_LIFETIME": timedelta(days=7), # Long-lived refresh
"ROTATE_REFRESH_TOKENS": True, # Issue NEW refresh token on refresh
"BLACKLIST_AFTER_ROTATION": True, # Invalidate old refresh token!
"UPDATE_LAST_LOGIN": True,
"ALGORITHM": "HS256",
"SIGNING_KEY": SECRET_KEY,
"AUTH_HEADER_TYPES": ("Bearer",), # Expects: Authorization: Bearer <token>
"USER_ID_FIELD": "id",
"USER_ID_CLAIM": "user_id",
}
5. Adding Custom Claims to Tokens
By default, JWTs only include user_id. You can embed custom claims (like email, role, or tenant_id) to avoid database lookups on client frontends:
Python
# accounts/tokens.py
from rest_framework_simplejwt.serializers import TokenObtainPairSerializer
from rest_framework_simplejwt.views import TokenObtainPairView
class CustomTokenObtainPairSerializer(TokenObtainPairSerializer):
@classmethod
def get_token(cls, user):
token = super().get_token(user)
# Inject custom claims into the signed JWT payload:
token["email"] = user.email
token["role"] = getattr(user, "role", "viewer")
token["organization_id"] = str(user.organization.id) if getattr(user, "organization", None) else None
return token
class CustomTokenObtainPairView(TokenObtainPairView):
serializer_class = CustomTokenObtainPairSerializer
Interactive Quiz
Practice Quiz
Question 1
What header format does SimpleJWT expect for authenticated requests?
Question 2
What security advantage does ROTATE_REFRESH_TOKENS and BLACKLIST_AFTER_ROTATION provide?
Question 3
Why are Access Tokens configured with short lifetimes (e.g. 5 to 15 minutes)?
Question 4
What does the TokenRefreshView endpoint (/api/token/refresh/) do?
Question 5
What information is contained in the signature of a JSON Web Token?
Next Lesson
Custom Permissions
Continue learning with hands-on practice, examples, and exercises in the upcoming topic.
Related Lessons
| Previous Lesson | Next Lesson |
|---|---|
| Token Authentication | Custom Permissions |
Practice Quiz
Test your understanding of this lesson with 5 questions. Each question has one correct answer.