Hacker DirectoryHacker Directory

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.

CORE · RED · BLUE · ARTIFACT · PRACTICE

1. Core · Mechanism

Read every scenario without motion

New passkey association

  1. 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
  2. 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
  3. 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
  4. 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
  5. 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
  6. 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
  7. 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
  8. 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

  1. 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
  2. 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
  3. 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
  4. 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
  5. 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
  6. 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
  7. 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
  8. 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

  1. 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
  2. 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
  3. 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
  4. 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
  5. 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

  1. 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
  2. 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
  3. 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
  4. 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

  1. 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
  2. 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
  3. 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
  4. 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
  5. 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
  6. 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

  1. 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
  2. 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
  3. 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
  4. 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
  5. 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
  6. 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

  1. 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
  2. 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
  3. 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
  4. 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
  5. 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
  6. 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

  1. 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
  2. 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
  3. 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
  4. 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
  5. 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
  6. 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?

  1. Yes. A true crypto result makes ceremony context irrelevant.
  2. 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.
  1. No. The rejected attempt queues no new notification; prior queued messages are not cleared.
  2. 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