Skip to content

test(passkey): add PRF output support to the virtual authenticator - #21115

Merged
vpomerleau merged 3 commits into
mainfrom
FXA-14268
Sep 2, 2026
Merged

test(passkey): add PRF output support to the virtual authenticator#21115
vpomerleau merged 3 commits into
mainfrom
FXA-14268

Conversation

@vpomerleau

@vpomerleau vpomerleau commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Because

  • Nothing in the test stack could produce a PRF output, so the kB wrap work in this epic could not be tested above the unit layer.
  • Two consumers were blocked on it: auth-server integration tests, and functional tests whose polyfill delegates its crypto to this authenticator.

This pull request

  • Returns a deterministic per-credential PRF output at assertion, keyed on the eval salt the server sent.
  • Reports prf.enabled at registration, the capability flag the server records.
  • Models an authenticator with no PRF support via prfSupported: false, for the password-fallback path.
  • Surfaces the output to page code through the Playwright polyfill as an ArrayBuffer.
  • Drives the adapter spec's two prfEnabled cases through the real path, retiring its hand-patched clientExtensionResults.
  • Moves the virtual authenticator behind a new @fxa/accounts/passkey/testing entry point.

Issue that this pull request solves

Closes: FXA-14268

Checklist

Put an x in the boxes that apply

  • My commit is GPG signed.
  • If applicable, I have modified or added tests which pass locally.
  • I have added necessary documentation (if appropriate).
  • I have verified that my changes render correctly in RTL (if appropriate).
  • I have manually reviewed all AI generated code.

How to review (Optional)

  • Key files/areas to focus on: libs/accounts/passkey/src/lib/virtual-authenticator.ts
  • Suggested review order: a4fdafaa35 (entry point) → authenticator → polyfill
  • Risky or complex parts: all test-only; derivePrfOutput is deterministic by construction and is not a real KDF

Screenshots (Optional)

Please attach the screenshots of the changes made in case of change in user interface.

Other information (Optional)

Any other information that is important to this pull request.

This comment was marked as outdated.

@vpomerleau
vpomerleau force-pushed the FXA-14268 branch 2 times, most recently from 14b17a7 to f3bc99f Compare August 28, 2026 00:30
@vpomerleau
vpomerleau requested a balanced review from Copilot August 31, 2026 16:46

This comment was marked as outdated.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated 1 comment.

Suppressed comments (2)

libs/accounts/passkey/src/lib/virtual-authenticator.ts:270

  • A PRF-capable registration still emits flags UP | AT | UV only and appends no authenticator-extension CBOR. That contradicts the stated hmac-secret registration support and lets tests produce prf.enabled: true without the corresponding ED flag and hmac-secret: true authenticator output. Set ED and append that CBOR output when PRF is requested and supported.
    const flags = Buffer.from([0x41 | uvFlag]); // UP + AT (+ UV unless suppressed)

libs/accounts/passkey/src/lib/virtual-authenticator.ts:149

  • The advertised per-UV-state derivation is explicitly not implemented here: userVerified never reaches prfSecret or derivePrfOutput, so UV and non-UV assertions return identical PRF bytes. Either incorporate UV state into the derivation and cover both states, or update the PR contract to document that this test authenticator intentionally models only the UV output.
 * Not keyed on UV state, unlike CTAP 2.1: FxA requires UV at both ceremonies
 * and rejects a no-UV assertion server-side, so there is no reachable no-UV
 * output to model.

Comment thread libs/accounts/passkey/src/lib/virtual-authenticator.ts
@vpomerleau
vpomerleau marked this pull request as ready for review August 31, 2026 20:32
@vpomerleau
vpomerleau requested a review from a team as a code owner August 31, 2026 20:32
Comment thread packages/functional-tests/lib/passkeyPolyfill.ts Outdated
Comment thread libs/accounts/passkey/src/lib/virtual-authenticator.ts Outdated
Comment thread libs/accounts/passkey/src/lib/virtual-authenticator.ts Outdated
Because:
- The virtual authenticator is test-only, but the package barrel exported it,
  so anything importing @fxa/accounts/passkey could reach it.
- The PRF work adds derivePrfOutput, which looks like a key-derivation function
  and should not sit one autocomplete away from production passkey code.

This commit:
- Adds a `@fxa/accounts/passkey/testing` entry point holding the fake.
- Drops the virtual authenticator from the package barrel.
- Repoints the auth-server remote spec at the new entry point.
- Maps the subpath ahead of the greedy accounts pattern in auth-server's jest
  config, which would otherwise resolve it under `passkey/testing/src`.
Because:
- Nothing in the test stack could produce a PRF output, so the kB wrap work
  could not be tested above the unit layer.
- The adapter spec hand-patched clientExtensionResults to route around the gap,
  leaving the fake's PRF path with no coverage at all.

This commit:
- Returns a deterministic per-credential PRF output at assertion, keyed on the
  eval salt the server sent.
- Reports `prf.enabled` at registration, the capability flag the server records.
- Models an authenticator with no PRF support via `prfSupported: false`.
- Returns no output for an eval carrying no salt, rather than throwing.
- Drives the adapter spec's two prfEnabled cases through the real path,
  retiring its hand-patched clientExtensionResults.
Because:
- The browser shim dropped `extensions`, so no eval salt ever reached the
  virtual authenticator and no output reached page code.
- Page code needs the output as an ArrayBuffer, as a real browser returns it —
  binary outputs are what keep kB out of the request body.

This commit:
- Forwards the PRF eval salt to Node and decodes the output to an ArrayBuffer.
- Imports the fake through the testing entry point rather than a deep relative
  path into another project's src.
- Adds two tests covering the browser shim seam, the one part of the polyfill
  no unit test can reach.
- Declares the Nx dependency on `accounts-passkey`.

Closes #FXA-14268
@vpomerleau
vpomerleau merged commit 1dd9ab3 into main Sep 2, 2026
17 of 19 checks passed
@vpomerleau
vpomerleau deleted the FXA-14268 branch September 2, 2026 18:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants