Build a case-review account flow for reviewer 29, who uses a laptop and a shared workstation. The server issues one-use challenges scoped to registration or sign-in, verifies the returned assertion with a maintained WebAuthn implementation, and binds registration to the signed-in account that requested it. A credential ID resolves to exactly one account. After a verified sign-in, object permissions are still checked on each case route. The interface offers a visible fallback when the browser has no credential or the prompt is canceled. Settings show enrolled credentials and require recent assurance before adding or removing one. Removing a credential takes effect at the authoritative lookup even if another browser already holds a challenge. Losing every credential enters a separate recovery workflow with abuse controls and current authorization checks.
Project: passkey account lifecycle
Build contract
- Register two credentials and reject account switches, expired challenges, replay, wrong origin, and duplicate IDs.
- Sign in with one verified assertion, then prove a valid session does not bypass case authorization.
- Cancel a prompt and finish through the approved fallback with keyboard and focus checks.
- Remove one credential after step-up, attempt reuse, then exercise last-credential and full-loss recovery paths.
Implementation checkpoint
function credentialUsable(record, challenge) {
return record.active && !challenge.used && challenge.actorId === record.actorId;
}
console.log(credentialUsable({ actorId: 29, active: false }, { actorId: 29, used: false }));
// Output: falseCost and boundaries
A credential lookup and challenge-state check are near O(1) with indexed IDs. Public-key verification has bounded cryptographic cost, while multiple credentials add small records and a settings surface. Recovery introduces support and abuse-review work; leaving it untested turns a lost phone into a locked account. Track challenge replay, origin rejection, canceled prompts, credential removal delay, and recovery completion. The small cost of a fresh verification step is justified for account-changing operations, but the product should measure unnecessary prompts.
Failure drill
Replay a registration response and confirm no new credential is stored. Start registration as reviewer 29, switch to reviewer 62, then submit the result; the account binding must fail. Change the origin in a sign-in response and verify no session appears. Remove a passkey while a sign-in prompt is open and finish the prompt; the removed credential must fail. Cancel a prompt on the shared workstation and confirm the fallback remains usable without exposing whether a named account exists. Complete recovery and inspect tenant permissions and old sessions.
Acceptance checks
- Challenges bind to one actor and purpose and are consumed once.
- A signature, origin, and relying-party scope are verified before sign-in.
- Credential removal and recovery follow current authorization and assurance policy.
- Missing credentials leave a usable independent sign-in route.
Common Mistakes
- Treating browser prompt success as server authentication.
- Attaching a credential using a client-supplied account ID.
- Leaving a removed credential active in cached lookup state.
Related lessons
Passkey Registration Challenge and Credential Binding; Passkey Assertion, Origin, and Signature Verification; Passkey Conditional Sign-In and Fallback; Passkey Management, Recovery, and Step-Up.
