# 🔌 API Reference ## Base URL ``` http://localhost:3000 (development) https://secure.k2r.ovh (production) ``` ## Authentication Endpoints ### Login Page ``` GET /auth/login-page Returns: HTML login page Status: 200 ``` ### Initiate OIDC Login ``` GET /auth/login Redirects to: Keycloak authorization endpoint Status: 302 (Redirect) ``` ### OAuth Callback ``` POST /auth/callback Parameters: code, state (from Keycloak) Returns: User session created Redirects to: Original page or / Status: 302 ``` ### User Logout ``` GET /auth/logout Effect: Session destroyed Redirects to: Keycloak logout or / Status: 302 ``` ### User Profile ``` GET /auth/profile Returns: { "user": { "sub": "user-id", "name": "User Name", "email": "user@example.com", "isAdmin": false } } Status: 200 Auth: Required ``` ## Service Management Endpoints (Admin Only) ### Create Service ``` POST /api/services Headers: Content-Type: application/json X-CSRF-Token: {token} Body: { "name": "My App", "path": "/myapp", "targetUrl": "http://localhost:8080", "requireAuth": true, "description": "Optional description" } Returns: Created service object Status: 201 Auth: Admin required ``` Example Response: ```json { "id": "uuid-here", "name": "My App", "path": "/myapp", "targetUrl": "http://localhost:8080", "requireAuth": true, "description": "Optional description", "enabled": true, "createdAt": "2025-12-03T10:00:00Z", "updatedAt": "2025-12-03T10:00:00Z" } ``` ### List All Services ``` GET /api/services Returns: Array of service objects Status: 200 Auth: Admin required ``` ### Get Service Details ``` GET /api/services/:id Parameters: :id = Service ID (UUID) Returns: Single service object Status: 200 Auth: Admin required ``` ### Update Service ``` PUT /api/services/:id Headers: Content-Type: application/json X-CSRF-Token: {token} Body: (any field to update) { "name": "Updated Name", "targetUrl": "http://new-target:8080", "requireAuth": false } Returns: Updated service object Status: 200 Auth: Admin required ``` ### Delete Service ``` DELETE /api/services/:id Headers: X-CSRF-Token: {token} Status: 204 (No Content) Auth: Admin required ``` ### Toggle Service (Enable/Disable) ``` PATCH /api/services/:id/toggle Headers: Content-Type: application/json X-CSRF-Token: {token} Body: { "enabled": true } Returns: Updated service object Status: 200 Auth: Admin required ``` ### Get Service Access Logs ``` GET /api/services/:id/logs Query Parameters: ?limit=100 (default: 100) ?offset=0 (default: 0) Returns: { "logs": [ { "id": 1, "service_id": "uuid", "user_id": "keycloak-id", "path": "/myapp/page", "method": "GET", "status_code": 200, "response_time_ms": 45, "ip_address": "127.0.0.1", "timestamp": "2025-12-03T10:00:00Z" } ], "total": 150 } Status: 200 Auth: Admin required ``` ## Dashboard Endpoints (Admin Only) ### Get Statistics ``` GET /dashboard/stats Returns: { "totalServices": 5, "enabledServices": 4, "disabledServices": 1, "recentActivity": [ { "id": 1, "action": "SERVICE_CREATED", "user_id": "admin", "timestamp": "2025-12-03T10:00:00Z" } ] } Status: 200 Auth: Admin required ``` ### Get Audit Logs ``` GET /dashboard/logs Query Parameters: ?limit=100 (default: 100) ?offset=0 (default: 0) Returns: { "logs": [ { "id": 1, "action": "SERVICE_CREATED", "user_id": "admin@example.com", "service_id": "uuid", "ip_address": "127.0.0.1", "details": "{}", "timestamp": "2025-12-03T10:00:00Z" } ], "total": 45 } Status: 200 Auth: Admin required ``` ## Dynamic Proxy Routes ### Access Proxied Service ``` ANY /:path Parameters: :path = Service path (e.g., /myapp, /grafana) Behavior: 1. Check if service exists in database 2. Verify authentication requirements 3. Proxy request to target URL 4. Log access 5. Return response Status: Depends on target service Auth: Checked if service.requireAuth = true ``` Example Flow: ``` GET /grafana/dashboard ↓ Found service: path=/grafana, target=http://localhost:3001 ↓ User authenticated (OIDC session) ↓ Proxy to: GET http://localhost:3001/dashboard ↓ Response returned ↓ Access logged ``` ## Error Responses ### 400 Bad Request ```json { "error": "Missing required fields: name, path, targetUrl" } ``` ### 401 Unauthorized ```json { "error": "Not authenticated" } ``` ### 403 Forbidden ```json { "error": "Admin access required" } ``` ### 404 Not Found ```json { "error": "Service not found" } ``` ### 429 Too Many Requests ```json { "error": "Too many requests, please try again later" } ``` ### 500 Internal Server Error ```json { "error": "Internal server error" } ``` ## HTTP Methods | Method | Use | |--------|-----| | GET | Retrieve data (safe, cacheable) | | POST | Create new resource | | PUT | Update entire resource | | PATCH | Update partial resource | | DELETE | Remove resource | ## Status Codes | Code | Meaning | |------|---------| | 200 | OK - Request successful | | 201 | Created - Resource created | | 204 | No Content - Success, no body | | 302 | Found - Redirect | | 400 | Bad Request - Invalid data | | 401 | Unauthorized - Auth required | | 403 | Forbidden - Access denied | | 404 | Not Found - Resource not found | | 429 | Rate Limited - Too many requests | | 500 | Internal Server Error | | 503 | Service Unavailable - Target down | ## CSRF Protection All state-changing requests (POST, PUT, DELETE, PATCH) require a CSRF token: ``` Header: X-CSRF-Token: {token} ``` The token is automatically included in HTML forms and available in `res.locals.csrfToken`. ## Rate Limiting Default limits: - General: 100 requests per 15 minutes - Auth: 5 attempts per 15 minutes Limits per IP address. ## Authentication Flow 1. User visits `GET /auth/login-page` 2. User clicks login 3. Redirected to `GET /auth/login` 4. Redirected to Keycloak 5. User authenticates on Keycloak 6. Keycloak redirects to `POST /auth/callback` with code 7. Callback validates code with Keycloak 8. Session created 9. Redirected to original page ## Common Usage Examples ### Create and Access a Service ```bash # 1. Create service (admin) curl -X POST http://localhost:3000/api/services \ -H "Content-Type: application/json" \ -H "X-CSRF-Token: YOUR_TOKEN" \ -d '{ "name": "My App", "path": "/myapp", "targetUrl": "http://localhost:8080", "requireAuth": true }' # 2. Access service (authenticated user) curl http://localhost:3000/myapp \ -b "connect.sid=SESSION_COOKIE" # Response proxies to http://localhost:8080/myapp ``` ### List All Services and Their Status ```bash curl http://localhost:3000/api/services \ -b "connect.sid=SESSION_COOKIE" ``` ### View Access Logs for a Service ```bash curl http://localhost:3000/api/services/SERVICE_ID/logs?limit=50 \ -b "connect.sid=SESSION_COOKIE" ``` ### Get Admin Dashboard Stats ```bash curl http://localhost:3000/dashboard/stats \ -b "connect.sid=SESSION_COOKIE" ``` --- **For more information, see README.md and ARCHITECTURE.md**