Skip to content

feat(passkeys): implement sign-in ceremony on Index and Signin pages#20575

Draft
vpomerleau wants to merge 4 commits into
mainfrom
FXA-13099
Draft

feat(passkeys): implement sign-in ceremony on Index and Signin pages#20575
vpomerleau wants to merge 4 commits into
mainfrom
FXA-13099

Conversation

@vpomerleau
Copy link
Copy Markdown
Contributor

@vpomerleau vpomerleau commented May 11, 2026

Because

  • We need to wire the passkey WebAuthn ceremony to the passkey button introduced in FXA-13487 so users can sign in with a passkey from the Index and Signin pages.

This pull request

  • Adds usePasskeySignIn hook owning the WebAuthn ceremony, error categorisation, Sync merge gate, account persistence, and post-auth routing. Validates the accountProfile response before relying on email, and sanitises Sentry captures so server-error responses cannot leak PII.
  • Wires the hook into Index and Signin; plumbs authClient and finishOAuthFlowHandler through the Index container.
  • Mounts /signin/passkey/fallback as a temporary stand-in for FXA-13100; hides the passkey button on Sync entry-points behind the same TODO.
  • Surfaces a tailored "passkey not recognized" banner when the server returns PASSKEY_NOT_FOUND (errno 224); does not report to Sentry since it is an expected divergence between server and authenticator state.
  • Fixes the auth-server passkey route to return sessionToken.data instead of .id so the client can Hawk-sign subsequent requests.
  • Enables passkeyAuthenticationEnabled in local.json-dist (dev only; production flag stays off via the convict default).
  • Adds functional tests covering the passkey sign-in happy, cancel, and PASSKEY_NOT_FOUND paths.

Issue that this pull request solves

Closes: FXA-13099

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

Other information

  • Telemetry: Glean events for this flow are intentionally omitted here. FXA-13475 owns the passkey sign-in telemetry design (surface-scoped email.* / login.* events plus password-page events) and will instrument both pages once this lands.
  • Sync end-to-end: the passkey button is currently hidden on Sync entry-points via !integration.isSync(). FXA-13100 will replace the temporary SetPasswordContainer mount at /signin/passkey/fallback with a container that derives Sync keys via verifyPasswordAfterPasskey; the Sync button can re-enable then.
  • Auth-server fix: the sessionToken.id → .data change in passkeys.ts is a real bug latent in main since 5a17be0bb7 — every passkey sign-in via the existing route would have failed downstream Hawk-authenticated calls. Worth filing a separate bug to track for backport visibility.

…apper

Because:

- The Mozilla design system replaces the circular third-party auth
  buttons with a unified box-style layout.
- Index/Signin/Signup need structural groundwork (composition,
  visibility gating, error banner slot) before FXA-13099 wires the
  passkey ceremony.

This commit:

- Adds `BoxButton`, a reusable presentational primitive.
- Adds `AlternativeAuthOptions`, composing divider + optional passkey
  button + `ThirdPartyAuth` row + inline error banner. Driven by
  `showThirdPartyAuth`, `showPasskeySignin`, and `isStandalone` props.
- Adds a `'box'` variant to `ThirdPartyAuth`; refactors
  `ButtonPasskeySignin` to wrap `BoxButton`.
- Wires the wrapper into Index, Signin, and Signup. Moves the
  `thirdPartyAuth.loginNoPwView` Glean event to Signin and restores it
  to a reachable state for the linked-no-password case.

Closes: FXA-13487
Because:

* The implementation matched an outdated design

This commit:

* Update the error messsage, and include a support link in the error component
* Show the updated message in an alert bar, not inline

Closes #FXA-13683
…ng state

Because:

- The "Cancel" button on the "Creating passkey…" loading page navigated back
to settings without any feedback. When a credential manager popup (e.g.,
Bitwarden) is dismissed via focus loss, the WebAuthn ceremony stays pending
and Cancel is the user's only escape — but it returned silently, leaving
no confirmation that cancellation was processed.

This commit:

- Shows the standard cancellation banner ("Passkey setup was canceled. Try
again.") in the alert bar before navigating back, mirroring the feedback
the user gets when the ceremony itself reports a cancel/timeout.

Closes #FXA-13681
Because:
We need to wire the passkey WebAuthn ceremony to the passkey button
introduced in FXA-13487.

This commit:
 * Adds a usePasskeySignIn hook driving the ceremony, error handling,
   Sync merge gate, and post-auth routing, and wires it into the Index
   and Signin pages.
 * Mounts /signin/passkey/fallback as a temporary stand-in until
   FXA-13100 lands the real password-fallback page.
 * Fixes the auth-server passkey route to return sessionToken.data
   instead of .id so the client can Hawk-sign subsequent requests.
 * Enables passkeyAuthenticationEnabled in local.json-dist.
 * Adds functional tests covering the passkey sign-in happy, cancel,
   and PASSKEY_NOT_FOUND paths.

Closes #FXA-13099
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.

1 participant