Authentication
AI-in-a-Box uses Keycloak OIDC for browser users, optional additional JWT issuers such as egauth, signed downstream principal headers, CapTokens, and service-to-service JWTs for most internal calls.
Browser Login
The frontend uses Authorization Code with PKCE against the aibox-frontend public client.
Issuer: ${PUBLIC_URL}/keycloak/realms/aibox
Client: aibox-frontend
Flow: authorization_code + PKCE
The realm import sets directAccessGrantsEnabled: false; password-grant curl examples are intentionally not the normal path. For scripts, use an access token obtained through an operator-approved client or from an authenticated browser/dev flow.
Trusted Issuers
Gateway auth is configured in deploy/config/gateway/config.yaml.
auth:
enabled: true
jwks_url: http://keycloak:8080/realms/aibox/protocol/openid-connect/certs
issuer: ${PUBLIC_URL}/keycloak/realms/aibox
additional_issuers:
- issuer: ${PUBLIC_URL}/egauth
jwks_url: http://egauth:8010/jwks
audience: aibox-frontend
The gateway validates issuer, signature, and configured audience before deriving identity.
Tenant and User Headers
External callers must not rely on spoofable identity headers. The gateway strips inbound values for:
X-User-IDX-User-EmailX-User-RolesX-Tenant-IDX-Aibox-PrincipalX-Aibox-Turn-IdX-Aibox-Cap-Token
When auth is enabled, the gateway derives:
| Header | Source |
|---|---|
X-User-ID | JWT sub |
X-User-Email | JWT email |
X-User-Roles | JWT realm_access.roles |
X-Tenant-ID | JWT tenant; falls back to sub |
Older docs and examples that mention tenant_id JWT claims or manually supplied tenant headers are stale for gateway traffic. Configure a Keycloak mapper to emit tenant when you need organization-level tenancy.
Roles
Runtime admin checks accept:
| Role | Meaning |
|---|---|
user | Normal application user. |
admin | Legacy broad admin role. Still accepted. |
tenant_admin | Admin for the caller's tenant. |
platform_admin | Cross-tenant platform operator. |
service-account | Realm role used by service clients. |
The current development realm seeds admin, user, and service-account. New deployments should add tenant_admin and platform_admin roles if they need split administration.
Signed Principal Header
After validating a user token, the gateway emits X-Aibox-Principal, an HMAC-signed JSON principal. Python services verify it using AIBOX_PRINCIPAL_KEYS.
Principal fields include:
{
"id": "user-sub",
"tenant_id": "tenant-or-sub",
"email": "alice@example.com",
"roles": ["user"],
"local_iss": "https://ai.example.com/keycloak/realms/aibox",
"local_sub": "user-sub",
"upstream_iss": "https://idp.example.com",
"upstream_sub": "external-id",
"auth_method": "password",
"iat": 1710000000,
"exp": 1710000300
}
For brokered upstream IdPs, configure Keycloak mappers for identity_provider, upstream_iss, upstream_sub, and upstream_preferred_username.
CapTokens and Turn Context
The gateway mints a new turn context for each authenticated request:
| Header | Purpose |
|---|---|
X-Aibox-Turn-Id | Gateway-generated turn identifier. |
X-Aibox-Cap-Token | Short-lived HMAC token bound to principal, tenant, scopes, and turn ID. |
CapTokens are signed with AIBOX_CAPTOKEN_KEYS. They currently grant broad end-user scopes such as agent.invoke, tool.*, memory.*, knowledge.*, and guardrail.*. Finer per-route scoping is a follow-up.
Service-to-Service Auth
Most gateway-to-service calls replace the user's bearer token with a short-lived Keycloak service token. Receiving services validate issuer, audience, client identity, and optional allowed callers.
Relevant variables:
| Variable | Purpose |
|---|---|
INTERNAL_AUTH_CLIENT_ID | Service client ID, for example service-agent-runtime. |
INTERNAL_AUTH_CLIENT_SECRET | Secret for the service client. |
INTERNAL_AUTH_REALM | Keycloak realm, default aibox. |
INTERNAL_AUTH_AUDIENCE | Required audience, default aibox-internal. |
INTERNAL_AUTH_ALLOWED_CLIENTS | Optional comma-separated caller allow-list. |
INTERNAL_AUTH_TOKEN_URL | Optional explicit token endpoint. |
INTERNAL_AUTH_INTROSPECTION_URL | Optional explicit introspection endpoint. |
deploy/scripts/ensure-keycloak-clients.py reconciles the service-* clients and audience mappers.
Inference-router /v1/models and /v1/routes are the notable current exception: the gateway proxies those routes without an internal service token.
SSO Provider Administration
The gateway can mount /v1/admin/sso/idps when these variables are configured:
| Variable | Purpose |
|---|---|
KEYCLOAK_ADMIN_BASE_URL | Internal Keycloak base URL, for example http://keycloak:8080. |
KEYCLOAK_ADMIN_REALM | Realm to manage. |
KEYCLOAK_ADMIN_CLIENT_ID | Admin service-account client. |
KEYCLOAK_ADMIN_CLIENT_SECRET | Admin service-account secret. |
The service account needs appropriate Keycloak realm-management permissions. Use this API to manage upstream OIDC/SAML providers when you do not want operators to use the Keycloak console directly.