Saltar al contenido principal

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/loginPOST
/dj-rest-auth/logout//_allauth/browser/v1/auth/sessionDELETE
/dj-rest-auth/registration//_allauth/browser/v1/auth/signupPOST
/dj-rest-auth/user//api/users/me/ (unchanged)GET
/dj-rest-auth/password/reset//_allauth/browser/v1/auth/password/requestPOST
/dj-rest-auth/password/reset/confirm//_allauth/browser/v1/auth/password/resetPOST
/dj-rest-auth/password/change//_allauth/browser/v1/account/password/changePOST

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 csrftoken cookie
  • Include X-CSRFToken header 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:

  1. Replace browser with app in all URLs
  2. Store meta.session_token from login response
  3. Include X-Session-Token header in all subsequent requests
  4. 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:

  1. Login with valid credentials
  2. Login with invalid credentials (error handling)
  3. Logout
  4. User registration
  5. Password reset request
  6. Password reset confirmation
  7. Session persistence after page refresh
  8. API calls after authentication

Resources