docs(api): record passkey login-handler deferral rationale
The passkey login/assertion HTTP handler stays deferred after its design checkpoint; capture the reasoning in the handler header so the decision is durable in the repo rather than only in task notes. - RP boundary (resolved): felis-api is the app-login relying party (panel.*); the WebAuthn security gate lives at the Cloudflare Access edge. Spec §14 ties WebAuthn/posture to admin.* (Access) while panel.* is plain app login, so there is neither a spec-required assertion handler nor a backend step-up consumer for one. - Identifier (blocking): a from-zero login needs a unique, human-typable handle to resolve an account, but users.email is nullable and non-unique and a player's username is their Minecraft uuid. Username-first assertion has nothing to key on; re-link stays the returning-player door. Discoverable (usernameless) credentials are the future enabler; the adapter crypto is already verified so that slice inherits correct crypto.
This commit is contained in:
1 file changed
+29
-7
@@ -19,13 +19,35 @@ import (
|
|||||||
// Scope of the HANDLERS in this file: ENROLLMENT only. Every ceremony here rides on a
|
// Scope of the HANDLERS in this file: ENROLLMENT only. Every ceremony here rides on a
|
||||||
// known principal — the challenge is bound to the caller's user_id and the finish
|
// known principal — the challenge is bound to the caller's user_id and the finish
|
||||||
// verifies against the server-stashed SessionData, never a client-echoed challenge. The
|
// verifies against the server-stashed SessionData, never a client-echoed challenge. The
|
||||||
// login/assertion path (proving a passkey to mint or elevate a session from an
|
// login/assertion path (proving a passkey to mint a session from an UNauthenticated
|
||||||
// UNauthenticated state) has its cryptographic half built and Oracle-verified in the
|
// state) has its cryptographic half built and Oracle-verified in the adapter
|
||||||
// adapter (internal/passkey BeginLogin/FinishLogin, against a virtual authenticator),
|
// (internal/passkey BeginLogin/FinishLogin, against a virtual authenticator) and its
|
||||||
// and its persist-ready output shape is VerifiedAssertion below — but the login HTTP
|
// persist-ready output shape is VerifiedAssertion below — but the login HTTP handler is
|
||||||
// handlers, the session minting, and the panel.* passkey relying-party boundary/tier
|
// a DELIBERATELY deferred slice. Its design checkpoint (task #36) resolved two questions
|
||||||
// decision (see migration 0007) are a deferred slice: this file adds no unauthenticated
|
// and then deferred, for reasons that outlive this comment:
|
||||||
// login route.
|
//
|
||||||
|
// - RP boundary (RESOLVED): felis-api is the app-login relying party (panel.*); the
|
||||||
|
// WebAuthn-as-security-gate lives at the Cloudflare Access EDGE, not here. Spec §14
|
||||||
|
// ties WebAuthn/posture to admin.* (Access), while panel.* is plain app login with
|
||||||
|
// no WebAuthn requirement — so there is neither a spec-required assertion handler
|
||||||
|
// nor a backend step-up consumer for one (the role-switcher step-up UX is frontend).
|
||||||
|
// - Identifier (BLOCKING): a from-zero login needs a unique, human-typable handle to
|
||||||
|
// resolve the account before its passkeys can be offered. users.email is nullable
|
||||||
|
// and NOT unique (0001_init.sql), and a player's users.username IS their Minecraft
|
||||||
|
// uuid (pgrepo.go RedeemPlayerBindCode mints a uuid-derived unique username) —
|
||||||
|
// opaque, never typed into a form. The username-first assertion the non-resident
|
||||||
|
// credentials + user-keyed challenge store support therefore has nothing to key on.
|
||||||
|
//
|
||||||
|
// The system's returning-player door is already re-link (control of the in-game identity
|
||||||
|
// is the root of trust — handlers_onboard.go re-mints a session through the bind-code
|
||||||
|
// flow even after passkey/OTP are bound); passkey and email-OTP are factors on an
|
||||||
|
// ALREADY-authenticated principal here, not from-zero login methods. The real enabler
|
||||||
|
// for a from-zero passkey login is discoverable ("usernameless") credentials, which
|
||||||
|
// sidestep the identifier gap but reshape enrollment (residentKey) and need a
|
||||||
|
// non-user-keyed challenge store — a future migration and its own checkpoint (that door
|
||||||
|
// partly bypasses the in-game-identity root of trust). The adapter crypto is verified
|
||||||
|
// now so that slice inherits correct crypto; this file adds no unauthenticated login
|
||||||
|
// route until then.
|
||||||
//
|
//
|
||||||
// The cryptographic half is a seam (PasskeyVerifier) so this package never imports
|
// The cryptographic half is a seam (PasskeyVerifier) so this package never imports
|
||||||
// go-webauthn: ceremony state crosses the boundary as opaque bytes, the attestation
|
// go-webauthn: ceremony state crosses the boundary as opaque bytes, the attestation
|
||||||
|
|||||||
Reference in new issue
Block a user