Skip to main content
InternalMarkdown

ADR 0024. Nest-Owned Portal Auth (Session API + Social IdP Intents)

Status​

Accepted.

Context​

ADR 0022 chose a Login V2 fork for branded portal sign-in. In the local POC, password and passkey on Login V2 conflicted with player rules (no email forms, PlayerPal ID as username, RP id on player.localhost) and with Session API limits (CreateSession cannot challenge without a user id — zitadel#8899). Social still needs ZITADEL IdP intents; password/passkey need to stay on the portal card. Same-origin Nest under player.localhost is required so the BFF session cookie is first-party after Google return (ADR 0016).

Decision​

  1. Password and passkey for the player portal are owned by Nest against ZITADEL User + Session APIs (POST /auth/password-*, /auth/passkey/*, /auth/factors/*). Login V2 is not the password/passkey UX.
  2. Social (Google / Apple / Facebook) starts from Nest (GET /auth/login or IdP intent → /auth/idp/success). Creates/links an IAM human whose username is pp_plr_…, throwaway password the player never sees, then issues the PlayerPal BFF cookie. No Login V2 email form (ADR 0012).
  3. Store a public-key mirror in webauthn_credentials for discoverable (usernameless) passkey login on the portal RP. Never store private keys or player PII. Identifier-first passkey may still use Session API with userId.
  4. Persist opaque IAM subject as authentication_identities.iam_subject for password sign-in (local lookup first; ListUsers by username only when missing). Keep player_sessions.iam_user_id for signed-in factor add. Neither is player PII; neither appears on /v1/me.
  5. Logout clears the PlayerPal cookie only (no ZITADEL end_session hop that parks on Login V2).
  6. Login V2 fork (ADR 0022) remains available for experiments / future skins; it is not the authoritative player password/passkey path for this POC.

Consequences​

  • Supersedes ADR 0021 item 6 and ADR 0022 items 2 and 5 for the local player portal auth path (see amendment notes on those ADRs).
  • WebAuthn RP is the portal host (WEBAUTHN_RP_DOMAIN / APP_BASE_URL, e.g. player.localhost), not localhost Login V2.
  • Day-to-day docs: docs/authentication.md, infra/README.md.
  • Does not close production IAM vendor choice (§23.2).