Frontend Authentication Migration Guide
This document describes the changes needed in the Vue.js frontend to migrate from dj-rest-auth to django-allauth headless module.
Overview
The backend has been migrated from dj-rest-auth to django-allauth's headless module. This requires updating all authentication-related API calls in the frontend.
Endpoint Changes
Authentication Endpoints
| Old Endpoint (dj-rest-auth) | New Endpoint (allauth headless) | Method |
|---|---|---|
/dj-rest-auth/login/ | /_allauth/browser/v1/auth/login | POST |
/dj-rest-auth/logout/ | /_allauth/browser/v1/auth/session | DELETE |
/dj-rest-auth/registration/ | /_allauth/browser/v1/auth/signup | POST |
/dj-rest-auth/user/ | /api/users/me/ (unchanged) | GET |
/dj-rest-auth/password/reset/ | /_allauth/browser/v1/auth/password/request | POST |
/dj-rest-auth/password/reset/confirm/ | /_allauth/browser/v1/auth/password/reset | POST |
/dj-rest-auth/password/change/ | /_allauth/browser/v1/account/password/change | POST |
For Mobile Apps (X-Session-Token)
Replace browser with app in the URLs:
/_allauth/app/v1/auth/login/_allauth/app/v1/auth/session- etc.
Request/Response Format Changes
Login
Old (dj-rest-auth):
// Request
POST /dj-rest-auth/login/
{
"username": "user",
"password": "pass"
}
// Response
{
"key": "abc123..." // Auth token
}
New (allauth headless - Browser):
// Request
POST /_allauth/browser/v1/auth/login
{
"username": "user",
"password": "pass"
}
// Response (session cookie is set automatically)
{
"status": 200,
"data": {
"user": {
"id": 1,
"display": "username",
"email": "user@example.com",
"username": "username"
}
},
"meta": {
"is_authenticated": true
}
}
New (allauth headless - App):
// Request
POST /_allauth/app/v1/auth/login
{
"username": "user",
"password": "pass"
}
// Response
{
"status": 200,
"data": {
"user": { ... }
},
"meta": {
"is_authenticated": true,
"session_token": "abc123..." // Use this for subsequent requests
}
}
// Subsequent requests must include:
// Header: X-Session-Token: abc123...
Logout
Old:
POST /dj-rest-auth/logout/
New:
DELETE /_allauth/browser/v1/auth/session
Registration (Signup)
Old:
POST /dj-rest-auth/registration/
{
"username": "newuser",
"email": "new@example.com",
"password1": "password",
"password2": "password"
}
New:
POST /_allauth/browser/v1/auth/signup
{
"username": "newuser",
"email": "new@example.com",
"password": "password"
}
Password Reset Request
Old:
POST /dj-rest-auth/password/reset/
{
"email": "user@example.com"
}
New:
POST /_allauth/browser/v1/auth/password/request
{
"email": "user@example.com"
}
Password Reset Confirm
Old:
POST /dj-rest-auth/password/reset/confirm/
{
"uid": "...",
"token": "...",
"new_password1": "newpass",
"new_password2": "newpass"
}
New:
POST /_allauth/browser/v1/auth/password/reset
Headers: X-Password-Reset-Key: {key}
{
"password": "newpass"
}
The key is extracted from the password reset URL: /reset/{key}/
Check Authentication Status
New (use this instead of checking token):
GET /_allauth/browser/v1/auth/session
// Response when authenticated
{
"status": 200,
"data": {
"user": { ... }
},
"meta": {
"is_authenticated": true
}
}
// Response when not authenticated
{
"status": 401,
"meta": {
"is_authenticated": false
}
}
CSRF Token Handling
For browser clients, CSRF tokens work the same way:
- Read CSRF token from
csrftokencookie - Include
X-CSRFTokenheader in POST/PUT/DELETE requests
Error Response Format
Old (dj-rest-auth):
{
"non_field_errors": ["Unable to log in with provided credentials."]
}
New (allauth headless):
{
"status": 400,
"errors": [
{
"code": "invalid_credentials",
"message": "The credentials you provided are not correct."
}
]
}
Example: Updated UserInfoStore.js
// stores/UserInfoStore.js
const API_BASE = '/_allauth/browser/v1';
// Login
async function login(username, password) {
const response = await fetch(`${API_BASE}/auth/login`, {
method: 'POST',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': getCSRFToken(),
},
body: JSON.stringify({ username, password }),
});
const data = await response.json();
if (data.status === 200 && data.meta.is_authenticated) {
// Login successful - session cookie is set automatically
await syncUser();
return true;
}
// Handle errors
throw new Error(data.errors?.[0]?.message || 'Login failed');
}
// Logout
async function logout() {
await fetch(`${API_BASE}/auth/session`, {
method: 'DELETE',
credentials: 'include',
headers: {
'X-CSRFToken': getCSRFToken(),
},
});
}
// Check session
async function checkSession() {
const response = await fetch(`${API_BASE}/auth/session`, {
credentials: 'include',
});
const data = await response.json();
return data.meta?.is_authenticated || false;
}
// Registration
async function register(username, email, password) {
const response = await fetch(`${API_BASE}/auth/signup`, {
method: 'POST',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': getCSRFToken(),
},
body: JSON.stringify({ username, email, password }),
});
const data = await response.json();
if (data.status === 200) {
await syncUser();
return true;
}
throw new Error(data.errors?.[0]?.message || 'Registration failed');
}
// Request password reset
async function requestPasswordReset(email) {
const response = await fetch(`${API_BASE}/auth/password/request`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': getCSRFToken(),
},
body: JSON.stringify({ email }),
});
return response.ok;
}
// Confirm password reset
async function resetPassword(key, newPassword) {
const response = await fetch(`${API_BASE}/auth/password/reset`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': getCSRFToken(),
'X-Password-Reset-Key': key,
},
body: JSON.stringify({ password: newPassword }),
});
return response.ok;
}
// User details (unchanged)
async function syncUser() {
const response = await fetch('/api/users/me/', {
credentials: 'include',
});
const data = await response.json();
// Update user state...
}
Vite Proxy Configuration Update
Update vite.config.js:
export default defineConfig({
server: {
proxy: {
'/api': {
target: 'http://localhost:8000',
changeOrigin: true,
},
'/_allauth': {
target: 'http://localhost:8000',
changeOrigin: true,
},
// Remove /dj-rest-auth proxy
},
},
});
Nginx Configuration Update (Production)
Update nginx.conf:
location /_allauth/ {
proxy_pass http://django:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
# Remove /dj-rest-auth location block
API Documentation
The headless API documentation is available at:
/_allauth/openapi.html- Interactive API docs/_allauth/openapi.yaml- OpenAPI specification/_allauth/openapi.json- OpenAPI specification (JSON)
Flow-Based Authentication
The allauth headless API uses a flow-based authentication system. Check meta.flows in responses to determine what steps are required:
{
"status": 401,
"meta": {
"is_authenticated": false,
"flows": [
{ "id": "login" },
{ "id": "signup" }
]
}
}
If a flow is pending (e.g., email verification), the response will include:
{
"meta": {
"flows": [
{ "id": "verify_email", "is_pending": true }
]
}
}
Mobile App Changes
For mobile apps using the app client type:
- Replace
browserwithappin all URLs - Store
meta.session_tokenfrom login response - Include
X-Session-Tokenheader in all subsequent requests - No CSRF token needed for app clients
// Mobile app example
const sessionToken = await login(username, password);
// Returns session_token from meta.session_token
// Subsequent requests
fetch('/_allauth/app/v1/auth/session', {
headers: {
'X-Session-Token': sessionToken,
},
});
Testing
After implementing changes, test:
- Login with valid credentials
- Login with invalid credentials (error handling)
- Logout
- User registration
- Password reset request
- Password reset confirmation
- Session persistence after page refresh
- API calls after authentication
Resources
- django-allauth Headless Documentation
- OpenAPI Specification (after backend is running):
/_allauth/openapi.html