AI AdminPanel Documentation

Authentication API

Use Keycloak OIDC for browser sign-in and panel API keys for automation. These are panel interfaces, separate from Partner Center's OIDC login and pcp_ tokens. The router also retains legacy password/JWT endpoints; do not mistake POST /api/v1/auth/login for the OIDC browser entry point.

OIDC Login Flow

The browser opens GET /api/v1/auth/oidc/login, which redirects to Keycloak using Authorization Code with PKCE. Keycloak returns to GET /api/v1/auth/oidc/callback; the panel exchanges the code, creates a session, sets oidc_session, and redirects to its configured frontend callback. The login handler does not implement a caller-selected redirect query parameter.

EndpointPurpose
GET /api/v1/auth/oidc-configFrontend OIDC configuration
GET /api/v1/auth/oidc/loginBrowser sign-in redirect; 503 if OIDC is unconfigured
GET /api/v1/auth/oidc/callbackProvider callback, not a direct integration call
POST /api/v1/auth/oidc/logoutClears the cookie, attempts session-row deletion, returns redirect_url for the browser to complete Keycloak logout
GET /api/v1/auth/meAuthenticated identity, wrapped in user

Example identity response (synthetic UUID and email):

{
  "user": {
    "id": "10000000-0000-4000-8000-000000000001",
    "email": "admin@example.test",
    "role": "admin"
  }
}

Logout's JSON response alone does not complete the browser's Keycloak logout; the browser follows redirect_url. Do not assume it revokes every other session.

API Keys

Create a key in Settings → Security → API Keys, or call POST /api/v1/api-keys using an already authenticated session or authorized key. The full secret is returned once. Keep it in a secrets manager and revoke it if lost or exposed.

Creating an API Key

curl -X POST https://panel.example.com/api/v1/api-keys \
  -H "Authorization: Bearer ${PANEL_API_KEY}" \
  -H 'Content-Type: application/json' \
  -d '{"name":"inventory","role":"admin","rateLimitRpm":60}'
FieldContract
nameRequired
roleadmin or customer; defaults to the caller's role. A customer cannot mint an admin key.
scopesOptional string array; specialized tenant MCP keys use the MCP surface below.
permissionsDenyOptional array of known permission names
expiresAtOptional future RFC3339 timestamp; omitted means no expiry
rateLimitRpmPositive requests/minute; defaults to 60
isServiceAccount, descriptionOptional metadata

201 Created returns key and metadata, rather than a flat key-record object:

{
  "key": "REDACTED_PANEL_API_KEY",
  "metadata": {
    "name": "inventory",
    "scopes": null,
    "role": "admin",
    "permissionsDeny": null,
    "rateLimitRpm": 60,
    "expiresAt": null,
    "isServiceAccount": false,
    "description": ""
  }
}

The redacted value above is not usable. Customer callers also go through the api_keys capability, organization attachment, and key-count policy; successful customer minting includes orgId in metadata. Admin-created keys remain platform-scoped on this route, including admin-created customer-role keys. A role label alone does not select a tenant.

Using an API Key

curl https://panel.example.com/api/v1/services \
  -H "Authorization: Bearer ${PANEL_API_KEY}"

Choose the role and endpoint for the intended account. Admin service/template routes require admin; customer integrations use the portal API. Permission-deny settings affect routes that enforce those permissions and should not be treated as a universal read-only replacement for an admin key.

Listing API Keys

GET /api/v1/api-keys returns {"keys": [...]} for the authenticated user. Each record includes its UUID id, name, prefix, role, scopes, policy metadata, and timestamps; the full key is not returned. Use that UUID when revoking.

Revoking an API Key

DELETE /api/v1/api-keys/{id} revokes a key owned by the authenticated user and returns 204 No Content. Subsequent authentication with the revoked key fails.

Session Management

Security limitation in v2.12.8: The OIDC session implementation stores access and refresh tokens using repeating-key XOR, without authenticated encryption. Do not rely on this storage format to protect tokens if the session database is exposed. Protect database and backup access; this limitation needs separate product-security remediation.

Session Storage

OIDC sessions are stored in PostgreSQL's identity_sessions table. The browser receives an opaque session identifier in the oidc_session cookie. Its attributes are:

  • HttpOnly — not accessible via JavaScript
  • Secure — only sent over HTTPS
  • SameSite=Lax — limits when browsers send the cookie across sites
  • Path=/; when configured, the cookie domain also covers service subdomains

Session Expiry

The login callback sets the cookie lifetime and server-side session expiry from Keycloak's token response (expires_in). The request middleware checks that stored expiry; it does not extend it on each request. Sign in again when the session expires.

Role-Based Access

The main services and templates routes in this reference belong to the admin-only router group. Customer access is served by /api/v1/portal routes with customer/organization checks. There is no operator or viewer grant for these admin routes. Do not infer tenant isolation from an optional customerId field on an admin request: that field assigns a resource's customer.

MCP Server describes the separate admin and tenant MCP endpoints and the credentials each accepts.