Skip to content

test(webauthn): add fake-authenticator integration tests for the WebAuthn ceremonies #162

@rado0x54

Description

@rado0x54

Problem

Our integration tests for every WebAuthn-using endpoint stop short of the
actual cryptographic ceremony. We exercise gates, state machines, and
challenge purpose binding by:

  • inserting credential rows directly into SQLite
  • minting step-up tokens directly via mintStepUpToken
  • pointing test calls at endpoints with crafted-but-not-signed payloads

That leaves the most security-critical path — successful assertion
verification — covered only by the @simplewebauthn/server library's own
tests. Specifically, none of the following happy paths are exercised
end-to-end in this repo:

The existing test files explicitly call out this gap (see headers of
passkey-invite-flow.test.ts and passkey-stepup-flow.test.ts).

Why this matters

  • A regression that breaks verifyAuthenticationResponse / verifyRegistrationResponse
    call-sites (wrong expectedChallenge, missing requireUserVerification, swapped
    expectedRPID, etc.) wouldn't be caught by any of our tests.
  • We can't write negative tests for things like counter rollback,
    UV-required-but-not-set, or wrong-RP-ID without a fake authenticator.
  • The step-up flow's purpose binding (feat(webauthn): require step-up assertion before adding or revoking a passkey #159 follow-up) is currently tested
    only via the failure path (purpose mismatch surfaces no challenge);
    there's no test that a happy-path step-up assertion + token mint actually
    works end to end.

Proposal

Add a small fake-authenticator helper under src/test/helpers/ that:

  1. Holds a P-256 keypair in memory (matches our supportedAlgorithmIDs: [-7]).
  2. Produces a registration response (AuthenticatorAttestationResponse-shaped)
    for a given challenge + RP ID + origin, with UV/UP flags set.
  3. Produces an authentication response (AuthenticatorAssertionResponse-shaped)
    for a given challenge + credential id + RP ID + origin.
  4. Returns base64url-encoded fields ready to drop into the
    credential body of the verify endpoints.

@simplewebauthn/server's test suite has reference helpers for both shapes
(generateAuthenticationResponse / generateRegistrationResponse aren't
public, but the JSON structure is stable). Could also use
@simplewebauthn/types for type alignment.

Then add ceremony-level happy-path tests for each of the five endpoints
above, plus at least:

  • counter-rollback rejection on a second login with the same counter
  • UV-required + UV-bit-not-set rejection
  • origin-mismatch rejection
  • successful /stepup/verify mints a token usable at a gated endpoint

Out of scope

  • Browser-side ceremony testing (Playwright + virtual authenticator) —
    worthwhile but a much bigger lift; cover server-side first.

Notes

This came out of the review on the #159 step-up PR. The reviewer flagged
the gap specifically for /stepup/verify, but the same pattern applies to
every WebAuthn endpoint we have, and the right fix is one shared helper
rather than per-flow workarounds.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions