🔒 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