temproary docs uplaoded
This commit is contained in:
255
v2/Live Docs on Server/igny8-app-docs/00-SYSTEM/AUTH-FLOWS.md
Normal file
255
v2/Live Docs on Server/igny8-app-docs/00-SYSTEM/AUTH-FLOWS.md
Normal file
@@ -0,0 +1,255 @@
|
||||
# Authentication & Authorization
|
||||
|
||||
**Last Verified:** January 20, 2026
|
||||
**Version:** 1.8.4
|
||||
**Backend Path:** `backend/igny8_core/auth/`
|
||||
**Frontend Path:** `frontend/src/store/authStore.ts`
|
||||
|
||||
---
|
||||
|
||||
## Quick Reference
|
||||
|
||||
| What | File | Key Functions |
|
||||
|------|------|---------------|
|
||||
| User Model | `auth/models.py` | `User`, `Account`, `Plan` |
|
||||
| Auth Views | `auth/views.py` | `LoginView`, `RegisterView`, `RefreshTokenView` |
|
||||
| Middleware | `auth/middleware.py` | `AccountContextMiddleware` |
|
||||
| JWT Auth | `api/authentication.py` | `JWTAuthentication`, `CookieJWTAuthentication` |
|
||||
| API Key Auth | `api/authentication.py` | `APIKeyAuthentication` |
|
||||
| Frontend Store | `store/authStore.ts` | `useAuthStore` |
|
||||
|
||||
---
|
||||
|
||||
## Authentication Methods
|
||||
|
||||
### 1. JWT Token Authentication (Primary)
|
||||
|
||||
**Flow:**
|
||||
1. User logs in via `/api/v1/auth/login/`
|
||||
2. Backend returns `access_token` (15 min) + `refresh_token` (7 days)
|
||||
3. Frontend stores tokens in localStorage and Zustand store
|
||||
4. All API requests include `Authorization: Bearer <access_token>`
|
||||
5. Token refresh via `/api/v1/auth/token/refresh/`
|
||||
|
||||
**Token Payload:**
|
||||
```json
|
||||
{
|
||||
"user_id": 123,
|
||||
"account_id": 456,
|
||||
"email": "user@example.com",
|
||||
"exp": 1735123456,
|
||||
"iat": 1735122456
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Session Authentication (Admin/Fallback)
|
||||
|
||||
- Used by Django Admin interface
|
||||
- Cookie-based session with CSRF protection
|
||||
- Redis-backed sessions (prevents user swapping bug)
|
||||
|
||||
### 3. API Key Authentication (WordPress Bridge)
|
||||
|
||||
**Flow:**
|
||||
1. Account generates API key in settings
|
||||
2. WordPress plugin uses `Authorization: ApiKey <key>`
|
||||
3. Backend validates key, sets `request.account` and `request.site`
|
||||
|
||||
**Use Cases:**
|
||||
- WordPress content sync
|
||||
- External integrations
|
||||
- Headless CMS connections
|
||||
|
||||
---
|
||||
|
||||
## API Endpoints
|
||||
|
||||
| Method | Path | Handler | Purpose |
|
||||
|--------|------|---------|---------|
|
||||
| POST | `/api/v1/auth/register/` | `RegisterView` | Create new user + account |
|
||||
| POST | `/api/v1/auth/login/` | `LoginView` | Authenticate, return tokens |
|
||||
| POST | `/api/v1/auth/logout/` | `LogoutView` | Invalidate tokens |
|
||||
| POST | `/api/v1/auth/token/refresh/` | `RefreshTokenView` | Refresh access token |
|
||||
| POST | `/api/v1/auth/password/change/` | `ChangePasswordView` | Change password |
|
||||
| POST | `/api/v1/auth/password/reset/` | `RequestPasswordResetView` | Request reset email |
|
||||
| POST | `/api/v1/auth/password/reset/confirm/` | `ResetPasswordView` | Confirm reset with token |
|
||||
|
||||
---
|
||||
|
||||
## User Roles
|
||||
|
||||
| Role | Code | Permissions |
|
||||
|------|------|-------------|
|
||||
| **Developer** | `developer` | Full access across ALL accounts (superuser) |
|
||||
| **Owner** | `owner` | Full access to own account (account creator) |
|
||||
| **Admin** | `admin` | Full access to own account, billing, team management |
|
||||
| **Editor** | `editor` | Content creation and editing only |
|
||||
| **Viewer** | `viewer` | Read-only access to content |
|
||||
| **System Bot** | `system_bot` | System automation (internal) |
|
||||
|
||||
**Role Hierarchy:**
|
||||
```
|
||||
developer > owner > admin > editor > viewer
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Middleware: AccountContextMiddleware
|
||||
|
||||
**File:** `auth/middleware.py`
|
||||
|
||||
**Purpose:** Injects `request.account` on every request
|
||||
|
||||
**Flow:**
|
||||
1. Check for JWT token → extract account_id
|
||||
2. Check for session → get account from session
|
||||
3. Check for API key → get account from key
|
||||
4. Validate account exists and is active
|
||||
5. Validate plan exists and is active
|
||||
6. Set `request.account`, `request.user`
|
||||
|
||||
**Error Responses:**
|
||||
- No account: 403 with JSON error
|
||||
- Inactive plan: 402 with JSON error
|
||||
|
||||
---
|
||||
|
||||
## Frontend Auth Store
|
||||
|
||||
**File:** `store/authStore.ts`
|
||||
|
||||
**State:**
|
||||
```typescript
|
||||
{
|
||||
user: User | null;
|
||||
token: string | null;
|
||||
refreshToken: string | null;
|
||||
isAuthenticated: boolean;
|
||||
}
|
||||
```
|
||||
|
||||
**Actions:**
|
||||
- `login(email, password)` - Authenticate and store tokens
|
||||
- `register(data)` - Create account and store tokens
|
||||
- `logout()` - Clear tokens and reset stores
|
||||
- `refreshToken()` - Refresh access token
|
||||
- `checkAuth()` - Verify current auth state
|
||||
|
||||
**Critical Implementation:**
|
||||
```typescript
|
||||
// Tokens are written synchronously to localStorage
|
||||
// This prevents race conditions where API calls happen before persist
|
||||
localStorage.setItem('auth-storage', JSON.stringify(authState));
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Session Security (Redis-Backed)
|
||||
|
||||
**Problem Solved:** User swapping / random logout issues
|
||||
|
||||
**Implementation:**
|
||||
```python
|
||||
# settings.py
|
||||
SESSION_ENGINE = 'django.contrib.sessions.backends.cache'
|
||||
SESSION_CACHE_ALIAS = 'default' # Redis
|
||||
|
||||
# auth/backends.py
|
||||
class NoCacheModelBackend(ModelBackend):
|
||||
"""Authentication backend without user caching"""
|
||||
pass
|
||||
```
|
||||
|
||||
**Session Integrity:**
|
||||
- Stores `account_id` and `user_id` in session
|
||||
- Validates on every request
|
||||
- Prevents cross-request contamination
|
||||
|
||||
---
|
||||
|
||||
## API Key Management
|
||||
|
||||
**Model:** `APIKey` in `auth/models.py`
|
||||
|
||||
| Field | Type | Purpose |
|
||||
|-------|------|---------|
|
||||
| key | CharField | Hashed API key |
|
||||
| account | ForeignKey | Owner account |
|
||||
| site | ForeignKey | Optional: specific site |
|
||||
| name | CharField | Key name/description |
|
||||
| is_active | Boolean | Enable/disable |
|
||||
| created_at | DateTime | Creation time |
|
||||
| last_used_at | DateTime | Last usage time |
|
||||
|
||||
**Generation:**
|
||||
- 32-character random key
|
||||
- Stored hashed (SHA-256)
|
||||
- Shown once on creation
|
||||
|
||||
---
|
||||
|
||||
## Permission Checking
|
||||
|
||||
**In ViewSets:**
|
||||
```python
|
||||
class MyViewSet(AccountModelViewSet):
|
||||
permission_classes = [IsAuthenticated]
|
||||
|
||||
def get_queryset(self):
|
||||
# Automatically filtered by request.account
|
||||
return super().get_queryset()
|
||||
```
|
||||
|
||||
**Role Checks:**
|
||||
```python
|
||||
if request.user.is_admin_or_developer:
|
||||
# Admin/developer access
|
||||
pass
|
||||
elif request.user.role == 'editor':
|
||||
# Editor access
|
||||
pass
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Logout Flow
|
||||
|
||||
**Backend:**
|
||||
1. Blacklist refresh token (if using token blacklist)
|
||||
2. Clear session
|
||||
|
||||
**Frontend (Critical):**
|
||||
```typescript
|
||||
logout: () => {
|
||||
// NEVER use localStorage.clear() - breaks Zustand persist
|
||||
const authKeys = ['auth-storage', 'site-storage', 'sector-storage', 'billing-storage'];
|
||||
authKeys.forEach(key => localStorage.removeItem(key));
|
||||
|
||||
// Reset dependent stores
|
||||
useSiteStore.setState({ activeSite: null });
|
||||
useSectorStore.setState({ activeSector: null, sectors: [] });
|
||||
|
||||
set({ user: null, token: null, isAuthenticated: false });
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Common Issues
|
||||
|
||||
| Issue | Cause | Fix |
|
||||
|-------|-------|-----|
|
||||
| 403 after login | Tokens not persisted before API call | Write to localStorage synchronously |
|
||||
| User swapping | DB-backed sessions with user caching | Redis sessions + NoCacheModelBackend |
|
||||
| Token refresh loop | Refresh token expired | Redirect to login |
|
||||
| API key not working | Missing site scope | Check API key has correct site assigned |
|
||||
|
||||
---
|
||||
|
||||
## Planned Changes
|
||||
|
||||
| Feature | Status | Description |
|
||||
|---------|--------|-------------|
|
||||
| Token blacklist | 🔜 Planned | Proper refresh token invalidation |
|
||||
| 2FA | 🔜 Planned | Two-factor authentication |
|
||||
| SSO | 🔜 Planned | Google/GitHub OAuth |
|
||||
Reference in New Issue
Block a user