JWT Setup
2. JWT Authentication Setup
Section titled “2. JWT Authentication Setup”Step 1: Install Required Packages
Section titled “Step 1: Install Required Packages”pip install djangorestframework-simplejwtStep 2: Configure JWT in Settings
Section titled “Step 2: Configure JWT in Settings”Update config/settings.py
Section titled “Update config/settings.py”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),}Step 3: Create Authentication URLs
Section titled “Step 3: Create Authentication URLs”Update config/urls.py
Section titled “Update config/urls.py”from django.urls import path, includefrom 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'), ])),]Step 4: Create User Serializer
Section titled “Step 4: Create User Serializer”Create api/serializers.py (add to existing)
Section titled “Create api/serializers.py (add to existing)”from django.contrib.auth.models import Userfrom 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 userStep 5: Create Authentication Views
Section titled “Step 5: Create Authentication Views”Update api/views.py
Section titled “Update api/views.py”from rest_framework import generics, statusfrom rest_framework.decorators import api_view, permission_classesfrom rest_framework.response import Responsefrom rest_framework.permissions import AllowAny, IsAuthenticatedfrom django.contrib.auth.models import Userfrom .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'})Step 6: Update API URLs
Section titled “Step 6: Update API URLs”Update api/urls.py
Section titled “Update api/urls.py”from django.urls import pathfrom . 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'),]Step 7: Update Permissions
Section titled “Step 7: Update Permissions”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] # UpdatedStep 8: Test JWT Authentication
Section titled “Step 8: Test JWT Authentication”Test Registration
Section titled “Test Registration”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" }'Get Access Token
Section titled “Get Access Token”curl -X POST http://127.0.0.1:8000/api/auth/token/ \ -H "Content-Type: application/json" \ -d '{ "username": "testuser", "password": "testpass123" }'Use Access Token
Section titled “Use Access Token”# Copy the access token from previous responseACCESS_TOKEN="your-access-token-here"
# Access protected endpointcurl http://127.0.0.1:8000/api/auth/protected/ \ -H "Authorization: Bearer $ACCESS_TOKEN"
# Access protected API endpointscurl http://127.0.0.1:8000/api/products/ \ -H "Authorization: Bearer $ACCESS_TOKEN"Refresh Token
Section titled “Refresh Token”curl -X POST http://127.0.0.1:8000/api/auth/token/refresh/ \ -H "Content-Type: application/json" \ -d '{ "refresh": "your-refresh-token-here" }'Step 9: Create Custom Permissions
Section titled “Step 9: Create Custom Permissions”Update api/permissions.py
Section titled “Update api/permissions.py”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