Django REST Framework Authentication

Securing your API with authentication methods

🔐 What is API Authentication?

Authentication identifies who is making API requests. DRF provides multiple authentication methods including tokens, sessions, and JWT. It ensures only authorized users can access protected endpoints and perform specific actions.


# Protect views with authentication
from rest_framework.permissions import IsAuthenticated

class BookViewSet(viewsets.ModelViewSet):
    permission_classes = [IsAuthenticated]
    queryset = Book.objects.all()
    serializer_class = BookSerializer
                                    

Unauthorized Response:

{
    "detail": "Authentication credentials were not provided."
}

Authentication Methods

🎫

Token Auth

Simple token-based auth

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'rest_framework.authentication.TokenAuthentication',
    ]
}
🍪

Session Auth

Django session-based auth

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'rest_framework.authentication.SessionAuthentication',
    ]
}
🔑

Basic Auth

Username/password in headers

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'rest_framework.authentication.BasicAuthentication',
    ]
}
🎯

JWT Auth

JSON Web Token auth

# Using djangorestframework-simplejwt
from rest_framework_simplejwt.authentication import JWTAuthentication

🔹 Token Authentication Setup

Token authentication is simple and secure. Each user gets a unique token for API access. Perfect for mobile apps and single-page applications:

# settings.py
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'rest_framework',
    'rest_framework.authtoken',  # Add this
]

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'rest_framework.authentication.TokenAuthentication',
    ],
    'DEFAULT_PERMISSION_CLASSES': [
        'rest_framework.permissions.IsAuthenticated',
    ],
}
# Run migrations to create token table
python manage.py migrate
# views.py - Create login endpoint
from rest_framework.authtoken.models import Token
from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import AllowAny
from rest_framework.response import Response
from django.contrib.auth import authenticate

@api_view(['POST'])
@permission_classes([AllowAny])
def login(request):
    username = request.data.get('username')
    password = request.data.get('password')
    
    user = authenticate(username=username, password=password)
    if user:
        token, created = Token.objects.get_or_create(user=user)
        return Response({'token': token.key})
    return Response({'error': 'Invalid credentials'}, status=400)

Usage Example:

# Login Request
POST /api/login/
{"username": "john", "password": "secret123"}

# Response
{"token": "9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b"}

# Use token in subsequent requests
GET /api/books/
Authorization: Token 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b

🔹 Session Authentication

Session authentication uses Django's built-in session framework. Best for web applications where users log in through a browser:

# settings.py
REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'rest_framework.authentication.SessionAuthentication',
    ],
}
# views.py
from django.contrib.auth import login, logout
from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import AllowAny
from rest_framework.response import Response
from django.contrib.auth import authenticate

@api_view(['POST'])
@permission_classes([AllowAny])
def user_login(request):
    username = request.data.get('username')
    password = request.data.get('password')
    
    user = authenticate(username=username, password=password)
    if user:
        login(request, user)
        return Response({'message': 'Logged in successfully'})
    return Response({'error': 'Invalid credentials'}, status=400)

@api_view(['POST'])
def user_logout(request):
    logout(request)
    return Response({'message': 'Logged out successfully'})

Session Auth Features:

  • Uses cookies for authentication
  • Integrates with Django admin
  • CSRF protection required for POST/PUT/DELETE
  • Best for same-domain web apps

🔹 Permission Classes

Control who can access your API endpoints using permission classes. Combine with authentication for fine-grained access control:

# views.py
from rest_framework import viewsets
from rest_framework.permissions import (
    IsAuthenticated,
    IsAuthenticatedOrReadOnly,
    AllowAny,
    IsAdminUser
)

# Only authenticated users can access
class BookViewSet(viewsets.ModelViewSet):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    permission_classes = [IsAuthenticated]

# Anyone can read, only authenticated can write
class PublicBookViewSet(viewsets.ModelViewSet):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    permission_classes = [IsAuthenticatedOrReadOnly]

