CSRF & Authentication Debugger
Analyzes and debugs CSRF and authentication issues in this project.
Project Context
-
Authentication: JWT tokens in httpOnly cookies + OAuth (Google, GitHub)
-
CSRF: Django's CSRF middleware with cookie-based tokens
-
OAuth library: django-allauth
-
Token service: services/auth/tokens.py
-
Frontend API: Axios with credentials and CSRF interceptor
Authentication Architecture
Browser ↓ Request with cookies │ - access_token (httpOnly, JWT) │ - refresh_token (httpOnly, JWT) │ - csrftoken (readable by JS) Django ↓ CsrfViewMiddleware ↓ JWTAuthenticationMiddleware ↓ View/API endpoint
When to Use
-
"CSRF verification failed"
-
"403 Forbidden on POST/PUT/DELETE"
-
"Login not working"
-
"Token expired"
-
"OAuth callback failing"
-
"Cookies not being set"
-
"X-CSRFToken header missing"
CSRF Flow
How CSRF Works in This Project
-
GET /api/v1/auth/csrf/
-
Sets csrftoken cookie
-
Frontend reads cookie - getCookie('csrftoken')
-
POST/PUT/DELETE requests - Include X-CSRFToken header
-
Django validates - Compares header to cookie
Frontend CSRF Handling
// frontend/src/services/api.ts api.interceptors.request.use((config) => { if (['post', 'put', 'patch', 'delete'].includes(method)) { const csrfToken = getCookie('csrftoken'); if (csrfToken) { config.headers['X-CSRFToken'] = csrfToken; } } });
Common CSRF Issues
403 "CSRF verification failed":
Missing CSRF cookie
Check if cookie exists in browser DevTools > Application > Cookies
Should see: csrftoken
Missing X-CSRFToken header
// Check Network tab - request headers should include: // X-CSRFToken: <token value>
Cookie not sent (CORS)
// Axios must have: withCredentials: true
Domain mismatch
settings.py - check these match your domain
CSRF_COOKIE_DOMAIN = None # or '.yourdomain.com' CSRF_TRUSTED_ORIGINS = ['http://localhost:3000', ...]
SameSite cookie issues
For cross-origin requests:
CSRF_COOKIE_SAMESITE = 'Lax' # or 'None' with Secure
Common Auth Issues
JWT token expired:
Check token expiry in services/auth/tokens.py
ACCESS_TOKEN_LIFETIME = timedelta(minutes=15) REFRESH_TOKEN_LIFETIME = timedelta(days=7)
Cookies not set after login:
Check response has Set-Cookie headers
Verify SameSite and Secure flags match environment
OAuth callback failing:
Check callback URL matches exactly:
- In Google/GitHub OAuth app settings
- In django-allauth config
- Including trailing slashes!
Debugging Steps
- Check CSRF Cookie Exists
// Browser console document.cookie.split(';').find(c => c.includes('csrftoken'))
- Check Request Headers
Network tab > Request > Headers Look for: X-CSRFToken: <value>
- Check Django Logs
docker compose logs web | grep -i csrf
- Test CSRF Endpoint
curl -c cookies.txt http://localhost:8000/api/v1/auth/csrf/ cat cookies.txt # Should show csrftoken
- Verify Settings
Django shell
from django.conf import settings print(settings.CSRF_COOKIE_NAME) print(settings.CSRF_TRUSTED_ORIGINS) print(settings.CORS_ALLOWED_ORIGINS)
Key Files to Check
Backend: ├── config/settings.py # CSRF_, CORS_, cookie settings ├── core/auth/views.py # Login, logout, OAuth views ├── core/views/core_views.py # CSRF token endpoint ├── services/auth/tokens.py # JWT token creation └── services/auth/init.py # set_auth_cookies function
Frontend: ├── src/services/api.ts # Axios CSRF interceptor ├── src/contexts/AuthContext.tsx # Auth state management └── src/pages/AuthPage.tsx # Login/OAuth UI
Django CSRF Settings
config/settings.py - key settings
CSRF_COOKIE_NAME = 'csrftoken' CSRF_HEADER_NAME = 'HTTP_X_CSRFTOKEN' CSRF_COOKIE_HTTPONLY = False # Must be False for JS to read CSRF_COOKIE_SAMESITE = 'Lax' CSRF_TRUSTED_ORIGINS = [ 'http://localhost:3000', 'http://localhost:8000', ]
Views Exempt from CSRF
Some views use @csrf_exempt (check if issue is with exempt view):
grep -r "csrf_exempt" core/
Testing Authentication
Login and get tokens
curl -X POST http://localhost:8000/api/v1/auth/login/
-H "Content-Type: application/json"
-c cookies.txt
-d '{"email":"test@example.com","password":"password"}'
Use tokens for authenticated request
curl http://localhost:8000/api/v1/users/me/
-b cookies.txt