WEB / WEB-14.S02
Recovery, passkeys, and sensitive account changes
Binding an authenticator or changing a recovery contact changes future account control. Track the subject and purpose bound to passkey ceremonies and recovery authority.
1. Core · Mechanism
Read every scenario without motion
New passkey association
- Scoped fresh proof at start
Existing-authenticator fresh reauthentication is supplied; authority covers subject-duru/register-new-passkey.
- Browser / Duru
- Awaiting registration options
- Atlas RP / Application
- Fresh reauth; scoped binding permission
- Account / credential ledger
- Existing credential association; no new key
- Registration challenge record
The RP creates a pending ceremony for trusted subject/purpose; its alias is not random bytes.
- Browser / Duru
- Awaiting registration options
- Atlas RP / Application
- Pending create ceremony
- Account / credential ledger
- Pending registration challenge; no new key
- Options reached the Browser
The HTTPS response carries RP ID, challenge alias, and required-UV intent.
- Browser / Duru
- Create options available
- Atlas RP / Application
- Awaiting registration result
- Account / credential ledger
- Pending registration challenge; no new key
- Local authenticator result
Browser create/authenticator processing is represented by a supplied result; this step is not an HTTPS packet.
- Browser / Duru
- Supplied create result ready
- Atlas RP / Application
- Awaiting registration result
- Account / credential ledger
- Pending registration challenge; no new key
- Registration result reached the RP
Application transport forwards a result alias; the RP has not accepted the association yet.
- Browser / Duru
- Waiting for binding decision
- Atlas RP / Application
- Received result; validation pending
- Account / credential ledger
- Pending registration challenge; no new key
- Trusted ceremony validation
Alongside fresh proof and subject/purpose binding, the RP checks webauthn.create type, challenge, allowed origin, RP-ID hash and required UP/UV. Algorithm, attestation, credential-ID availability and crypto outcomes are supplied in this example; the association has not committed yet.
- Browser / Duru
- Waiting for binding decision
- Atlas RP / Application
- Validation passed
- Account / credential ledger
- Challenge checked; no new key committed
- Association commit or unchanged state
All acceptance conditions pass for this registration, so the RP consumes the challenge and stores the new public-key/subject association. Notification is queued, without proof of sending or receipt. The Browser still awaits the binding result.
- Browser / Duru
- Waiting for binding decision
- Atlas RP / Application
- Validation passed
- Account / credential ledger
- Challenge consumed; new credential bound; notification queued
- Binding outcome at the Browser
The Browser received confirmation that the new passkey association was stored. This result covers register-new-passkey/subject-duru; it performs no new login ceremony and grants nothing for another account. Notification delivery needs separate evidence.
- Browser / Duru
- Passkey added
- Atlas RP / Application
- Validation passed
- Account / credential ledger
- Challenge consumed; new credential bound; notification queued
Origin mismatch
- Scoped fresh proof at start
Existing-authenticator fresh reauthentication is supplied; authority covers subject-duru/register-new-passkey.
- Browser / Duru
- Awaiting registration options
- Atlas RP / Application
- Fresh reauth; scoped binding permission
- Account / credential ledger
- Existing credential association; no new key
- Registration challenge record
The RP creates a pending ceremony for trusted subject/purpose; its alias is not random bytes.
- Browser / Duru
- Awaiting registration options
- Atlas RP / Application
- Pending create ceremony
- Account / credential ledger
- Pending registration challenge; no new key
- Options reached the Browser
The HTTPS response carries RP ID, challenge alias, and required-UV intent.
- Browser / Duru
- Create options available
- Atlas RP / Application
- Awaiting registration result
- Account / credential ledger
- Pending registration challenge; no new key
- Local authenticator result
Browser create/authenticator processing is represented by a supplied result; this step is not an HTTPS packet.
- Browser / Duru
- Supplied create result ready
- Atlas RP / Application
- Awaiting registration result
- Account / credential ledger
- Pending registration challenge; no new key
- Registration result reached the RP
Application transport forwards a result alias; the RP has not accepted the association yet.
- Browser / Duru
- Waiting for binding decision
- Atlas RP / Application
- Received result; validation pending
- Account / credential ledger
- Pending registration challenge; no new key
- Trusted ceremony validation
Alongside fresh proof and subject/purpose binding, the RP checks webauthn.create type, challenge, allowed origin, RP-ID hash and required UP/UV. Algorithm, attestation, credential-ID availability and crypto outcomes are supplied in this example; the association has not committed yet.
- Browser / Duru
- Waiting for binding decision
- Atlas RP / Application
- Validation denied: origin mismatch
- Account / credential ledger
- Challenge checked; no new key committed
- Association commit or unchanged state
With originMatched=false, the RP stores no new credential association: newCredentialBound=false and the challenge remains rejected. cryptographicResultValid=true cannot satisfy that independent origin condition; existing account associations remain unchanged.
- Browser / Duru
- Waiting for binding decision
- Atlas RP / Application
- Validation denied: origin mismatch
- Account / credential ledger
- Challenge rejected; existing associations unchanged
- Binding outcome at the Browser
The Browser received a registration rejection; no new passkey was added. Existing account associations remain intact. This branch explains the RP’s received-result checks; it does not claim a real Browser produced this inconsistent result.
- Browser / Duru
- Passkey not added
- Atlas RP / Application
- Validation denied: origin mismatch
- Account / credential ledger
- Challenge rejected; existing associations unchanged
Restricted recovery
- Recovery context at start
Approved recovery evidence and assurance are supplied; a proof alias is not an ordinary session.
- Browser / Duru
- Recovery proof alias ready
- Atlas RP / Application
- No recovery request
- Account / credential ledger
- Proof unused; generation-a; lost key active; old session active
- Recovery-proof request arrived
The RP will evaluate account/purpose, proof verification, and unused/lifetime conditions.
- Browser / Duru
- Waiting for recovery result
- Atlas RP / Application
- Recovery proof received
- Account / credential ledger
- Proof unused; generation-a; lost key active; old session active
- Restricted recovery gate
Acceptance consumes proof atomically; used proof grants no further mutation authority.
- Browser / Duru
- Waiting for recovery result
- Atlas RP / Application
- Restricted reset authorized
- Account / credential ledger
- Proof consumed; restricted capability
- Reset and affected invalidation
A local commit changes verifier generation, invalidates the known lost association, revokes the old session generation, and only queues notification.
- Browser / Duru
- Waiting for recovery result
- Atlas RP / Application
- Restricted reset completed; no ordinary session
- Account / credential ledger
- Proof consumed; generation-b; lost key invalidated; old session revoked
- Recovery outcome at the Browser
The Browser received completion of the restricted reset. A new verifier generation was stored, the known lost association invalidated and the old session generation revoked; ordinarySessionIssued=false remains. Ordinary login and notification delivery are separate operations.
- Browser / Duru
- Reset complete; normal login required
- Atlas RP / Application
- No ordinary session issued
- Account / credential ledger
- Proof consumed; generation-b; lost key invalidated; old session revoked
Proof consumed
- Recovery context at start
Approved recovery evidence and assurance are supplied; a proof alias is not an ordinary session.
- Browser / Duru
- Recovery proof alias ready
- Atlas RP / Application
- No recovery request
- Account / credential ledger
- Proof consumed; generation-b; lost key invalidated; old session revoked
- Recovery-proof request arrived
The RP will evaluate account/purpose, proof verification, and unused/lifetime conditions.
- Browser / Duru
- Waiting for recovery result
- Atlas RP / Application
- Recovery proof received
- Account / credential ledger
- Proof consumed; generation-b; lost key invalidated; old session revoked
- Used proof denied
The proof was already consumed. The recovery gate grants no new reset capability; credential and session generations remain unchanged.
- Browser / Duru
- Waiting for recovery result
- Atlas RP / Application
- Denied: proof already consumed
- Account / credential ledger
- Proof consumed; generation-b; lost key invalidated; old session revoked
- Recovery outcome at the Browser
The browser received the recovery denial. No new reset, ordinary session, or notification delivery occurred; existing records remain unchanged.
- Browser / Duru
- Recovery not completed
- Atlas RP / Application
- No ordinary session issued
- Account / credential ledger
- Proof consumed; generation-b; lost key invalidated; old session revoked
ACTORS · STATE · DATA FLOW
Future account control is a sensitive permission
Duru wants to add a passkey on a new laptop. This action changes more than profile text: an authenticator controlling the new private key can authenticate subject-duru in the future. Atlas does not treat an active Browser session alone as authority to create this association; it requires fresh reauthentication and trusted account binding.
The normal fixture starts with supplied success from fresh reauthentication using an existing authenticator. That ceremony is not separately animated. Authority is restricted to register-new-passkey for subject-duru; it does not grant changes to another account or recovery contact.
Consider current credentials/fresh proof for password change and trusted old context/new-endpoint verification for contact changes separately. A session supplies continuity rather than perpetual unrestricted sensitive-change authority. WEB-14.S01 develops account lifecycle.
Passkeys replace server passwords with public-key associations
A passkey is a FIDO credential associated with a website/application account. The WebAuthn RP server keeps trusted associations among credential ID, subject/user handle, and public key. The authenticator performs private-key operations; the server does not request the private key or device-unlock PIN.
Platform and roaming authenticators offer different access forms. A passkey can be device-bound or syncable, so do not assume every private key always remains on one device. A sync fabric, provider-account recovery, and device locks introduce their own boundaries.
Biometrics or PINs provide local user verification; this does not imply that Atlas receives biometric templates. User presence and user verification are distinct flags. A product requiring UV must check it through trusted validation; a face icon in the UI does not prove that result.
Registration and authentication are separate ceremonies
navigator.credentials.create() produces/registers a new credential; navigator.credentials.get() requests an authentication assertion with an existing credential. The RP server supplies ceremony options/challenge, the Browser uses the authenticator API, and application transport forwards the response to the RP.
The normal scene teaches register-new-passkey. Browser create-result processing uses a supplied authenticator result; key generation, CBOR/COSE parsing, and cryptographic attestation are not implemented. The Application’s gate represents trusted validation by an established WebAuthn implementation. Algorithm/attestation policy, credential-ID uniqueness, and account binding are supplied true in the normal fixture.
During get authentication, the RP checks the assertion signature with the stored credential public key and validates the credential/account association. A declining counter or constant zero is not universal proof of compromise; authenticator type, sync, and response ordering affect risk assessment. An assertion does not automatically grant new-registration authority.
Challenge, RP ID, and origin are different bindings
Atlas chooses RP ID=library.atlas.example and expected origin=https://library.atlas.example. RP ID describes domain scope; origin includes scheme, host, and port. Their checks are not interchangeable string comparisons. Broader RP-ID scope changes subdomain trust, and credentials do not use cookie Domain/Path scoping.
Registration clientData must match type=webauthn.create, the expected challenge, and an allowed origin; authenticator data must satisfy RP-ID hash and required-flag checks. Authentication uses the distinct webauthn.get ceremony. The fixture supplies type/challenge/origin/rpIdHash/UV/cryptographic-result booleans; the challenge alias is not random bytes.
The wrong-origin branch supplies cryptographicResultValid=true but originMatched=false, so the RP creates no association. It does not claim a real Browser generated this inconsistent result; it illustrates the RP’s received-input acceptance boundary. Keeping the challenge with ceremony/account/purpose prevents a completed result being bound to an incorrect subject.
Recovery is not a shortcut to login success
Losing an old authenticator can require recovery. Forgot-password, password replacement using an available authenticator, and account recovery after loss of all required authenticators are different situations. Available proof, account assurance, and product risk analysis determine the permitted recovery path.
The recovery branch supplies approvedRecoveryEvidence=true and assuranceRequirementMet=true as prior trusted decisions. RECOVERY_SECRET_ALIAS is an inert token reference rather than a claim that one code suffices for every AAL/product. A valid, unused, live proof bound to the account and purpose=lifecycle-recovery is consumed atomically.
Success grants restricted reset authority rather than a new authenticated-user session. Atlas changes the password-verifier generation, invalidates the known lost credential association, marks its old session generation revoked, and queues independent notification. It does not depict delivery or simultaneous revocation across every resource server; normal login follows.
Boundaries of reset, factor replacement, and notification
A password-reset token is securely generated, purpose-bound, single-use, and lifetime-limited. The request itself should not mutate account state and lock out the user. Restricted reset state completes the update separately from login. Supplying a consumed recovery proof makes unused=false and blocks further mutation.
Password reset alone may not restore control after suspected compromise: active sessions, added authenticators, or changed recovery addresses may remain. Review previously trusted evidence, current associations, and pending changes. Do not automatically elevate a recently added contact to strongest proof or restore old contacts without knowing why they were removed.
Notification does not authorize the change; it helps a user detect and repudiate it. notificationQueued=true does not imply sent/read delivery. Define repudiation, rollback, and session effects after contact or factor changes.
2. Red · Trust & Impact
Read every scenario without motion
Wrong origin
- The passkey-association scope was selected
Purpose register-new-passkey and type webauthn.create are supplied. RP ID library.atlas.example and expected origin https://library.atlas.example are distinct control fields.
- Ceremony/recovery context
- wrong-origin registration
- Account lifecycle gate
- Gates not evaluated
- Association/session boundary
- Credential not bound
- Fresh proof and subject were separated
freshReauth=true and subjectBound=true are supplied. These positive conditions do not replace the ceremony-origin check; a browser displayName is not authority.
- Ceremony/recovery context
- Fresh proof; subject bound
- Account lifecycle gate
- Origin check pending
- Association/session boundary
- Credential not bound
- Crypto and origin were separated
cryptographicResultValid=true but originMatched=false. True rpIdHashMatched, challenge and type predicates do not remove the failed origin-association gate.
- Ceremony/recovery context
- Crypto predicate=true
- Account lifecycle gate
- Origin matched=false
- Association/session boundary
- Credential not bound
- Association commit was rejected
newCredentialBound=false and afterChallengeState=rejected remain. A valid crypto flag does not authorize adding a credential under the wrong ceremony context.
- Ceremony/recovery context
- Crypto predicate=true
- Account lifecycle gate
- Challenge rejected
- Association/session boundary
- New credential bound=false
- Sensitive-change authority was not broadened
Factor binding requires fresh proof together with account-bound ceremony validation. Recovery or password-change capability does not automatically open the origin gate for this registration.
- Ceremony/recovery context
- Purpose: register-new-passkey
- Account lifecycle gate
- Origin gate failed
- Association/session boundary
- No association mutation
- The association boundary stayed closed
This fixture shows wrong-origin denial; it adds no claim of an actual browser ceremony, CBOR/COSE processing or signature operation. A declared crypto predicate and an association decision are different evidence.
- Ceremony/recovery context
- Declared crypto valid
- Account lifecycle gate
- Known: origin mismatch
- Association/session boundary
- No new credential association
Consumed proof
- The recovery-capability boundary was selected
The recovery-used row belongs to purpose lifecycle-recovery. A prior successful attempt established credential-generation-b and invalidated affected old state; that past operation is not rolled back.
- Ceremony/recovery context
- Recovery-used row
- Account lifecycle gate
- Consumption not examined
- Association/session boundary
- No new reset
- Proof matching and availability were separated
proofMatches=true and lifetimeValid=true coexist with unused=false. Presenting a matching proof again does not reopen the one-time consumption condition.
- Ceremony/recovery context
- Proof matches; unused=false
- Account lifecycle gate
- Already consumed
- Association/session boundary
- No new reset
- A new reset was withheld
resetCompleted=false remains. credentialGenerationAfter=credential-generation-b and lostCredentialStateAfter=invalidated preserve earlier committed outcomes; the repeated attempt makes no new mutation.
- Ceremony/recovery context
- Used proof rejected
- Account lifecycle gate
- Generation b retained
- Association/session boundary
- No new credential reset
- Session and notification were separated
ordinarySessionIssued=false and notificationQueued=false apply to this new attempt. Previously queued notifications are not considered cleared.
- Ceremony/recovery context
- Used proof rejected
- Account lifecycle gate
- Old-session revocation retained
- Association/session boundary
- No additional notification
- Recovery was not elevated to ordinary access
The limited recovery purpose establishes neither an unrestricted session nor a new action grant. An old session being revoked is not proof of browser cleanup or revocation of every access token.
- Ceremony/recovery context
- Purpose: lifecycle-recovery
- Account lifecycle gate
- Generation b retained
- Association/session boundary
- No ordinary session
- Denial preserved the previous effect
This branch produces no new reset or additional notification. It does not undo the prior successful reset; notification delivery and downstream acceptance need separate evidence.
- Ceremony/recovery context
- Known: proof consumed
- Account lifecycle gate
- Prior committed state retained
- Association/session boundary
- No new reset/session/notification
ASSUMPTION · BOUNDARY · CONTROL
Correct cryptography does not correct a wrong association
Registration normally associates a new authenticator public key with an authorized subject. Skipping fresh reauthentication/account binding or ceremony-origin gates can associate a key with an incorrect subject/purpose. The prerequisite is an unchecked received result reaching the association gate; scope is the account context later established through that credential.
Validate challenge/ceremony context alongside trusted subject, RP ID, origin, required UV, and approved validation policy before committing the association. Browser display names supply no authority. The artifact keeps newCredentialBound=false for wrong origin; a crypto-valid flag cannot override policy.
Recovery authority must not silently become ordinary access
Normal recovery permits controlled replacement after the specified proof. Elevating its capability into an unrestricted session or leaving proof reusable can grant broader access/change authority. One successful-looking response does not establish closure of every lost-key/session state.
Restricted purpose, one-time consumption, a new credential generation, and affected-association/session invalidation are separate controls. Legitimate users also lose devices, have sync failures, or receive stale notifications; a failure reason is not an attack label. Review recovery trust independently of primary authentication.
3. Blue · Secure development & defense
Read every scenario without motion
Recovery ledger
- The recovery-success scope was selected
The normal recovery row carries four distinct state outcomes: proof consumption, credential generation, affected old state and notification queue. One success label does not turn all of them into delivery.
- Lifecycle observation
- case=recovery
- Association/queue review
- States not correlated
- Evidence conclusion
- No delivery evidence
- Consumption and generation were correlated
afterProofState=consumed and credentialGenerationAfter=credential-generation-b are recorded. These are restricted-reset state changes; ordinarySessionIssued=false remains separate.
- Lifecycle observation
- Proof consumed
- Association/queue review
- Generation b; no ordinary session
- Evidence conclusion
- No delivery evidence
- Affected old state was read
lostCredentialStateAfter=invalidated and oldSessionStateAfter=revoked are supplied. These describe which old state closed; they are not assumed to cover every resource-server token.
- Lifecycle observation
- Proof consumed
- Association/queue review
- Lost credential invalidated; old session revoked
- Evidence conclusion
- Downstream token state unknown
- Queueing and delivery were separated
notificationQueued=true shows only that this attempt queued an independent notification. It does not establish sending, inbox arrival or the user reading it.
- Lifecycle observation
- Restricted reset completed
- Association/queue review
- Notification queued=true
- Evidence conclusion
- UNKNOWN: notification delivery
- Missing delivery evidence was requested
Without delivery telemetry, queue success is not shown as delivery success. Producer and notification outcomes require separate correlation; logging secrets or a new password is unnecessary.
- Lifecycle observation
- Restricted reset completed
- Association/queue review
- Queue evidence present
- Evidence conclusion
- Delivery observation required
- The recovery conclusion stayed in scope
Proof consumption, generation change and affected invalidation are known. Notification delivery and other downstream acceptance remain UNKNOWN; recovery does not issue an ordinary session.
- Lifecycle observation
- Known: reset completed
- Association/queue review
- Known: scoped invalidation
- Evidence conclusion
- UNKNOWN: delivery/downstream
Missing origin
- The association-audit scope was selected
This branch reviews newCredentialBound and freshReauth from the normal association record, but omits originMatched. Missing origin evidence is not filled with success.
- Lifecycle observation
- Partial binding record
- Association/queue review
- Origin evidence missing
- Evidence conclusion
- No integrity conclusion
- The association outcome was read
newCredentialBound=true and freshReauth=true are visible. These two fields do not establish ceremony-origin or rpIdHash validation in the supplied record.
- Lifecycle observation
- New credential bound=true
- Association/queue review
- Fresh reauth=true
- Evidence conclusion
- No integrity conclusion
- The selector field requirement was separated
The XPath searches for completed-binding inconsistency with false origin or false freshReauth. A missing origin is not originMatched=true; predicate coverage is incomplete.
- Lifecycle observation
- Completed binding claim
- Association/queue review
- Missing origin ≠ true
- Evidence conclusion
- UNKNOWN: origin validation
- A zero count was not treated as clean evidence
Missing fields can leave a selection empty; this does not prove enforcement of the origin gate. The separate positive fixture shows originMatched=false with newCredentialBound=true.
- Lifecycle observation
- Completed binding claim
- Association/queue review
- Selection coverage incomplete
- Evidence conclusion
- UNKNOWN: association integrity
- A trusted-source record was requested
The origin decision in the same ceremony and subject scope is required. A browser displayName or credential alias is not authentication proof that fills this missing decision.
- Lifecycle observation
- Completed binding claim
- Association/queue review
- Origin decision required
- Evidence conclusion
- UNKNOWN: association integrity
- Missing evidence was neither denial nor bypass
This partial record cannot establish either safe or incorrect association. Event loss and schema mapping need their own evidence; no actual WebAuthn crypto result is added.
- Lifecycle observation
- Known: partial binding claim
- Association/queue review
- Missing origin evidence
- Evidence conclusion
- UNKNOWN: gate enforcement
IMPLEMENTATION · SECURITY CONTROL · VERIFICATION
What can an association ledger establish?
A sanitized RP decision record can correlate ceremonyRef, subjectRef, originMatched, rpIdHashMatched, challengeMatched, freshReauth, and newCredentialBound. Public-key/credential references do not authenticate like secrets but still require privacy/retention protection. Exclude private keys, recovery secrets, and biometric data.
The XPath selects integrity discrepancies where newCredentialBound=true but originMatched=false or freshReauth=false. Normal binding selects zero; a synthetic audit ignoring the origin gate selects one. Missing source events provide insufficient evidence; this does not perform multi-host ordering or real cryptographic verification.
Track separate outcomes after recovery succeeds
Consumed proof, replacement generation, affected old association/session invalidation, and independent notification are separate transitions. A queued notification does not prove delivery; Browser acceptance of a new password does not establish immediate expiry of an old resource-server access token.
Normal recovery retains restricted reset completed and ordinarySessionIssued=false. The used-proof branch leaves records/generations unchanged. Valid proof with delivery retries can be benign; authorization-ledger evidence and notification-delivery telemetry remain separate observations.
Validate Browser ceremonies alongside account policy
Use an established WebAuthn library and a supported Browser/device matrix to validate RP ID, allowed origins, userVerification, platform/roaming, and sync behavior. API availability does not give every credential identical assurance/recovery properties. Origin allowlists and reverse-proxy external-origin changes need controlled review.
Sensitive-change paths specify which action and freshness window accept the proof. Users need understandable paths for lost-device invalidation, replacement enrollment, and repudiation. Determine affected state/product risk for controlled migration rather than deleting all credentials indiscriminately.
NOW APPLY IT TO THE CASE
How do crypto outcomes, recovery state and notifications differ?
Origin association and one-time recovery purpose establish distinct boundaries. Ledger state is not substituted for notification delivery or all downstream acceptance.
Separate decisions for verified actor, tenant relation and requested action in the case. Do not substitute authentication or proof success for object permission.
Open the related case file ↗READ THE EXAMPLE TOGETHER
Recovery and passkey-association ledger
Select a field and examine what it supports and where the evidence ends.
Read the raw artifact and field explanations
{
"subjectRef": "subject-duru",
"rpId": "library.atlas.example",
"expectedOrigin": "https://library.atlas.example",
"credentialAlias": "CREDENTIAL_NEW_ALIAS_NOT_BYTES",
"userHandleAlias": "USER_HANDLE_ALIAS_NOT_BYTES",
"publicKeyAlias": "PUBLIC_KEY_ALIAS_NOT_COSE",
"registrationChallenge": "REGISTRATION_CHALLENGE_ALIAS_NOT_RANDOM_BYTES",
"registrationType": "webauthn.create",
"authenticationType": "webauthn.get",
"purpose": "register-new-passkey",
"registrationRows": [
{
"case": "normal",
"freshReauth": true,
"subjectBound": true,
"purposeMatched": true,
"typeMatched": true,
"challengeMatched": true,
"originMatched": true,
"rpIdHashMatched": true,
"userVerified": true,
"cryptographicResultValid": true,
"algorithmAllowed": true,
"attestationPolicyAllowed": true,
"credentialIdAvailable": true,
"challengeUnused": true,
"newCredentialBound": true,
"afterChallengeState": "consumed",
"userPresent": true
},
{
"case": "wrong-origin",
"freshReauth": true,
"subjectBound": true,
"purposeMatched": true,
"typeMatched": true,
"challengeMatched": true,
"originMatched": false,
"rpIdHashMatched": true,
"userVerified": true,
"cryptographicResultValid": true,
"algorithmAllowed": true,
"attestationPolicyAllowed": true,
"credentialIdAvailable": true,
"challengeUnused": true,
"newCredentialBound": false,
"afterChallengeState": "rejected",
"userPresent": true
}
],
"authenticationValidationNotes": {
"requiredChecks": [
"credential/account binding",
"type",
"challenge",
"allowed origin",
"rpIdHash",
"required UP/UV",
"stored-key signature verification"
],
"signCountZeroIsNotUniversalCompromiseProof": true
},
"recoveryAlias": "RECOVERY_SECRET_ALIAS_NOT_A_SECRET",
"recoveryVerifierAlias": "RECOVERY_VERIFIER_ALIAS_NOT_A_HASH",
"recoveryPurpose": "lifecycle-recovery",
"replacementVerifierAlias": "NEW_PASSWORD_VERIFIER_ALIAS_NOT_A_HASH",
"recoveryRows": [
{
"case": "recovery",
"approvedRecoveryEvidence": true,
"assuranceRequirementMet": true,
"subjectBound": true,
"purposeMatched": true,
"proofMatches": true,
"unused": true,
"lifetimeValid": true,
"resetCompleted": true,
"afterProofState": "consumed",
"credentialGenerationAfter": "credential-generation-b",
"lostCredentialStateAfter": "invalidated",
"oldSessionStateAfter": "revoked",
"notificationQueued": true,
"ordinarySessionIssued": false,
"notificationMeaning": "A new independent notification is queued for this attempt; delivery is not asserted."
},
{
"case": "recovery-used",
"approvedRecoveryEvidence": true,
"assuranceRequirementMet": true,
"subjectBound": true,
"purposeMatched": true,
"proofMatches": true,
"unused": false,
"lifetimeValid": true,
"resetCompleted": false,
"afterProofState": "consumed",
"credentialGenerationAfter": "credential-generation-b",
"lostCredentialStateAfter": "invalidated",
"oldSessionStateAfter": "revoked",
"notificationQueued": false,
"ordinarySessionIssued": false,
"notificationMeaning": "No additional notification queued by this rejected attempt; prior queued messages are not cleared."
}
],
"sensitiveChanges": {
"passwordChange": "fresh current authenticator proof plus scoped permission",
"contactChange": "fresh proof, new contact verification and independent notification",
"factorBinding": "fresh proof plus account-bound ceremony validation"
},
"selector": {
"language": "XPath",
"xml": "<audit><binding newCredentialBound=\"true\" originMatched=\"true\" freshReauth=\"true\"/></audit>",
"xpath": "count(/audit/binding[@newCredentialBound=\"true\" and (@originMatched=\"false\" or @freshReauth=\"false\")])",
"expected": 0,
"positiveFixtureXml": "<audit><binding newCredentialBound=\"true\" originMatched=\"false\" freshReauth=\"true\"/></audit>",
"positiveExpected": 1,
"scope": "Own association-integrity XML; no CBOR/COSE, Browser ceremony, crypto, recovery provider or delivery runtime.",
"missingFieldBehavior": "Selection requires declared fields. Missing fields mean insufficient evidence; a zero count does not prove control efficacy."
}
}- rpId / expectedOrigin
- Credential-domain scope differs from scheme/host/port origin and is not cookie scope.
- credentialAlias / userHandleAlias / publicKeyAlias
- Aliases track account-key associations without actual credential bytes or usable keys.
- registrationRows
- Fresh-proof and ceremony-acceptance results with supplied cryptographic predicates.
- recoveryRows
- Approved evidence/assurance are supplied; restricted reset, proof consumption, and affected invalidation are distinct.
- notificationQueued / ordinarySessionIssued
- Queued is not delivered; recovery success does not automatically issue an ordinary login session.
Aliases are not actual secrets, keys, or challenges. Existing-factor reauthentication, approved recovery evidence, and cryptographic/attestation/flag results are declared inputs. Browser create/get, signatures, provider recovery, delivery, and distributed revocation are not executed.
Two reality checks
Passkey login sends the biometric template and private key to the server.
The authenticator performs key operations; the RP evaluates a public-key association and valid result. Local biometric verification does not imply transfer of raw biometrics.
Completing password reset automatically invalidates every authenticator and session.
Affected credentials, session/token revocation, and notifications are separate lifecycle operations; propagation and ordinary login require separate treatment.
YOUR TURN
Work through this story.
Predict the outcome, find the evidence boundary, and explain it in your own words.
Passkey registration has cryptographicResultValid=true but originMatched=false. Is the new credential bound to the account?
- Yes. A true crypto result makes ceremony context irrelevant.
- No. newCredentialBound=false and the challenge is rejected.
Read the explained answer
No. newCredentialBound=false and the challenge is rejected. — This registration policy requires origin, challenge, type, subject and other conditions together. One valid crypto result does not approve the wrong origin.
The recovery proof was already consumed. Does notificationQueued=false mean an earlier queued notification was deleted?
Selected lesson artifact fields; teaching example
- recoveryRows[1].unused
- false
- recoveryRows[1].resetCompleted
- false
- recoveryRows[1].notificationQueued
- false
- recoveryRows[1].notificationMeaning
- No additional notification queued by this rejected attempt; prior queued messages are not cleared.
- No. The rejected attempt queues no new notification; prior queued messages are not cleared.
- Yes. A rejected proof rolls back every prior recovery effect.
Read the explained answer
No. The rejected attempt queues no new notification; prior queued messages are not cleared. — unused=false rejects the reset. notificationMeaning describes no additional notification for this attempt, not deletion of earlier records.
Recovery creates a new generation and revokes the old session, but ordinarySessionIssued=false. Why is recovery not ordinary login or delivered notification?
Read the explained answer
Recovery requires a separate account-bound lifecycle proof meeting the assurance requirement. This example changes the password verifier, invalidates the lost credential and revokes the old session without issuing a new ordinary session. Queued notification is not delivery. New-factor binding and contact changes need their own fresh proof and ceremony conditions. Aliases are not real recovery secrets, COSE keys or an executed browser ceremony.
□ I separated recovery purpose from ordinary session issuance.
□ I did not treat queued notification as delivery or rollback of prior effects.
Open the application console · request / response / browser
Also open request, URL, cookie and DOM examples
Sources and scope
- W3C — Web Authentication Level 31 Introduction · 7.1 Registering a New Credential · 7.2 Verifying an Authentication Assertion · 13.4.9 Validating the origin of a credential · 6.1.1 Signature Counter Considerations
- MDN — Web Authentication APIWebAuthn concepts and usage · Creating a key pair and registering a user · Authenticating a user
- FIDO Alliance — PasskeysWhat are passkeys? · Based on Open Standards
- OWASP — Forgot Password Cheat SheetForgot Password Request · User Resets Password · Account Recovery After Suspected Compromise · General Security Practices · URL Tokens
- OWASP — Multifactor Authentication Cheat SheetIntroduction · One-Time Password (OTP) Handling and Storage · Resetting MFA · Changing MFA Factors · MFA Fatigue (Push Notification Bombing): Mitigations
- OWASP — Authentication Cheat SheetUsernames · Compare Password Hashes Using Safe Functions · Authentication and Error Messages · Login Throttling · Require Re-authentication for Sensitive Features
- NIST SP 800-63B-4 — Authentication and Authenticator Management2.2 Authentication Assurance Level 2 · 3.1.1.2 Password Verifiers · 3.2.2 Rate Limiting (Throttling) · 3.2.5 Phishing Resistance · 4.1 Authenticator Binding · 4.2 Account Recovery · 4.5 Invalidation · 4.6 Account Notifications
- OWASP — Logging Cheat SheetWhich events to log · Event attributes · Data to exclude · Verification