Configuration
The product iam/ folder
Section titled “The product iam/ folder”Delivered through meta (or meta.localdir in development):
iam/ providers.yaml # auth method declarations realms.yaml # which entities authenticate, with which providers token.yaml # token expiry + claims access.yaml # named authorization predicates (js/expr) config.yaml # free-form service properties extend/ # entity overlays (new entities, or field augments)providers.yaml — declare methods; see Authentication for the full provider catalog:
providers:- name: password type: challenge- name: magiclink type: magic template: magictemplaterealms.yaml — a realm binds an entity to providers; the default realm authenticates users:
realms:- name: default entity: users providers: [password, magiclink] default: true- name: patient entity: patient # a product-defined entity providers: [password]Feature toggles remove whole surfaces — e.g. realmconfig.enable.agents: false removes /rest/iamagents.
token.yaml — expiry plus static and row-derived claims:
token: expiry: 600m claims: plan: gold claims_from: department: properties.department # dot-path into the identity rowReserved claims (iss, sub, tenant, realm, roles, iat, nbf, exp, type, scope, act) cannot be shadowed.
Tenant extensions are the same file shapes stored as rows in the tenant’s tenant_extensions entity (path: /token.yaml or /extend/<name>.yaml, YAML body) — they merge over the product layer, augment-only.
Boot configuration
Section titled “Boot configuration”Profiles are embedded — iam.svc config list, then config generate <name>: bootstrap-dev, bootstrap-config-server, bootstrap-vault, bootstrap-full, bootstrap-managed-session.
Key top-level (boot-plane) keys — dev port is 5030:
name: iamhost: 127.0.0.1port: "5030"bootstrap: token: one-time-bootstrap-tokenjwks: issuers: iam: "http://127.0.0.1:5030" # MUST be top-level, never under hives:config: url: https://config.internal:7123 # optional remote configvault: url: https://vault.internal:7999 # optional key custodyTenant nodes live in the tenant hive (inline in dev, on config.svc in production). Each served CPET declares its datastore, pool, and product source:
hives: tenant: - path: acme:forge:prod:tenant-a domain: app.acme.com meta: url: https://meta.internal:8080 # or meta.localdir: ./myproduct dbpools: main: dsn: vault:tenant-a-dsn schema: tenant_a # schema-per-tenant isolation session: # optional managed-session posture preset: hipaa max_concurrent_sessions: 1 on_limit: evict_oldest idle_timeout_s: 900 absolute_expiry_s: 43200 - path: acme:forge:prod:superadmin # the product's control plane dbpools: main: dsn: vault:superadmin-dsn schema: superadminSigning keys
Section titled “Signing keys”Three-tier resolution per tenant:
- Vault secret named by tenant property
jwt.signing.key(PKCS#8 Ed25519 PEM). Naming a vault secret without a vault client configured is a loud boot error. - Inline PEM literal in the tenant node (dev only).
- Generated into the tenant’s own
jwt_signing_keytable on first token mint.
External keys are never persisted; key ids are RFC 7638 thumbprints.
Verifying IAM tokens in your own service
Section titled “Verifying IAM tokens in your own service”Any chassis service verifies iam-issued tokens by declaring the issuer:
jwks: issuers: iam: "https://iam.internal:5030"The chassis middleware then validates every Bearer token on protected routes:
- Dual-accept — PASETO v4.public and legacy JWT verify through the same core; keys resolve via the tenant’s JWKS (5-minute cache, stale-key fallback).
- Tenant pin — the token’s
tenantclaim must equal the request’s CPET headers. There is no superadmin exception: a control-plane token on a tenant surface is rejected. - SSRF guard — only issuers listed under
jwks.issuers.*are ever fetched. - Claims land in request context; role helpers (
admin,superadminguards) compose on top. Ascopeclaim confers authority only ontype: "service"tokens — user tokens derive everything from roles.
Non-chassis consumers: fetch GET /.well-known/jwks.json with CPET headers, verify the Ed25519 signature and exp/nbf, then authorize on tenant, realm, and roles.