14 KiB
API Documentation
Complete REST API documentation for the Feuerwehr Dashboard backend.
Table of Contents
- Base URL
- Authentication
- Rate Limiting
- Response Format
- Error Codes
- Health Check
- Authentication Endpoints
- User Endpoints
- 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
Authorization: Bearer <your-jwt-token>
How to Get Tokens
- User authenticates via Authentik OAuth flow
- Frontend receives authorization code
- Frontend sends code to
/api/auth/callback - Backend returns
accessTokenandrefreshToken - Frontend includes
accessTokenin 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
RateLimit-Limit: 100
RateLimit-Remaining: 95
RateLimit-Reset: 1645564800
Rate Limit Exceeded Response
HTTP/1.1 429 Too Many Requests
{
"success": false,
"message": "Too many requests from this IP, please try again later."
}
Response Format
All API responses follow a consistent format:
Success Response
{
"success": true,
"message": "Operation completed successfully",
"data": {
// Response data here
}
}
Error Response
{
"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
// 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:
GET /health HTTP/1.1
Host: api.yourdomain.com
Response:
HTTP/1.1 200 OK
Content-Type: application/json
{
"status": "ok",
"timestamp": "2026-02-23T10:30:00.000Z",
"uptime": 3600.5,
"environment": "production"
}
Response Fields:
status(string): Always "ok" if server is runningtimestamp(string): Current server time in ISO 8601 formatuptime(number): Server uptime in secondsenvironment(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:
{
"code": "authorization_code_from_authentik"
}
Request Example:
POST /api/auth/callback HTTP/1.1
Host: api.yourdomain.com
Content-Type: application/json
{
"code": "abc123def456ghi789"
}
Success Response:
HTTP/1.1 200 OK
Content-Type: application/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/1.1 400 Bad Request
{
"success": false,
"message": "Authorization code is required"
}
HTTP/1.1 403 Forbidden
{
"success": false,
"message": "User account is inactive"
}
HTTP/1.1 500 Internal Server Error
{
"success": false,
"message": "Authentication failed"
}
Response Fields:
accessToken(string): JWT access token for API authenticationrefreshToken(string): JWT refresh token for getting new access tokensuser(object): User profile informationid(number): User database IDemail(string): User email addressname(string): Full namepreferredUsername(string): Preferred usernamegivenName(string): First namefamilyName(string): Last nameprofilePictureUrl(string): URL to profile pictureisActive(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:
{
"refreshToken": "your_refresh_token"
}
Request Example:
POST /api/auth/refresh HTTP/1.1
Host: api.yourdomain.com
Content-Type: application/json
{
"refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
Success Response:
HTTP/1.1 200 OK
Content-Type: application/json
{
"success": true,
"message": "Token refreshed successfully",
"data": {
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
}
Error Responses:
HTTP/1.1 400 Bad Request
{
"success": false,
"message": "Refresh token is required"
}
HTTP/1.1 401 Unauthorized
{
"success": false,
"message": "Invalid refresh token"
}
HTTP/1.1 403 Forbidden
{
"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:
Authorization: Bearer <access-token>
Request Example:
POST /api/auth/logout HTTP/1.1
Host: api.yourdomain.com
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Success Response:
HTTP/1.1 200 OK
Content-Type: application/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:
Authorization: Bearer <access-token>
Request Example:
GET /api/user/me HTTP/1.1
Host: api.yourdomain.com
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Success Response:
HTTP/1.1 200 OK
Content-Type: application/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/1.1 401 Unauthorized
{
"success": false,
"message": "Not authenticated"
}
HTTP/1.1 404 Not Found
{
"success": false,
"message": "User not found"
}
Response Fields:
id(number): User database IDemail(string): User email addressname(string): Full namepreferredUsername(string): Preferred usernamegivenName(string): First namefamilyName(string): Last nameprofilePictureUrl(string): URL to profile pictureisActive(boolean): Whether user account is activelastLoginAt(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:
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
curl -X POST https://api.yourdomain.com/api/auth/callback \
-H "Content-Type: application/json" \
-d '{
"code": "abc123def456"
}'
Response:
{
"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
curl -X GET https://api.yourdomain.com/api/user/me \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
Step 5: Refresh Token When Expired
curl -X POST https://api.yourdomain.com/api/auth/refresh \
-H "Content-Type: application/json" \
-d '{
"refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}'
JavaScript/TypeScript Examples
Using Axios
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
curl -X GET https://api.yourdomain.com/health
Login Callback
curl -X POST https://api.yourdomain.com/api/auth/callback \
-H "Content-Type: application/json" \
-d '{"code":"your_auth_code"}'
Get Current User
curl -X GET https://api.yourdomain.com/api/user/me \
-H "Authorization: Bearer your_access_token"
Refresh Token
curl -X POST https://api.yourdomain.com/api/auth/refresh \
-H "Content-Type: application/json" \
-d '{"refreshToken":"your_refresh_token"}'
Logout
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:
// 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:
- Check this documentation
- Review DEVELOPMENT.md for debugging tips
- Check backend logs for detailed error messages
- Consult ARCHITECTURE.md for system design
- 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