Auth Flows
Three distinct callers reach the platform, each with its own credential type.
Web console (owner / developer)
- The browser redirects to the Cognito Hosted UI with PKCE.
- The user signs in with a social provider (Google, optionally GitHub / Microsoft Entra) or email/password.
- On first confirmation, a
post-confirmationCognito trigger writes the user’sUSER#<sub>record (approval_status=pendingfor self-signups,approvedfor invited users). - After login, the console’s
AuthGuardcallsGET /v1/tenants/my. A user with no active tenant is redirected to/onboarding. - Submitting the onboarding form (
POST /v1/tenants) provisions the tenant, KMS CMK, Stripe customer/subscription, and free-credit row.
The pre-token-generation trigger injects tenant_id, tenant_role,
and platform_role claims into the JWT from the DynamoDB user record.
Claude Code via agent-runner-auth
The apiKeyHelper integration runs agent-runner-auth token. On first
use it opens a browser PKCE flow, stores the access and refresh tokens in
the OS keychain, and prints the access token to stdout. Subsequent calls
return the cached token (~50ms) or silently refresh it.
The OAuth endpoints are Cognito Hosted UI:
| Endpoint | URL |
|---|---|
| Authorize | https://auth.<domain>/oauth2/authorize |
| Token | https://auth.<domain>/oauth2/token |
| Revoke | https://auth.<domain>/oauth2/revoke |
| UserInfo | https://auth.<domain>/oauth2/userinfo |
Service accounts (CI / Claude Desktop)
Generate an API key (ar_live_...) from the console and pass it as the
x-api-key header. The proxy verifies it via bcrypt comparison against
the stored hash, then loads tenant_id and limits from the key record.
Proxy authentication invariants
- The JWKS cache TTL is 1 hour. On JWKS fetch failure the proxy fails over to the DynamoDB key path — it never serves unauthenticated requests.
- The DynamoDB tenant cache TTL is 60 seconds. A cold Lambda always reads DynamoDB; a warm Lambda may use the in-memory cache. Cache invalidation is not supported — config changes propagate in ≤60s.
- The credential’s
tenant_idmust match the tenant resolved from the Host header, or the request is rejected with 403.
Last updated on