Gateway auth, RBAC, and key lifecycle
Use this page to enable gateway key auth and enforce RBAC on proxy and API routes. It also covers gateway key lifecycle endpoints and operational behavior in static and Postgres-backed modes.
Access model
- Requires gateway key authentication on protected routes.
- Maps routes to required permissions (
proxy:write,analytics:read,keys:manage). - Applies role defaults with optional additive custom permissions.
- Strips the gateway auth header before proxy forwarding.
- Exposes gateway key list, create, revoke, and rotate APIs.
- Emits audit logs for auth denies and key lifecycle actions.
Operational fit
- You need machine-to-machine access control for shared gateway deployments.
- You need least-privilege access between proxy traffic and analytics reads.
- You need auditable gateway key lifecycle operations by workspace scope.
Authorization lifecycle
- Middleware resolves required access from route and method.
- Protected routes require the configured gateway key header.
- Middleware authenticates the key and resolves identity
(
org_id,workspace_id, role, key ID). - Middleware enforces required permission for the target route.
- For provider routes, middleware also requires provider credentials
(
AuthorizationorX-API-Key). - Middleware removes the gateway key header before upstream forwarding.
- API handlers apply tenant scope to traces, analytics, and gateway key management.
- If auth is enabled in Postgres mode, active keys refresh in-memory every
30 seconds. If the cache is older than 60 seconds, protected routes fail
closed with
503.
Permission mapping:
/openai/*and/anthropic/*:proxy:writeGET /api/tracesandGET /api/traces/:id:analytics:readGET /api/analytics/*:analytics:readGET/POST/DELETE /api/gateway-keys*:keys:manageGET /api/health: public
Role defaults:
owner,admin:proxy:write,analytics:read,keys:managedeveloper,member:proxy:write,analytics:readviewer:analytics:read- Unknown roles: no implicit permissions
Starter policy config
YAML
auth:
enabled: true
header: X-OngoingAI-Gateway-Key
keys:
- id: team-a-owner-1
token: replace-me-owner
org_id: org-default
workspace_id: workspace-default
role: owner
- id: team-a-viewer-1
token: replace-me-viewer
org_id: org-default
workspace_id: workspace-default
role: viewerIf auth.enabled=true, proxy requests must include both:
- Gateway key header (default:
X-OngoingAI-Gateway-Key) - Provider credential header (
AuthorizationorX-API-Key)
Deployment patterns
- Use static YAML keys for local and single-team deployments.
- Use Postgres-backed config store for key lifecycle APIs in team mode.
- Set a custom gateway auth header with
auth.headerwhen your edge stack reserves default header names. - Add explicit
permissionsto grant exceptions beyond role defaults.
Worked examples
Create a viewer key for analytics-only access
YAML
auth:
enabled: true
header: X-OngoingAI-Gateway-Key
keys:
- id: team-a-dev-1
token: replace-me
org_id: org-default
workspace_id: workspace-default
role: viewer
permissions:
- analytics:readManage keys with lifecycle APIs in Postgres mode
YAML
storage:
driver: postgres
dsn: postgres://USER:PASSWORD@HOST:5432/DB?sslmode=disable
auth:
enabled: true
header: X-OngoingAI-Gateway-KeyBash
curl -X POST "http://localhost:8080/api/gateway-keys" \
-H "X-OngoingAI-Gateway-Key: GATEWAY_KEY_OWNER" \
-H "Content-Type: application/json" \
-d '{"id":"team-a-dev-2","role":"developer","permissions":["proxy:write","analytics:read"]}'The create response includes the key token. Store that token securely.
Verification steps
-
Validate config.
Bashongoingai config validate -
Start the gateway.
Bashongoingai serve -
Check that protected routes reject missing keys.
Bashcurl -i "http://localhost:8080/api/traces?limit=1" -
Check that viewer keys cannot proxy provider requests.
Bashcurl -i "http://localhost:8080/openai/v1/models" \ -H "X-OngoingAI-Gateway-Key: GATEWAY_KEY_VIEWER" \ -H "Authorization: Bearer OPENAI_API_KEY" -
Check that owner keys can read and manage key inventory.
Bashcurl -i "http://localhost:8080/api/gateway-keys" \ -H "X-OngoingAI-Gateway-Key: GATEWAY_KEY_OWNER"
Placeholders:
GATEWAY_KEY_OWNER: Key token withkeys:managepermission.GATEWAY_KEY_VIEWER: Key token withanalytics:readonly.OPENAI_API_KEY: Upstream provider API key.
You should see:
401withmissing or invalid gateway keywhen no key is present.403withgateway key does not have required permissionfor viewer proxy attempts.200from/api/gateway-keyswhen the caller haskeys:manage.
Troubleshooting
Protected routes return 401
- Symptom: Response error is
missing or invalid gateway key. - Cause: Gateway key is missing, invalid, or sent in the wrong header.
- Fix: Send the key in
auth.header(default:X-OngoingAI-Gateway-Key).
Proxy routes return 403 for permission
- Symptom: Response error is
gateway key does not have required permission. - Cause: Key role or explicit permissions do not include
proxy:write. - Fix: Use a key with
proxy:write, or update role/permissions.
Proxy routes return 403 for provider credentials
- Symptom: Response error says provider API key is missing.
- Cause: Gateway key is valid, but no upstream provider credential was sent.
- Fix: Add
AuthorizationorX-API-Keyto proxy requests.
Key create, revoke, or rotate returns 501
- Symptom: Lifecycle endpoint returns
not implemented. - Cause: Static config store does not support key mutations.
- Fix: Use
storage.driver=postgresand setstorage.dsn, then restart.
Protected routes return 503
- Symptom: Response error is
gateway key verification unavailable. - Cause: In Postgres mode, key refresh failed and auth cache became stale.
- Fix: Restore Postgres connectivity and key-store health, then verify refresh logs.