Setu-TS
    Preparing search index...

    Interface IPasskeyStore

    Store port for passkey credentials and single-use challenge claims.

    All methods are async so remote backends can implement the interface without a breaking change.

    interface IPasskeyStore {
        claimChallenge(
            challenge: string,
            now: number,
            expiresAt: number,
        ): Promise<boolean>;
        delete(id: string): Promise<void>;
        findById(id: string): Promise<StoredPasskey | null>;
        listByPrincipal(principalId: string): Promise<readonly StoredPasskey[]>;
        save(
            credential: StoredPasskey,
            options: PasskeySaveOptions,
        ): Promise<PasskeySaveResult>;
        updateCounter(id: string, observed: number): Promise<boolean>;
    }

    Implemented by

    Index
    • Atomically records a challenge as used until expiresAt.

      Answers false when the challenge was already claimed and its claim has not expired. This is the server-side replay guard (plan §3.5): on the default encrypted-cookie session strategy, removing the challenge from the session only changes the cookie sent back, and an OLDER copy of the cookie still carries it — so the session alone cannot stop a replayed assertion.

      Parameters

      • challenge: string

        The base64url challenge

      • now: number

        The current wall-clock time in ms; the purge cutoff

      • expiresAt: number

        The wall-clock time the claim lapses, in ms

      Returns Promise<boolean>

      true when this call is the claim's first

    • Atomically stores a NEWLY registered credential.

      This is a compare-and-set, not a blind write, and BOTH conditions are checked in the same atomic step as the insert:

      • no credential with the same id is already present — two ceremonies registering one credential id concurrently (a synced or cloned authenticator shared across accounts) must not both succeed with the later record silently replacing the earlier one, principalId included;
      • the principal holds fewer than options.maxPerPrincipal credentials — a count checked before a separate write lets a burst of concurrent registrations overshoot the cap.

      A duplicate id answers 'duplicate' (checked first), a full principal answers 'limit', and neither writes anything. The registration ceremony maps them to 409 credential-duplicate and 409 credential-limit.

      Parameters

      Returns Promise<PasskeySaveResult>

      'saved', 'duplicate' or 'limit'

    • Atomically advances the stored counter to observed.

      Stores observed only when it is greater than the stored counter, or when both are zero (a synced passkey's steady state), and reports whether it did. A false answer means the assertion's counter did not advance past the stored one — a replay, a regression, or a concurrent use — and the verifier refuses it.

      Parameters

      • id: string

        The credential id

      • observed: number

        The counter the assertion carried

      Returns Promise<boolean>

      true when the stored counter now reflects observed