Authentication
APEX uses two credential families. Which one you use depends on whether you are making runtime product calls (queries, sends, renders) or control-plane calls (provisioning tenants).
Both are issued by your Reisiger platform operator during onboarding — there is no self-service sign-up. Credentials are delivered as a secure bundle; never commit them to source control.
1. Tenant API key — runtime product calls
A platform API key issued per tenant through Forge:
- Format:
apex_live_…(production-class) orapex_test_…(test-class), a long opaque token. - Presentation:
Authorization: Bearer <key>on requests to product APIs. - Scope: the key is bound to your tenant. Which products and operations it may touch is dictated by your tenant's platform configuration — a valid key is still rejected by a product your tenant is not entitled to.
- Issuance & rotation: keys are created, revoked, and rotated in the Forge portal (
/api/tenants/{id}/api-keys) by your operator or your tenant administrators. Rotate on schedule and immediately on suspected exposure; the key value is shown once at creation.
2. Machine-to-machine token — OAuth2 client-credentials
For services that authenticate with the platform identity provider, and for control-plane operations (tenant provisioning, configuration integrations):
- Grant: OAuth2
client_credentialsagainst the token endpoint included in your credential bundle. - Request:
``` POST {token_url} Content-Type: application/x-www-form-urlencoded
grant_type=client_credentials&client_id={client_id}&client_secret={client_secret}&scope={scopes} ```
- Scopes: tenant-namespaced actions in the form
apex/{tenant}.{action}— e.g.apex/your-tenant.read,apex/your-tenant.ingest. Your bundle lists the scopes your tenant was provisioned with. Provisioning integrations additionally useforge/…scopes (e.g.forge/tenant.write). - Lifetime: access tokens are valid for 60 minutes; there is no refresh token. Cache the token and mint a new one shortly before expiry.
- Presentation:
Authorization: Bearer <access_token>. - Registration matters: possession of a client id and secret is not sufficient — clients must be registered with the platform before tokens are issued. If token requests are denied, contact your operator; do not retry in a loop.
Minting a token
PowerShell:
$body = @{
grant_type = 'client_credentials'
client_id = $env:APEX_CLIENT_ID
client_secret = $env:APEX_CLIENT_SECRET
scope = 'apex/your-tenant.read apex/your-tenant.write'
}
$token = (Invoke-RestMethod -Method Post -Uri $env:APEX_TOKEN_URL -Body $body).access_token
curl:
curl -s -X POST "$APEX_TOKEN_URL" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials&client_id=$APEX_CLIENT_ID&client_secret=$APEX_CLIENT_SECRET&scope=apex/your-tenant.read"
Python:
import os, requests
resp = requests.post(os.environ["APEX_TOKEN_URL"], data={
"grant_type": "client_credentials",
"client_id": os.environ["APEX_CLIENT_ID"],
"client_secret": os.environ["APEX_CLIENT_SECRET"],
"scope": "apex/your-tenant.read apex/your-tenant.query",
})
resp.raise_for_status()
token = resp.json()["access_token"] # cache; refresh before the 60-minute expiry
Which products accept which credential
| Product | Machine-to-machine token | Tenant API key | Notes |
|---|---|---|---|
| Zenith | Yes | Operator-enabled | Tenant in the URL path must match the credential's tenant |
| Echo | Yes | Operator-enabled | Per-tenant authentication strategy is configurable (token-only, key-only, or either) |
| Prism | Yes | Operator-enabled | Tenant from request body or inferred from the credential |
| Vector | No | Yes (primary) | Bearer value is the tenant API key itself, centrally verified; tenant carried as tenant_id query parameter |
| Document Operations | Yes | Yes | Tenant via X-Tenant-ID header |
| Forge portal | Provisioning only (forge/… scopes) |
Issued here, used at other products | Portal browsing uses operator sign-in sessions |
| Forge support service | No | No | Separate support-service token issued by your operator (Preview) |
| Forge LLM gateway | — | Yes (scope llm:invoke) |
Planned — contract pinned, not yet served |
| Pulse | Preview | Preview | Bearer required; credential verification is hardening — server-side, trusted callers only |
| Quantum | Preview | Preview | Authentication hardening in progress; local/preview use only |
Handling rules
- Server-side only. APEX credentials live in your backend environment (the backend-for-frontend pattern). They must never reach a browser, mobile client, or client-side bundle.
- One credential set per environment. Test-class keys against development; production-class keys against production. Never share credentials across environments.
- Your users are not APEX principals. End users authenticate with your platform (your identity provider). Their identity terminates at your backend; APEX sees your tenant credential. An audit header for acting-user attribution (
X-On-Behalf-Of) is Planned. - Expect 401 vs 403 to mean different things.
401— credential missing, malformed, or expired (mint a fresh token / check the key).403— credential valid but not permitted (tenant mismatch, entitlement, or tenant not configured). Do not retry a403unchanged. - Rotate without downtime. Create the replacement key, deploy it, then revoke the old one.