Skip to content

JWT Setup

Terminal window
pip install djangorestframework-simplejwt
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework_simplejwt.authentication.JWTAuthentication',
],
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.IsAuthenticatedOrReadOnly',
],
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
'PAGE_SIZE': 10,
'DEFAULT_FILTER_BACKENDS': [
'django_filters.rest_framework.DjangoFilterBackend',
'rest_framework.filters.SearchFilter',
'rest_framework.filters.OrderingFilter',
],
}
from datetime import timedelta
SIMPLE_JWT = {
'ACCESS_TOKEN_LIFETIME': timedelta(minutes=60),
'REFRESH_TOKEN_LIFETIME': timedelta(days=1),
'ROTATE_REFRESH_TOKENS': True,
'BLACKLIST_AFTER_ROTATION': True,
'UPDATE_LAST_LOGIN': False,
'ALGORITHM': 'HS256',
'SIGNING_KEY': SECRET_KEY,
'VERIFYING_KEY': None,
'AUDIENCE': None,
'ISSUER': None,
'AUTH_HEADER_TYPES': ('Bearer',),
'AUTH_HEADER_NAME': 'HTTP_AUTHORIZATION',
'USER_ID_FIELD': 'id',
'USER_ID_CLAIM': 'user_id',
'USER_AUTHENTICATION_RULE': 'rest_framework_simplejwt.authentication.default_user_authentication_rule',
'AUTH_TOKEN_CLASSES': ('rest_framework_simplejwt.tokens.AccessToken',),
'TOKEN_TYPE_CLAIM': 'token_type',
'JTI_CLAIM': 'jti',
'SLIDING_TOKEN_REFRESH_EXP_CLAIM': 'refresh_exp',
'SLIDING_TOKEN_LIFETIME': timedelta(minutes=5),
'SLIDING_TOKEN_REFRESH_LIFETIME': timedelta(days=1),
}
from django.urls import path, include
from rest_framework_simplejwt.views import (
TokenObtainPairView,
TokenRefreshView,
TokenVerifyView,
)
urlpatterns = [
path('admin/', admin.site.urls),
path('api/', include('api.urls')),
path('api/auth/', include([
path('token/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
path('token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
path('token/verify/', TokenVerifyView.as_view(), name='token_verify'),
])),
]

Create api/serializers.py (add to existing)

Section titled “Create api/serializers.py (add to existing)”
from django.contrib.auth.models import User
from rest_framework import serializers
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ['id', 'username', 'email', 'first_name', 'last_name', 'is_staff']
read_only_fields = ['is_staff']
class UserRegistrationSerializer(serializers.ModelSerializer):
password = serializers.CharField(write_only=True, min_length=8)
password_confirm = serializers.CharField(write_only=True)
class Meta:
model = User
fields = ['username', 'email', 'password', 'password_confirm', 'first_name', 'last_name']
def validate(self, attrs):
if attrs['password'] != attrs['password_confirm']:
raise serializers.ValidationError({"password": "Password fields didn't match."})
return attrs
def create(self, validated_data):
validated_data.pop('password_confirm')
user = User.objects.create_user(**validated_data)
return user
from rest_framework import generics, status
from rest_framework.decorators import api_view, permission_classes
from rest_framework.response import Response
from rest_framework.permissions import AllowAny, IsAuthenticated
from django.contrib.auth.models import User
from .serializers import UserSerializer, UserRegistrationSerializer
class UserRegistrationView(generics.CreateAPIView):
queryset = User.objects.all()
serializer_class = UserRegistrationSerializer
permission_classes = [AllowAny]
class UserProfileView(generics.RetrieveUpdateAPIView):
serializer_class = UserSerializer
permission_classes = [IsAuthenticated]
def get_object(self):
return self.request.user
@api_view(['GET'])
@permission_classes([IsAuthenticated])
def protected_view(request):
return Response({
'message': 'This is a protected view!',
'user': request.user.username,
'email': request.user.email
})
@api_view(['POST'])
@permission_classes([AllowAny])
def token_test(request):
# This view doesn't require authentication
return Response({'message': 'Token test successful - no authentication needed'})
from django.urls import path
from . import views
urlpatterns = [
# ... existing URLs ...
# Authentication URLs
path('auth/register/', views.UserRegistrationView.as_view(), name='user-register'),
path('auth/profile/', views.UserProfileView.as_view(), name='user-profile'),
path('auth/protected/', views.protected_view, name='protected-view'),
path('auth/token-test/', views.token_test, name='token-test'),
]

Update existing views to use authentication

Section titled “Update existing views to use authentication”
# In api/views.py, update existing class-based views:
from .permissions import IsAdminOrReadOnly, IsOwnerOrReadOnly
class CategoryListCreateView(generics.ListCreateAPIView):
queryset = Category.objects.all()
serializer_class = CategorySerializer
permission_classes = [IsAuthenticatedOrReadOnly] # Updated
# Optional: Set user on create
def perform_create(self, serializer):
# If you want to track who created categories
serializer.save()
class ProductListCreateView(generics.ListCreateAPIView):
queryset = Product.objects.select_related('category').all()
serializer_class = ProductSerializer
permission_classes = [IsAuthenticatedOrReadOnly] # Updated
Terminal window
curl -X POST http://127.0.0.1:8000/api/auth/register/ \
-H "Content-Type: application/json" \
-d '{
"username": "testuser",
"email": "test@example.com",
"password": "testpass123",
"password_confirm": "testpass123",
"first_name": "Test",
"last_name": "User"
}'
Terminal window
curl -X POST http://127.0.0.1:8000/api/auth/token/ \
-H "Content-Type: application/json" \
-d '{
"username": "testuser",
"password": "testpass123"
}'
Terminal window
# Copy the access token from previous response
ACCESS_TOKEN="your-access-token-here"
# Access protected endpoint
curl http://127.0.0.1:8000/api/auth/protected/ \
-H "Authorization: Bearer $ACCESS_TOKEN"
# Access protected API endpoints
curl http://127.0.0.1:8000/api/products/ \
-H "Authorization: Bearer $ACCESS_TOKEN"
Terminal window
curl -X POST http://127.0.0.1:8000/api/auth/token/refresh/ \
-H "Content-Type: application/json" \
-d '{
"refresh": "your-refresh-token-here"
}'
from rest_framework import permissions
class IsAdminOrReadOnly(permissions.BasePermission):
def has_permission(self, request, view):
if request.method in permissions.SAFE_METHODS:
return True
return request.user and request.user.is_staff
class IsOwnerOrReadOnly(permissions.BasePermission):
def has_object_permission(self, request, view, obj):
if request.method in permissions.SAFE_METHODS:
return True
# Check if object has user attribute
if hasattr(obj, 'user'):
return obj.user == request.user
elif hasattr(obj, 'owner'):
return obj.owner == request.user
return False
class IsAuthenticatedOrCreateOnly(permissions.BasePermission):
def has_permission(self, request, view):
if request.method == 'POST':
return True
return request.user and request.user.is_authenticated