# Only admin users can access
class AdminBookViewSet(viewsets.ModelViewSet):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    permission_classes = [IsAdminUser]

# Anyone can access (no authentication)
class OpenBookViewSet(viewsets.ModelViewSet):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    permission_classes = [AllowAny]

Built-in Permission Classes:

  • AllowAny: No restrictions
  • IsAuthenticated: Requires login
  • IsAdminUser: Only admin users
  • IsAuthenticatedOrReadOnly: Read for all, write for authenticated

🔹 Custom Permissions

Create custom permission classes for specific business logic and access control rules:

# permissions.py
from rest_framework import permissions

class IsOwnerOrReadOnly(permissions.BasePermission):
    """
    Custom permission: only owners can edit
    """
    def has_object_permission(self, request, view, obj):
        # Read permissions for any request
        if request.method in permissions.SAFE_METHODS:
            return True
        
        # Write permissions only for owner
        return obj.owner == request.user

class IsAuthorOrAdmin(permissions.BasePermission):
    """
    Custom permission: authors and admins only
    """
    def has_permission(self, request, view):
        return request.user.is_authenticated and (
            request.user.is_staff or 
            request.user.groups.filter(name='Authors').exists()
        )
# views.py
from .permissions import IsOwnerOrReadOnly

class BookViewSet(viewsets.ModelViewSet):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    permission_classes = [IsAuthenticated, IsOwnerOrReadOnly]
    
    def perform_create(self, serializer):
        serializer.save(owner=self.request.user)

🔹 JWT Authentication

JSON Web Tokens provide stateless authentication with access and refresh tokens. Great for modern APIs and microservices:

# Install JWT package
pip install djangorestframework-simplejwt
# settings.py
from datetime import timedelta

INSTALLED_APPS = [
    # ...
    'rest_framework',
    'rest_framework_simplejwt',
]

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'rest_framework_simplejwt.authentication.JWTAuthentication',
    ],
}

SIMPLE_JWT = {
    'ACCESS_TOKEN_LIFETIME': timedelta(minutes=60),
    'REFRESH_TOKEN_LIFETIME': timedelta(days=1),
}
# urls.py
from rest_framework_simplejwt.views import (
    TokenObtainPairView,
    TokenRefreshView,
)

urlpatterns = [
    path('api/token/', TokenObtainPairView.as_view(), name='token_obtain'),
    path('api/token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
]

JWT Usage:

# Get tokens
POST /api/token/
{"username": "john", "password": "secret123"}

Response:
{
    "access": "eyJ0eXAiOiJKV1QiLCJhbGc...",
    "refresh": "eyJ0eXAiOiJKV1QiLCJhbGc..."
}

# Use access token
GET /api/books/
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGc...

# Refresh token when expired
POST /api/token/refresh/
{"refresh": "eyJ0eXAiOiJKV1QiLCJhbGc..."}

🔹 Multiple Authentication Methods

Support multiple authentication methods simultaneously for flexibility across different client types:

# settings.py
REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'rest_framework.authentication.TokenAuthentication',
        'rest_framework.authentication.SessionAuthentication',
        'rest_framework_simplejwt.authentication.JWTAuthentication',
    ],
    'DEFAULT_PERMISSION_CLASSES': [
        'rest_framework.permissions.IsAuthenticated',
    ],
}
# views.py - Per-view authentication
from rest_framework.authentication import TokenAuthentication, SessionAuthentication

class BookViewSet(viewsets.ModelViewSet):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    authentication_classes = [TokenAuthentication, SessionAuthentication]
    permission_classes = [IsAuthenticated]

When to use multiple methods:

  • Web app (sessions) + Mobile app (tokens)
  • Supporting legacy and new clients
  • Admin interface + Public API
  • Gradual migration between auth methods

🧠 Test Your Knowledge

Which authentication method uses a unique string for each user?