Appearance
Security invariants
These rules are enforced by the Central Auth Gateway. Platform integrations must respect them; bypassing them in the BFF creates security holes even if Central itself remains correct.
Identity and tokens
- The IESF identity service (identity-api) owns credentials, e-mail verification, identity sessions, and OIDC tokens. Each environment is a separate issuer with its own users and signing keys.
- Users are keyed by (issuer, subject). E-mail is never an identity key; the same address in DEV and PROD is two users.
- Platforms never receive identity ID, access, or refresh tokens from Central. The gateway keeps the ID token only encrypted on the gateway session, as
id_token_hintfor logout. - PKCE verifiers and nonces never leave Central (stored hashed / encrypted; not returned on exchange).
- Externally supplied ID tokens are rejected (Bearer tokens carrying
nonceare refused); only the central code exchange path establishes identity for login. - Bearer access tokens are accepted only from active identity environments:
issselects the environment, the signature is checked against that environment's JWKS, and the audience must equalIDENTITY_ACCESS_TOKEN_AUDIENCE. - Tokens and handoff codes must never be logged.
Handoff
- Codes are prefixed
handoff_, stored as SHA-256 only, short-lived (AUTH_HANDOFF_TTL_SECONDS, 30–300s), platform-bound, and atomically single-use. - Exchange requires platform Basic auth with a BFF key (
client_id+ scrypt-verified secret) of an active platform; a backend key gets403. - A code can only be exchanged with a BFF key whose pair has the callback the code was sent to; a code of another platform or callback gives
404. A leaked key of a development pair therefore cannot redeem production logins. - The pending
gatewayTokenis AES-256-GCM encrypted at rest and revealed only after successful exchange.
Gateway session
- Opaque random token; only the hash is stored.
- Cookie: HttpOnly,
SameSite=Lax,Path=/,Securein production; name fromAUTH_SESSION_COOKIE_NAME(defaultiesf_auth_session). - TTL from
AUTH_SESSION_TTL_SECONDS(default 43200). - Inactive / soft-deleted users cannot authenticate a session.
- Permissions are a snapshot taken at login. Removing a role strips the permissions from active sessions immediately; a granted role takes effect at the next login.
POST /v1/auth/logoutrevokes the session and clears the cookie; it is idempotent. Its optionalreturnTois checked against the redirect pairs of the platform whose login created the session and travels through the identity provider only as an AES-GCM encrypted, 1-hourstate;/v1/auth/logged-outnever redirects to an unvalidated URL.- The platform callback carries only the handoff code, no platform
state; platforms protect themselves against login CSRF with their own short-lived "login pending" cookie set before redirecting to start. - Cookie-authenticated writes (including logout) require an allowlisted
Origin: an entry inCORS_ORIGINS, the host of the deployment issuer or of an active identity environment's issuer (the identity UI, which renders central onboarding), or the origin of a redirect pair's return URL on an active platform. Database origins are cached for 60 seconds, so deactivating a platform or an environment revokes its origin within that window. - Because the cookie is
SameSite=Lax, only origins that are same-site with the gateway can send it at all. Allowlisting a cross-site platform origin does not grant it cookie access; those platforms use the BFF handoff instead.
Platform registry
- Redirect pairs (return URL root → callback), the identity environment and onboarding mode come from the server-side registry, not from untrusted query overrides. The matched callback and the environment are snapshotted on the transaction at start.
- Only the deployment (
PROD) identity environment can grant gateway administration permissions; a gateway session from one environment cannot resume a login started in another. - OIDC client secrets of database-managed environments are AES-256-GCM encrypted with
IDENTITY_ENVIRONMENT_SECRET_KEY, bound to their row, write-only through the API and redacted from logs. - A database environment can never reuse the deployment issuer.
- Platforms on a production environment only accept public HTTPS return and callback URLs.
onboardingModeon start is assertion-only.- Active platforms must have at least one return/callback URL pair, a BFF key, and an active identity environment. A login through a pair whose callback has no BFF key is refused at start.
- Client secrets are high-entropy, returned once, stored hashed (scrypt). Each pair has its own BFF key and a platform at most one introspection-only backend key, so a key can be rotated or revoked without touching the others. A rotated secret stays valid for 60 minutes unless revoked;
last_used_atshows which keys are still in use. - Soft deactivation preserves memberships, onboarding values, and audit history.
Authorization
- User IDs are never taken from profile/account request bodies for identity.
- User permissions come only from local
user_roles(platform_admin) and only for PROD users. Machine-token scopes count only when the issuer is PROD; machine tokens are refused on user endpoints. platform_admincan be granted only to PROD users, and the last remaining one cannot be removed.PLATFORM_ADMIN_BOOTSTRAP_EMAILSapplies only to PROD logins with a verified e-mail.- Platform ownership for admin/schema routes is derived from verified token claims/scopes (or
platforms:admin), not from trusting a body/path platform key alone. - Passwords never reach the gateway; they are managed in the identity UI (
accountManagementUrl). - Account deletion suspends the identity user through the identity service API first (which also revokes identity sessions and tokens), then soft-deletes locally and revokes gateway sessions; local profile and audit data remain.
- Gateway → identity-api service calls use short-lived (60 s) HS256 JWTs signed with
IDENTITY_SERVICE_KEYand scoped to one environment and action.
Onboarding integrity
- Completion is always recalculated server-side from active required definitions and current values.
- Resume ignores client completion assertions.
- Historical onboarding values remain when definitions are archived.
- Schema definitions cannot carry arbitrary executable / HTML payloads;
uiConfigis declarative.
Operational
- Application instances are stateless; auth state lives in PostgreSQL.
- Do not connect to or migrate the identity service's database (its
auth_<env>schemas) from this service; use the internal service API. - Generate API clients from
/openapi.json; treat Swagger examples as illustrative and verify against runtime for security-sensitive fields.