Introduction
While tokens are popular for APIs, session authentication remains valuable—especially for web applications where your frontend and backend share the same domain. Django's built-in session framework provides battle-tested security with minimal configuration.
Key Concepts
Session Authentication: Using Django's session cookies to identify users. The session ID is stored in a cookie and maps to user data on the server.
CSRF Protection: Required for session-based APIs since browsers automatically send cookies. The CSRF token prevents cross-site request forgery.
Same-Origin Policy: Session auth works best when frontend and backend share the same origin (domain + port).
Real World Context
Session authentication is ideal for:
- Traditional web apps: Django templates with AJAX calls
- Same-domain SPAs: React/Vue apps served from the same domain
- Admin interfaces: Internal tools where simplicity matters
- Hybrid applications: Mix of server-rendered pages and API calls
Deep Dive
Enabling Session Authentication
Django sessions are enabled by default. Verify your settings:
python# settings.py INSTALLED_APPS = [ 'django.contrib.sessions', 'django.contrib.auth', # ... ] MIDDLEWARE = [ 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', # ... ]
These three middleware components work together: SessionMiddleware manages session cookies, CsrfViewMiddleware protects against cross-site request forgery, and AuthenticationMiddleware attaches the user to each request.
Login/Logout API Endpoints
These endpoints use Django's built-in authenticate(), login(), and logout() functions, which manage session creation and destruction automatically:
pythonimport json from django.http import JsonResponse from django.contrib.auth import authenticate, login, logout from django.views.decorators.http import require_POST from django.middleware.csrf import get_token def api_csrf_token(request): """Return CSRF token for AJAX requests.""" return JsonResponse({'csrfToken': get_token(request)}) @require_POST def api_login(request): data = json.loads(request.body) user = authenticate( request, username=data.get('username'), password=data.get('password') ) if user is None: return JsonResponse({'error': 'Invalid credentials'}, status=401) login(request, user) return JsonResponse({ 'user': {'id': user.id, 'username': user.username} }) @require_POST def api_logout(request): logout(request) return JsonResponse({'message': 'Logged out'}) def api_current_user(request): if request.user.is_authenticated: return JsonResponse({ 'user': {'id': request.user.id, 'username': request.user.username} }) return JsonResponse({'user': None})
The @require_POST decorator rejects non-POST requests with 405. The login() call creates a session and sets the session cookie, while logout() destroys it.
CSRF with AJAX
Session-based APIs require CSRF tokens for state-changing requests. Extract the token from the cookie and include it as a header:
javascript// Get CSRF token from cookie function getCookie(name) { const value = `; ${document.cookie}`; const parts = value.split(`; ${name}=`); if (parts.length === 2) return parts.pop().split(';').shift(); } // Include in requests fetch('/api/articles/', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-CSRFToken': getCookie('csrftoken'), }, credentials: 'same-origin', // Important! body: JSON.stringify({title: 'New Article'}) });
The credentials: 'same-origin' option is essential -- without it, fetch does not send cookies, and the session will not be recognized.
Secure Session Settings
In production, harden your session cookies with these security settings:
python# settings.py (production) SESSION_COOKIE_SECURE = True # HTTPS only SESSION_COOKIE_HTTPONLY = True # No JavaScript access SESSION_COOKIE_SAMESITE = 'Lax' # CSRF protection CSRF_COOKIE_SECURE = True CSRF_COOKIE_HTTPONLY = False # JS needs to read this
Note that CSRF_COOKIE_HTTPONLY stays False because JavaScript must read the CSRF cookie to include it in request headers. The session cookie, however, should always be httponly.
Common Pitfalls
-
Forgetting credentials: 'same-origin': Fetch doesn't send cookies by default. Always include credentials option.
-
CORS issues: Session auth doesn't work well cross-origin. Use tokens for cross-domain APIs.
-
Missing CSRF token: POST/PUT/DELETE requests need the X-CSRFToken header.
Best Practices
-
Use sessions for same-origin: When frontend and backend share a domain, sessions are simpler than tokens.
-
Secure your cookies: Always set Secure, HttpOnly, and SameSite flags in production.
-
Provide a CSRF endpoint: Let SPAs fetch a fresh CSRF token on page load.
Summary
Session authentication leverages Django's built-in session framework for API security. It works best for same-origin applications where cookies are automatically sent. Remember to handle CSRF tokens for non-GET requests and configure secure cookie settings in production.
Code Examples
import json
from django.http import JsonResponse
from django.contrib.auth import authenticate, login, logout
from django.views.decorators.http import require_POST
@require_POST
def api_login(request):
data = json.loads(request.body)
user = authenticate(
request,
username=data.get('username'),
password=data.get('password')
)
if user is None:
return JsonResponse({'error': 'Invalid credentials'}, status=401)
login(request, user)
return JsonResponse({'user': {'id': user.id, 'username': user.username}})