🔒 Add documentation for authentication architecture in Pokedex.Online
This commit is contained in:
322
docs/projects/Pokedex.Online/architecture/authentication.md
Normal file
322
docs/projects/Pokedex.Online/architecture/authentication.md
Normal file
@@ -0,0 +1,322 @@
|
||||
# JWT Authentication Architecture
|
||||
|
||||
**Last Updated:** January 28, 2026
|
||||
**Status:** ✅ Implemented (Step 9 Complete)
|
||||
|
||||
## Overview
|
||||
|
||||
Pokedex.Online uses JWT (JSON Web Token) authentication for admin access to protected features like the Gamemaster Manager. The system provides:
|
||||
|
||||
- Token-based authentication (stateless)
|
||||
- 7-day token expiration with refresh capability
|
||||
- Permission-based access control
|
||||
- Secure localStorage token storage
|
||||
- Automatic Bearer token injection in API requests
|
||||
|
||||
## Architecture Diagram
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ Client (Browser) │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ AdminLogin View │
|
||||
│ ↓ (password) │
|
||||
│ useAuth Composable (login → POST /auth/login) │
|
||||
│ ↓ (token received) │
|
||||
│ localStorage.setItem('auth_token', token) │
|
||||
│ ↓ │
|
||||
│ api-client.setDefaultHeader('Authorization', Bearer ...) │
|
||||
│ ↓ │
|
||||
│ Router Guards (requiresAdmin check) │
|
||||
│ ↓ │
|
||||
│ Protected Routes (GamemasterManager, etc.) │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
↕
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ Server (Express) │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ Auth Routes (server/routes/auth.js) │
|
||||
│ ↓ /auth/login (POST) → verifyPassword │
|
||||
│ ↓ createToken(payload, secret, expiration) │
|
||||
│ ↓ return { token, user, expiresIn } │
|
||||
│ │
|
||||
│ Auth Middleware (server/middleware/auth.js) │
|
||||
│ ↓ authMiddleware() → verifyToken(token) │
|
||||
│ ↓ requirePermission() → check permissions │
|
||||
│ ↓ requireAdmin() → check isAdmin flag │
|
||||
│ │
|
||||
│ Protected Routes │
|
||||
│ ↓ /api/gamemaster/* (with @authMiddleware) │
|
||||
│ ↓ /api/feature-flags/* (with @requirePermission) │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## File Structure
|
||||
|
||||
```
|
||||
Frontend:
|
||||
├── src/
|
||||
│ ├── composables/
|
||||
│ │ └── useAuth.js # Auth state management
|
||||
│ ├── views/
|
||||
│ │ └── AdminLogin.vue # Login page
|
||||
│ ├── router/
|
||||
│ │ └── guards.js # Route protection
|
||||
│ └── utilities/
|
||||
│ └── api-client.js # Enhanced with header mgmt
|
||||
│
|
||||
Backend:
|
||||
├── server/
|
||||
│ ├── utils/
|
||||
│ │ └── jwt-utils.js # Token creation/validation
|
||||
│ ├── middleware/
|
||||
│ │ └── auth.js # Auth middleware
|
||||
│ └── routes/
|
||||
│ └── auth.js # Auth endpoints
|
||||
│
|
||||
Tests:
|
||||
└── tests/unit/
|
||||
├── composables/
|
||||
│ └── useAuth.test.js # Auth composable tests
|
||||
└── views/
|
||||
└── AdminLogin.test.js # Login page tests
|
||||
```
|
||||
|
||||
## API Endpoints
|
||||
|
||||
### POST /auth/login
|
||||
Authenticate with password to receive JWT token.
|
||||
|
||||
**Request:**
|
||||
```json
|
||||
{
|
||||
"password": "admin-password"
|
||||
}
|
||||
```
|
||||
|
||||
**Response (Success):**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"token": "eyJhbGc...",
|
||||
"expiresIn": 604800,
|
||||
"user": {
|
||||
"isAdmin": true,
|
||||
"permissions": ["admin", "gamemaster-edit"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Response (Error):**
|
||||
```json
|
||||
{
|
||||
"error": "Invalid password",
|
||||
"code": "INVALID_PASSWORD"
|
||||
}
|
||||
```
|
||||
|
||||
### POST /auth/verify
|
||||
Verify that a token is valid and get its metadata.
|
||||
|
||||
**Request:**
|
||||
```json
|
||||
{
|
||||
"token": "eyJhbGc..."
|
||||
}
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"valid": true,
|
||||
"user": {
|
||||
"isAdmin": true,
|
||||
"permissions": ["admin", "gamemaster-edit"]
|
||||
},
|
||||
"expiresIn": 3600,
|
||||
"expiresAt": "2026-02-04T17:48:00Z"
|
||||
}
|
||||
```
|
||||
|
||||
### POST /auth/refresh
|
||||
Extend token expiration.
|
||||
|
||||
**Request:**
|
||||
```json
|
||||
{
|
||||
"token": "eyJhbGc..."
|
||||
}
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"token": "eyJhbGc...",
|
||||
"expiresIn": 604800
|
||||
}
|
||||
```
|
||||
|
||||
### GET /auth/user
|
||||
Get current user information (requires valid token).
|
||||
|
||||
**Headers:**
|
||||
```
|
||||
Authorization: Bearer eyJhbGc...
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"user": {
|
||||
"isAdmin": true,
|
||||
"permissions": ["admin", "gamemaster-edit"],
|
||||
"loginTime": "2026-01-28T17:48:00Z"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### POST /auth/logout
|
||||
Logout endpoint (token invalidation happens client-side).
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "Logged out successfully"
|
||||
}
|
||||
```
|
||||
|
||||
## Frontend Integration
|
||||
|
||||
### Using useAuth in Components
|
||||
|
||||
```javascript
|
||||
import { useAuth } from '../composables/useAuth.js';
|
||||
|
||||
export default {
|
||||
setup() {
|
||||
const {
|
||||
login, // login(password)
|
||||
logout, // logout()
|
||||
token, // Reactive token ref
|
||||
user, // Reactive user ref
|
||||
isAuthenticated, // Boolean computed
|
||||
isAdmin, // Boolean computed
|
||||
hasPermission // (perm) => boolean
|
||||
} = useAuth();
|
||||
|
||||
return {
|
||||
login,
|
||||
logout,
|
||||
token,
|
||||
user,
|
||||
isAuthenticated,
|
||||
isAdmin,
|
||||
hasPermission
|
||||
};
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
### Protected Routes
|
||||
|
||||
```javascript
|
||||
import { setupAuthGuards } from './router/guards.js';
|
||||
|
||||
const router = createRouter({ ... });
|
||||
|
||||
setupAuthGuards(router);
|
||||
|
||||
// In route definitions:
|
||||
{
|
||||
path: '/gamemaster-manager',
|
||||
component: GamemasterManager,
|
||||
meta: { requiresAdmin: true } // Protected route
|
||||
}
|
||||
```
|
||||
|
||||
### Setting Up Auth on App Startup
|
||||
|
||||
```javascript
|
||||
import { useAuth } from './composables/useAuth.js';
|
||||
|
||||
export default {
|
||||
async setup() {
|
||||
const { initializeAuth, setupAuthInterceptor } = useAuth();
|
||||
|
||||
// Initialize from localStorage
|
||||
await initializeAuth();
|
||||
|
||||
// Set up automatic token injection
|
||||
setupAuthInterceptor();
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
## Security Considerations
|
||||
|
||||
### ✅ Implemented
|
||||
|
||||
- JWT tokens with HMAC-SHA256 signature
|
||||
- 7-day expiration with refresh capability
|
||||
- Bearer token in Authorization header
|
||||
- Token stored in localStorage (browser-side)
|
||||
- Permission-based access control
|
||||
- Server-side token validation
|
||||
|
||||
### ⚠️ Recommendations
|
||||
|
||||
For production deployment:
|
||||
|
||||
1. **HTTPS Only:** Ensure all authentication over HTTPS
|
||||
2. **Environment Secrets:** Store JWT_SECRET in environment variables
|
||||
3. **Password Hashing:** Use bcrypt for password hashing on server
|
||||
4. **CSRF Protection:** Add CSRF tokens for state-changing requests
|
||||
5. **Rate Limiting:** Implement rate limiting on /auth/login endpoint
|
||||
6. **Secure Cookies:** Consider httpOnly cookies for sensitive tokens
|
||||
7. **Token Rotation:** Implement token rotation for long-lived sessions
|
||||
8. **Logout Blacklist:** Maintain blacklist of revoked tokens (if needed)
|
||||
|
||||
### Current Limitations
|
||||
|
||||
- Passwords stored in environment/config (suitable for single admin scenario)
|
||||
- No multi-user support yet (planned for future)
|
||||
- Tokens valid until expiration (no immediate revocation)
|
||||
- Single secret key (key rotation not yet implemented)
|
||||
|
||||
## Testing
|
||||
|
||||
Tests verify:
|
||||
|
||||
✅ useAuth composable state management
|
||||
✅ AdminLogin component rendering and interaction
|
||||
✅ Login/logout flow
|
||||
✅ Token state in localStorage
|
||||
✅ Permission checking logic
|
||||
✅ Router guard integration
|
||||
|
||||
Run tests:
|
||||
```bash
|
||||
npm test # Watch mode
|
||||
npm test -- AdminLogin # Specific test
|
||||
npm run test:coverage # Coverage report
|
||||
```
|
||||
|
||||
## Next Steps (Phase 3: Steps 10-12)
|
||||
|
||||
- Feature flags system leveraging JWT permissions
|
||||
- Secure backend configuration management
|
||||
- Environment-based flag toggleput
|
||||
- Flag caching and invalidation
|
||||
- Admin panel for flag management
|
||||
|
||||
---
|
||||
|
||||
**Related Documentation:**
|
||||
- [PROGRESS.md](./PROGRESS.md) - Full refactoring progress
|
||||
- [REFACTORING-PLAN.md](./REFACTORING-PLAN.md) - Complete 68-step plan
|
||||
Reference in New Issue
Block a user