# API Documentation Complete REST API documentation for the Feuerwehr Dashboard backend. ## Table of Contents - [Base URL](#base-url) - [Authentication](#authentication) - [Rate Limiting](#rate-limiting) - [Response Format](#response-format) - [Error Codes](#error-codes) - [Health Check](#health-check) - [Authentication Endpoints](#authentication-endpoints) - [User Endpoints](#user-endpoints) - [Request Examples](#request-examples) ## Base URL ### Development ``` http://localhost:3000 ``` ### Production ``` https://api.yourdomain.com ``` ## Authentication The API uses JWT (JSON Web Token) bearer authentication for protected endpoints. ### Authentication Header Format ```http Authorization: Bearer ``` ### How to Get Tokens 1. User authenticates via Authentik OAuth flow 2. Frontend receives authorization code 3. Frontend sends code to `/api/auth/callback` 4. Backend returns `accessToken` and `refreshToken` 5. Frontend includes `accessToken` in subsequent requests ### Token Expiration - **Access Token**: 1 hour (3600 seconds) - **Refresh Token**: 24 hours (86400 seconds) Use `/api/auth/refresh` endpoint to get a new access token before it expires. ## Rate Limiting All `/api/*` endpoints are rate-limited to prevent abuse. ### Limits - **Window**: 15 minutes - **Max Requests**: 100 requests per IP ### Rate Limit Headers ```http RateLimit-Limit: 100 RateLimit-Remaining: 95 RateLimit-Reset: 1645564800 ``` ### Rate Limit Exceeded Response ```http HTTP/1.1 429 Too Many Requests ``` ```json { "success": false, "message": "Too many requests from this IP, please try again later." } ``` ## Response Format All API responses follow a consistent format: ### Success Response ```json { "success": true, "message": "Operation completed successfully", "data": { // Response data here } } ``` ### Error Response ```json { "success": false, "message": "Error description", "error": "Optional error details" } ``` ## Error Codes ### HTTP Status Codes | Code | Meaning | Description | |------|---------|-------------| | 200 | OK | Request successful | | 201 | Created | Resource created successfully | | 400 | Bad Request | Invalid request parameters | | 401 | Unauthorized | Authentication required or failed | | 403 | Forbidden | Authenticated but not authorized | | 404 | Not Found | Resource not found | | 429 | Too Many Requests | Rate limit exceeded | | 500 | Internal Server Error | Server error occurred | ### Common Error Messages ```json // Missing authentication { "success": false, "message": "No token provided" } // Invalid token { "success": false, "message": "Invalid or expired token" } // Inactive user { "success": false, "message": "User account is inactive" } ``` ## Health Check Check if the API is running and healthy. ### GET /health **Authentication**: Not required **Request**: ```http GET /health HTTP/1.1 Host: api.yourdomain.com ``` **Response**: ```http HTTP/1.1 200 OK Content-Type: application/json ``` ```json { "status": "ok", "timestamp": "2026-02-23T10:30:00.000Z", "uptime": 3600.5, "environment": "production" } ``` **Response Fields**: - `status` (string): Always "ok" if server is running - `timestamp` (string): Current server time in ISO 8601 format - `uptime` (number): Server uptime in seconds - `environment` (string): Current environment (development/production) ## Authentication Endpoints ### POST /api/auth/callback Handle OAuth callback and exchange authorization code for tokens. **Authentication**: Not required **Request Body**: ```json { "code": "authorization_code_from_authentik" } ``` **Request Example**: ```http POST /api/auth/callback HTTP/1.1 Host: api.yourdomain.com Content-Type: application/json { "code": "abc123def456ghi789" } ``` **Success Response**: ```http HTTP/1.1 200 OK Content-Type: application/json ``` ```json { "success": true, "message": "Authentication successful", "data": { "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "user": { "id": 1, "email": "john.doe@feuerwehr.de", "name": "John Doe", "preferredUsername": "john.doe", "givenName": "John", "familyName": "Doe", "profilePictureUrl": "https://auth.example.com/media/avatars/john.jpg", "isActive": true } } } ``` **Error Responses**: ```http HTTP/1.1 400 Bad Request ``` ```json { "success": false, "message": "Authorization code is required" } ``` ```http HTTP/1.1 403 Forbidden ``` ```json { "success": false, "message": "User account is inactive" } ``` ```http HTTP/1.1 500 Internal Server Error ``` ```json { "success": false, "message": "Authentication failed" } ``` **Response Fields**: - `accessToken` (string): JWT access token for API authentication - `refreshToken` (string): JWT refresh token for getting new access tokens - `user` (object): User profile information - `id` (number): User database ID - `email` (string): User email address - `name` (string): Full name - `preferredUsername` (string): Preferred username - `givenName` (string): First name - `familyName` (string): Last name - `profilePictureUrl` (string): URL to profile picture - `isActive` (boolean): Whether user account is active --- ### POST /api/auth/refresh Refresh an expired access token using a refresh token. **Authentication**: Not required (uses refresh token) **Request Body**: ```json { "refreshToken": "your_refresh_token" } ``` **Request Example**: ```http POST /api/auth/refresh HTTP/1.1 Host: api.yourdomain.com Content-Type: application/json { "refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." } ``` **Success Response**: ```http HTTP/1.1 200 OK Content-Type: application/json ``` ```json { "success": true, "message": "Token refreshed successfully", "data": { "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." } } ``` **Error Responses**: ```http HTTP/1.1 400 Bad Request ``` ```json { "success": false, "message": "Refresh token is required" } ``` ```http HTTP/1.1 401 Unauthorized ``` ```json { "success": false, "message": "Invalid refresh token" } ``` ```http HTTP/1.1 403 Forbidden ``` ```json { "success": false, "message": "User account is inactive" } ``` **Response Fields**: - `accessToken` (string): New JWT access token --- ### POST /api/auth/logout Logout the current user. **Authentication**: Optional (for logging purposes) **Request Headers**: ```http Authorization: Bearer ``` **Request Example**: ```http POST /api/auth/logout HTTP/1.1 Host: api.yourdomain.com Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... ``` **Success Response**: ```http HTTP/1.1 200 OK Content-Type: application/json ``` ```json { "success": true, "message": "Logout successful" } ``` **Note**: Since this API uses stateless JWT authentication, logout is primarily handled client-side by discarding the tokens. This endpoint exists for audit logging purposes. --- ## User Endpoints ### GET /api/user/me Get the currently authenticated user's profile. **Authentication**: Required **Request Headers**: ```http Authorization: Bearer ``` **Request Example**: ```http GET /api/user/me HTTP/1.1 Host: api.yourdomain.com Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... ``` **Success Response**: ```http HTTP/1.1 200 OK Content-Type: application/json ``` ```json { "success": true, "data": { "id": 1, "email": "john.doe@feuerwehr.de", "name": "John Doe", "preferredUsername": "john.doe", "givenName": "John", "familyName": "Doe", "profilePictureUrl": "https://auth.example.com/media/avatars/john.jpg", "isActive": true, "lastLoginAt": "2026-02-23T10:30:00.000Z", "createdAt": "2026-01-01T12:00:00.000Z" } } ``` **Error Responses**: ```http HTTP/1.1 401 Unauthorized ``` ```json { "success": false, "message": "Not authenticated" } ``` ```http HTTP/1.1 404 Not Found ``` ```json { "success": false, "message": "User not found" } ``` **Response Fields**: - `id` (number): User database ID - `email` (string): User email address - `name` (string): Full name - `preferredUsername` (string): Preferred username - `givenName` (string): First name - `familyName` (string): Last name - `profilePictureUrl` (string): URL to profile picture - `isActive` (boolean): Whether user account is active - `lastLoginAt` (string): Last login timestamp (ISO 8601) - `createdAt` (string): Account creation timestamp (ISO 8601) --- ## Request Examples ### Full Authentication Flow Example #### Step 1: User Clicks Login Frontend redirects to Authentik: ```javascript const authentikAuthUrl = `https://auth.yourdomain.com/application/o/authorize/`; const params = new URLSearchParams({ client_id: 'your_client_id', redirect_uri: 'https://dashboard.yourdomain.com/auth/callback', response_type: 'code', scope: 'openid profile email' }); window.location.href = `${authentikAuthUrl}?${params}`; ``` #### Step 2: Authentik Redirects Back After authentication, Authentik redirects to: ``` https://dashboard.yourdomain.com/auth/callback?code=abc123def456 ``` #### Step 3: Exchange Code for Tokens ```bash curl -X POST https://api.yourdomain.com/api/auth/callback \ -H "Content-Type: application/json" \ -d '{ "code": "abc123def456" }' ``` Response: ```json { "success": true, "message": "Authentication successful", "data": { "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOjEsImVtYWlsIjoiam9obkBleGFtcGxlLmNvbSIsImlhdCI6MTcwODY5MTQwMCwiZXhwIjoxNzA4Njk1MDAwfQ.signature", "refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOjEsImVtYWlsIjoiam9obkBleGFtcGxlLmNvbSIsImlhdCI6MTcwODY5MTQwMCwiZXhwIjoxNzA4Nzc3ODAwfQ.signature", "user": { "id": 1, "email": "john.doe@feuerwehr.de", "name": "John Doe", "preferredUsername": "john.doe", "givenName": "John", "familyName": "Doe", "profilePictureUrl": null, "isActive": true } } } ``` #### Step 4: Access Protected Resources ```bash curl -X GET https://api.yourdomain.com/api/user/me \ -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." ``` #### Step 5: Refresh Token When Expired ```bash curl -X POST https://api.yourdomain.com/api/auth/refresh \ -H "Content-Type: application/json" \ -d '{ "refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." }' ``` ### JavaScript/TypeScript Examples #### Using Axios ```typescript import axios from 'axios'; const API_URL = 'https://api.yourdomain.com'; // Create axios instance with auth const api = axios.create({ baseURL: API_URL, headers: { 'Content-Type': 'application/json', }, }); // Add auth token to requests api.interceptors.request.use((config) => { const token = localStorage.getItem('accessToken'); if (token) { config.headers.Authorization = `Bearer ${token}`; } return config; }); // Handle authentication export const handleCallback = async (code: string) => { const response = await api.post('/api/auth/callback', { code }); const { accessToken, refreshToken, user } = response.data.data; // Store tokens localStorage.setItem('accessToken', accessToken); localStorage.setItem('refreshToken', refreshToken); return user; }; // Refresh token export const refreshAccessToken = async () => { const refreshToken = localStorage.getItem('refreshToken'); const response = await api.post('/api/auth/refresh', { refreshToken }); const { accessToken } = response.data.data; localStorage.setItem('accessToken', accessToken); return accessToken; }; // Get current user export const getCurrentUser = async () => { const response = await api.get('/api/user/me'); return response.data.data; }; // Logout export const logout = async () => { await api.post('/api/auth/logout'); localStorage.removeItem('accessToken'); localStorage.removeItem('refreshToken'); }; ``` ### cURL Examples #### Health Check ```bash curl -X GET https://api.yourdomain.com/health ``` #### Login Callback ```bash curl -X POST https://api.yourdomain.com/api/auth/callback \ -H "Content-Type: application/json" \ -d '{"code":"your_auth_code"}' ``` #### Get Current User ```bash curl -X GET https://api.yourdomain.com/api/user/me \ -H "Authorization: Bearer your_access_token" ``` #### Refresh Token ```bash curl -X POST https://api.yourdomain.com/api/auth/refresh \ -H "Content-Type: application/json" \ -d '{"refreshToken":"your_refresh_token"}' ``` #### Logout ```bash curl -X POST https://api.yourdomain.com/api/auth/logout \ -H "Authorization: Bearer your_access_token" ``` ## Security Considerations ### HTTPS Required in Production Always use HTTPS for API requests in production to protect tokens and sensitive data. ### Token Storage - **Access Token**: Store in memory or sessionStorage (more secure) - **Refresh Token**: Can be stored in httpOnly cookie or localStorage - **Never**: Store tokens in unencrypted cookies or URL parameters ### CORS Configuration The API is configured to only accept requests from allowed origins: ```javascript // Backend CORS configuration cors({ origin: process.env.CORS_ORIGIN, // e.g., https://dashboard.yourdomain.com credentials: true }) ``` Ensure `CORS_ORIGIN` environment variable matches your frontend URL exactly. ### Rate Limiting Respect rate limits to avoid being temporarily blocked. Implement exponential backoff for failed requests. ## Additional Notes ### Timestamps All timestamps are in ISO 8601 format with UTC timezone: ``` 2026-02-23T10:30:00.000Z ``` ### JSON Format All request bodies and responses use JSON format with `Content-Type: application/json`. ### Versioning API versioning is currently not implemented. All endpoints are under `/api/` prefix. Future versions may use: - `/api/v1/` for version 1 - `/api/v2/` for version 2 ## Support For API support: 1. Check this documentation 2. Review [DEVELOPMENT.md](DEVELOPMENT.md) for debugging tips 3. Check backend logs for detailed error messages 4. Consult [ARCHITECTURE.md](ARCHITECTURE.md) for system design 5. Create an issue with detailed request/response information ## Changelog ### Version 1.0.0 (2026-02-23) Initial API release: - OAuth 2.0 authentication with Authentik - JWT-based session management - User profile endpoints - Health check endpoint - Rate limiting - Security headers