user-engine/docs/configuration.md

134 lines
5.6 KiB
Markdown
Raw Normal View History

# Configuration Boundaries
## Standalone Mode
Standalone mode is for local development, tests, prototypes, and small
single-service deployments.
Expected characteristics:
- local configuration file or environment variables;
- local database or file-backed persistence during early development;
- fixture or local identity claims adapter;
- deterministic authorization test adapter;
- no password, MFA, or token issuance responsibility inside user-engine.
## Platform Mode
Platform mode is for a NetKingdom-aligned shared service deployment.
Expected characteristics:
- verified IAM Profile claims arrive from an identity layer;
- authorization decisions are requested through the authorization check port;
- runtime secrets are delivered through a scoped secret provider;
- audit records and outbox events are correlated with platform sinks;
- tenant and application bindings are explicit.
## Secret Names
The code should refer to logical secret names, not platform paths. Concrete
secret lookup is owned by the active `SecretProvider` adapter.
Initial logical names:
- `database.url`
- `event.signing_key`
- `webhook.shared_secret`
## Production Guardrails
- Local issuers must be rejected by production adapters.
- Sensitive writes must fail closed when authorization is unavailable.
- Claims enrichment must be optional and must not make user-engine a token
issuer.
## Portal integration settings
The production portal requires its existing database, OIDC, proxy-marker, and
identity-provisioning settings. Platform tenant creation is enabled only when
both of these settings are present:
- `USER_ENGINE_TENANT_MANAGEMENT_URL` — tenant-authority base URL;
- `USER_ENGINE_TENANT_MANAGEMENT_TOKEN` — workload-scoped bearer token.
The adapter calls `POST /v1/tenants` with correlation and idempotency headers.
The token is never returned in errors, audit records, outbox events, or browser
responses. When the settings are absent, ordinary portal behavior remains
available and platform tenant creation fails closed as unavailable.
Public registration is off unless `USER_ENGINE_PUBLIC_REGISTRATION=true`.
Enabling it also requires the verification adapter and allow-lists:
- `USER_ENGINE_REGISTRATION_VERIFICATION_URL`
- `USER_ENGINE_REGISTRATION_VERIFICATION_TOKEN`
- `USER_ENGINE_REGISTRATION_CLIENTS`
- `USER_ENGINE_REGISTRATION_TENANTS`
- `USER_ENGINE_REGISTRATION_PASSWORD_SETUP_ORIGINS`
- `USER_ENGINE_MAIL_URL` and `USER_ENGINE_MAIL_TOKEN` when verification
mail is delivered through the outbox
The service fails closed when those settings are absent. Do not add a
placeholder or reused credential to turn the flag on.
`USER_ENGINE_MAIL_CLIENT_BINDINGS` is optional and unset by default. When
unset, invitation mail envelopes keep the legacy shape (no `client_id`). When
set, it is a JSON list of `[tenant_glob, client_id]` pairs (1–128 rows, unique
globs, case-sensitive whole-string `*`/`?` matching), for example
`[["tenant:*-family", "coulomb-social"]]`. Each invitation mail carries the
single matching `client_id`, so email-connect can admit it as a scoped caller
(EMAIL-WP-0008). A tenant with no match, or with matches naming different
clients, is denied as `mail_binding_denied` before either delivery lane is
contacted; the platform event never carries `client_id`. An invalid value stops
startup — it never falls back to the legacy shape.
## Application access readback
Off unless `USER_ENGINE_READBACK_URL` is set. When it is set, these are also
needed:
- `USER_ENGINE_READBACK_URL`: base URL of access-engine's dedicated
`flex-auth-application-readback` pin;
- `USER_ENGINE_READBACK_TOKEN_FILE`: the readback caller token, read on every
call. This is a separate file from `USER_ENGINE_FLEX_AUTH_TOKEN_FILE`. The pin
admits it only under the `application-readback` binding, so it can never act
on `/v1/check`;
- `USER_ENGINE_READBACK_TIMEOUT`: optional, in seconds (default `3`).
The account page (`/onboarding`) then lists each workload bound in all three
records:
- the user-engine application record;
- its binding's `protected_system_id`;
- the readback system's `client_binding`, whose issuer and client id must equal
our OIDC issuer and the binding's `oidc_client_id`.
The rows are rendered as follows. No row is ever inferred as allow:
| access-engine answer | Shown |
| --- | --- |
| `allow` before `expires_at` | Available |
| `deny` | Not available |
| `not_applicable` | Not available: not offered here |
| failure, missing row, or `allow` past or without `expires_at` | Not available: could not be checked |
Answers are read only on account-page views. They are reused per session and
subject for at most 60 seconds, and never past the earliest allow's
`expires_at`. Logout drops them. A failed read is not reused. Contract:
access-engine `docs/application-access-readback.md` (FLEX-DEC-2026-019).
## Authenticator management handoff
`USER_ENGINE_MFA_MANAGEMENT_URL` is optional and empty by default. When set, the
public `/security` help page offers a fixed HTTPS provider-management link. No
credentials, query parameters or fragments are allowed in this URL. The portal
never collects an OTP, reads an OTP seed, or marks a factor enabled from a return
URL. It cannot currently display authoritative enrollment status.
Enable only after verifying provider self-service identity checks, confirmation
before activation, cancellation/recovery, and enrolled-factor enforcement under
KEY-WP-0035. A reachable provider homepage alone is insufficient. Leave unset
while this dependency is unresolved; users get an explicit unavailable state and
help without needing to complete OTP login first. See [account journeys](account-journeys.md).