7.0 KiB
7.0 KiB
🔌 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:
{
"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
{
"error": "Missing required fields: name, path, targetUrl"
}
401 Unauthorized
{
"error": "Not authenticated"
}
403 Forbidden
{
"error": "Admin access required"
}
404 Not Found
{
"error": "Service not found"
}
429 Too Many Requests
{
"error": "Too many requests, please try again later"
}
500 Internal Server Error
{
"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
- User visits
GET /auth/login-page - User clicks login
- Redirected to
GET /auth/login - Redirected to Keycloak
- User authenticates on Keycloak
- Keycloak redirects to
POST /auth/callbackwith code - Callback validates code with Keycloak
- Session created
- Redirected to original page
Common Usage Examples
Create and Access a Service
# 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
curl http://localhost:3000/api/services \
-b "connect.sid=SESSION_COOKIE"
View Access Logs for a Service
curl http://localhost:3000/api/services/SERVICE_ID/logs?limit=50 \
-b "connect.sid=SESSION_COOKIE"
Get Admin Dashboard Stats
curl http://localhost:3000/dashboard/stats \
-b "connect.sid=SESSION_COOKIE"
For more information, see README.md and ARCHITECTURE.md