proxy-oidcv2/API-REFERENCE.md
2025-12-03 21:34:44 +01:00

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

  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

# 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