Skip to content

refactor(settings): split the passkey sign-in hook into steps - #21249

Draft
vpomerleau wants to merge 3 commits into
FXA-13151from
FXA-14557
Draft

vpomerleau wants to merge 3 commits into
FXA-13151from
FXA-14557

Conversation

@vpomerleau

Copy link
Copy Markdown
Contributor

Because

  • usePasskeySignIn ran the WebAuthn ceremony, the account lookup, the wrap-offer probe and navigation in one 300-line click handler, so every branch could only be tested by mounting the whole hook.
  • The passwordless Sync sign-in adds another branch; splitting first keeps that diff reviewable.

This pull request

  • Moves the hook from lib/passkeys/signin-flow.ts to lib/hooks/usePasskeySignIn.
  • Extracts runPasskeyAssertion (ceremony, PRF handling, server completion, WebAuthn error banners) to lib/passkeys/signin-assertion.ts.
  • Extracts resolveSignedInAccount (account lookup, merge gate, persistence) and stashPasskeyWrapOffer (stored-wrap probe and opt-in stash).
  • Adds a shared useMounted hook.
  • Adds direct unit tests for the three steps and trims the same cases from the hook test.

Issue that this pull request solves

Closes: FXA-14557

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: lib/hooks/usePasskeySignIn/index.ts reads as the flow; compare it against the three step modules.
  • Suggested review order: commit by commit. The first commit is a pure move (git show -M), the second is the extraction, the third is tests only.
  • Risky or complex parts: completeSignIn in the hook carries the WebChannel ordering and performNavigation rules verbatim from the old inline call.

Screenshots (Optional)

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

Other information (Optional)

No behaviour change. Stacked on FXA-13151 and must merge before the passwordless Sync sign-in PR, which rebases onto it.

Because:
- The hook returned React elements and mixed three progress flags.
- Surface handling was spread over three switches on one union.

This commit:
- Moves usePasskeySignIn to lib/hooks/usePasskeySignIn; it now returns banner state.
- Collapses isLoading/isNavigating/inFlight into one status plus a re-entry ref.
- Replaces the surface switches with one PASSKEY_SIGNIN_SURFACES table.
- Keeps the FTL-bound banner builders in lib/passkeys/signin-flow.ts.
- Callers render the banner themselves.
Because:
- usePasskeySignIn's click handler ran the WebAuthn ceremony, the account
  lookup, the wrap-offer probe and the navigation in one 300-line closure,
  so each branch could only be tested by mounting the whole hook.

This commit:
- Extract runPasskeyAssertion (ceremony, PRF handling, server completion,
  WebAuthn error banners) to lib/passkeys/signin-assertion.ts.
- Extract resolveSignedInAccount (account lookup, merge gate, persistence)
  to lib/passkeys/signin-account.ts.
- Extract stashPasskeyWrapOffer and the stored-wrap probe to
  lib/passkeys/wrap/offer.ts.
- Add a shared useMounted hook; move PasskeySignInAuthClient to signin-flow.

Closes #FXA-14557
Because:
- The extracted steps can be tested without mounting the hook, and the
  hook test was carrying their branch tables.

This commit:
- Add signin-assertion, signin-account and wrap/offer tests covering the
  WebAuthn error banners, PRF handling, service resolution, account lookup,
  merge gate and wrap-offer probe.
- Trim the same cases from the usePasskeySignIn test, keeping wiring and
  status coverage.

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.

🔵 Needs a closer look

This security-sensitive authentication refactor spans ceremony, persistence, navigation, and sensitive-data cleanup, with an unresolved regression-coverage gap.

Pull request overview

Refactors passkey sign-in into independently testable steps while preserving existing behavior.

Changes:

  • Extracts assertion, account resolution, and wrap-offer logic.
  • Moves orchestration into usePasskeySignIn.
  • Updates consumers and focused tests.
File summaries
File Description
packages/fxa-settings/src/pages/Signin/SigninPasswordlessCode/index.tsx Uses the new hook and banner model.
packages/fxa-settings/src/pages/Signin/index.tsx Uses the new hook and banner model.
packages/fxa-settings/src/pages/Signin/components/SigninAlternativeAuthOptions/index.tsx Updates alternative sign-in integration.
packages/fxa-settings/src/pages/Index/index.tsx Updates index-page passkey integration.
packages/fxa-settings/src/lib/passkeys/wrap/offer.ts Extracts wrap-offer handling.
packages/fxa-settings/src/lib/passkeys/wrap/offer.test.ts Tests wrap-offer decisions.
packages/fxa-settings/src/lib/passkeys/signin-flow.ts Retains shared passkey types and helpers.
packages/fxa-settings/src/lib/passkeys/signin-flow.test.tsx Trims tests moved to extracted modules.
packages/fxa-settings/src/lib/passkeys/signin-assertion.ts Extracts WebAuthn assertion handling.
packages/fxa-settings/src/lib/passkeys/signin-assertion.test.ts Tests assertion behavior.
packages/fxa-settings/src/lib/passkeys/signin-account.ts Extracts account lookup and persistence.
packages/fxa-settings/src/lib/passkeys/signin-account.test.ts Tests account resolution.
packages/fxa-settings/src/lib/hooks/usePasskeySignIn/index.ts Orchestrates the sign-in steps.
packages/fxa-settings/src/lib/hooks/usePasskeySignIn/index.test.tsx Tests hook orchestration.
packages/fxa-settings/src/lib/hooks/useMounted/index.ts Adds mounted-state tracking.
packages/fxa-settings/src/lib/hooks/index.ts Exports the mounted-state hook.
Review details
  • Files reviewed: 16/16 changed files
  • Comments generated: 1
  • Review effort level: Balanced

💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

const inFlight = useRef(false);
// A ceremony the user walked away from must not leave material behind,
// nor overwrite what a ceremony started on the next page has stashed.
const mounted = useMounted();
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.

2 participants