Skip to content

API Reference

Complete documentation for all Policy Service endpoints.

Base URL

Environment URL
Development http://localhost:8009
Docker Compose http://policy-service:8009
Production Configure via environment

Authentication

All authorization endpoints require a JWT in the Authorization header:

Authorization: Bearer <jwt-token>

The JWT must be issued by the configured Keycloak realm.

Common Headers

Header Required Description
Authorization Yes* Bearer token (*except health endpoints)
Content-Type Yes application/json
X-Request-Id No Correlation ID for tracing
X-Source-Service No Calling service name (for audit)

Common Response Fields

All authorization responses include:

Field Type Description
allowed boolean Whether the action is permitted
reason string Human-readable explanation
request_id string Request identifier for tracing

Authorization Endpoints

POST /authorize

Generic authorization check for any resource type.

Request Body:

{
  "resource": {
    "type": "dataset | pipeline | dt | topic | userdata",
    "id": "resource-identifier",
    "attributes": {
      "access_level": "open | internal | restricted"
    }
  },
  "action": {
    "name": "read | write | admin | ...",
    "context": {}
  },
  "context": {}
}

Response:

{
  "allowed": true,
  "reason": "user has viewer access and client has dataset.query scope",
  "request_id": "550e8400-e29b-41d4-a716-446655440000"
}

Example:

curl -X POST http://localhost:8009/authorize \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "resource": {
      "type": "dataset",
      "id": "ds-energy-consumption",
      "attributes": {"access_level": "internal"}
    },
    "action": {"name": "read"}
  }'

Dataset Endpoints

POST /dataset/access

Check access to a specific dataset.

Request Body:

{
  "dataset_id": "string",
  "access_level": "open | internal | restricted",
  "action": "read | write | admin"
}

Response:

{
  "allowed": true,
  "reason": "user has viewer access and client has dataset.query scope",
  "request_id": "uuid"
}

Access Matrix:

Level Anonymous Viewers Editors Managers Admins
open read read read read read/write
internal read* read/write* read/write* read/write
restricted read/write*

*Requires appropriate client scope (dataset.query or dataset.admin)

POST /dataset/filters

Get row-level filters to apply to dataset queries.

Request Body:

{
  "dataset_id": "string",
  "access_level": "open | internal | restricted"
}

Response:

{
  "allowed": true,
  "filters": [
    {
      "field": "organization_id",
      "operator": "eq",
      "value": "org-123"
    },
    {
      "field": "classification",
      "operator": "in",
      "value": ["public", "internal"]
    }
  ],
  "reason": "filters applied based on user context",
  "request_id": "uuid"
}

Filter Operators:

Operator Description Example
eq Equals field = value
ne Not equals field != value
in In list field IN (values)
gt Greater than field > value
lt Less than field < value

Pipeline Endpoints

POST /pipeline/transition

Validate a pipeline state transition.

Request Body:

{
  "pipeline_id": "string",
  "from_state": "pending | started | running | completed | failed | cancelled",
  "to_state": "pending | started | running | completed | failed | cancelled"
}

Response:

{
  "allowed": true,
  "reason": "valid transition from started to running",
  "request_id": "uuid"
}

Valid Transitions:

pending ──▶ started ──▶ running ──▶ completed
   │           │           │
   │           │           └──▶ failed
   │           │
   │           └──▶ cancelled
   │
   └──▶ cancelled

Digital Twin Endpoints

POST /dt/access

Check access to digital twin operations.

Request Body:

{
  "dt_id": "string",
  "action": "read | write | simulate | admin"
}

Response:

{
  "allowed": true,
  "reason": "user can read dt data",
  "request_id": "uuid"
}

Action Requirements:

Action Users Services
read viewers+ with dt.read dt.read scope
write editors+ with dt.write dt.write scope
simulate managers+ with dt.simulate dt.simulate scope
admin admins with dt.admin dt.admin scope

POST /dt/event

Authorize a digital twin event emission.

Request Body:

{
  "dt_id": "string",
  "event_type": "string",
  "simulation_state": "string | null"
}

Response:

{
  "allowed": true,
  "reason": "service can emit dt events",
  "request_id": "uuid"
}

MQTT Endpoints

Compatible with mosquitto-go-auth HTTP backend.

POST /mqtt/user

Authenticate an MQTT client.

Request:

The JWT should be passed in the Authorization header:

Authorization: Bearer <jwt>

Response:

{
  "ok": true,
  "reason": "authenticated"
}

HTTP Status Codes:

Code Meaning
200 Authentication successful
403 Authentication failed

POST /mqtt/acl

Check topic access for an authenticated client.

Request Body (form-encoded or JSON):

{
  "username": "jwt-token-or-username",
  "topic": "celine/digital-twin/events/pump/123",
  "clientid": "client-id",
  "acc": 1
}

Access Mask (acc):

Value Permission
1 Read
2 Write (Publish)
4 Subscribe
3 Read + Write
5 Read + Subscribe
7 All

Response:

{
  "ok": true,
  "reason": "authorized"
}

POST /mqtt/superuser

Check if a client has superuser (admin) access.

Request Body:

{
  "username": "jwt-token-or-username"
}

Response:

{
  "ok": true,
  "reason": "superuser"
}

User Data Endpoints

POST /userdata/access

Check access to user-owned resources.

Request Body:

{
  "resource_type": "dashboard | profile | settings",
  "resource_id": "string",
  "owner_id": "user-id-who-owns-resource",
  "action": "read | write | delete | share"
}

Response:

{
  "allowed": true,
  "reason": "user accessing own data",
  "request_id": "uuid"
}

Access Rules:

Scenario Allowed
Owner accessing own data
Resource shared with user ✅ (read only)
Resource shared with user's group ✅ (read only)
Admin with userdata.admin scope
Other users

Health Endpoints

GET /health

Liveness check — is the service running?

Response:

{
  "status": "healthy",
  "version": "0.1.0",
  "policies_loaded": true,
  "details": {
    "policy_count": 6
  }
}

GET /ready

Readiness check — is the service ready to accept requests?

Response:

{
  "status": "healthy",
  "version": "0.1.0",
  "policies_loaded": true,
  "details": {
    "policy_count": 6,
    "cache": {
      "hits": 1234,
      "misses": 56
    }
  }
}

POST /reload

Hot-reload policies from disk.

Response:

{
  "status": "success",
  "policy_count": 6
}

Error Responses

400 Bad Request

Invalid request format or unknown resource type.

{
  "detail": "Unknown resource type: invalid"
}

401 Unauthorized

Missing or invalid JWT.

{
  "detail": "Invalid authorization header format"
}

403 Forbidden

Valid JWT but access denied (for MQTT endpoints).

{
  "ok": false,
  "reason": "insufficient privileges"
}

500 Internal Server Error

Policy evaluation failure.

{
  "detail": "Policy evaluation failed: ..."
}

Rate Limiting

Production deployments should implement rate limiting. Recommended limits:

Endpoint Limit
/authorize 1000 req/sec per client
/health 100 req/sec
/reload 1 req/min

OpenAPI Specification

The service exposes an OpenAPI spec at:

GET /openapi.json
GET /docs        # Swagger UI
GET /redoc       # ReDoc UI