You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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:
POST /api/auth/login (login assertion)
POST /api/auth/register (self-register)
POST /api/webauthn/register (in-account add)
POST /api/passkey-invite/register (invite-flow add)
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.
Add a small fake-authenticator helper under src/test/helpers/ that:
Holds a P-256 keypair in memory (matches our supportedAlgorithmIDs: [-7]).
Produces a registration response (AuthenticatorAttestationResponse-shaped)
for a given challenge + RP ID + origin, with UV/UP flags set.
Produces an authentication response (AuthenticatorAssertionResponse-shaped)
for a given challenge + credential id + RP ID + origin.
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.
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:
mintStepUpTokenThat leaves the most security-critical path — successful assertion
verification — covered only by the
@simplewebauthn/serverlibrary's owntests. Specifically, none of the following happy paths are exercised
end-to-end in this repo:
POST /api/auth/login(login assertion)POST /api/auth/register(self-register)POST /api/webauthn/register(in-account add)POST /api/passkey-invite/register(invite-flow add)POST /api/webauthn/stepup/verify(feat(webauthn): require step-up assertion before adding or revoking a passkey #159 step-up)The existing test files explicitly call out this gap (see headers of
passkey-invite-flow.test.tsandpasskey-stepup-flow.test.ts).Why this matters
verifyAuthenticationResponse/verifyRegistrationResponsecall-sites (wrong
expectedChallenge, missingrequireUserVerification, swappedexpectedRPID, etc.) wouldn't be caught by any of our tests.UV-required-but-not-set, or wrong-RP-ID without a fake authenticator.
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:supportedAlgorithmIDs: [-7]).AuthenticatorAttestationResponse-shaped)for a given challenge + RP ID + origin, with UV/UP flags set.
AuthenticatorAssertionResponse-shaped)for a given challenge + credential id + RP ID + origin.
credentialbody of the verify endpoints.@simplewebauthn/server's test suite has reference helpers for both shapes(
generateAuthenticationResponse/generateRegistrationResponsearen'tpublic, but the JSON structure is stable). Could also use
@simplewebauthn/typesfor type alignment.Then add ceremony-level happy-path tests for each of the five endpoints
above, plus at least:
/stepup/verifymints a token usable at a gated endpointOut of scope
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 toevery WebAuthn endpoint we have, and the right fix is one shared helper
rather than per-flow workarounds.