Skip to content

add optional passkey signin and AMO AAL2 enforcement#20635

Merged
vbudhram merged 1 commit into
mainfrom
fxa-13101
May 27, 2026
Merged

add optional passkey signin and AMO AAL2 enforcement#20635
vbudhram merged 1 commit into
mainfrom
fxa-13101

Conversation

@vbudhram
Copy link
Copy Markdown
Contributor

@vbudhram vbudhram commented May 21, 2026

Because

  • Users with an enrolled passkey could not use it from the email-first signin flow without typing their password first, undermining the value of passkeys as a primary authentication method
  • AMO and similar RPs perform a profile-level AAL2 check that excludes webauthn from availableAuthenticationMethods, so a passkey-only user satisfied session AAL2 yet was bounced back to FxA in a redirect loop instead of being prompted to enrol TOTP

This pull request

  • Adds a "Continue with passkey" button to Signin/index.tsx (password-entry page) and SigninAlternativeAuthOptions (email-first), gated by the passkeyAuthenticationEnabled feature flag
  • Shows the button unconditionally to preserve the privacy invariant that /account/status does not leak passkey enrolment
  • Adds unit coverage in signin-flow.test.tsx and utils.test.ts (passkey-session AAL2 gate cases) plus stories for the new alternative-auth UI

Issue that this pull request solves

Closes: https://mozilla-hub.atlassian.net/browse/FXA-13101

Checklist

  • 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.

Other information

Companion PR: FXA-13103 adds the Playwright coverage for these flows (passkey signin paths + AMO profile-AAL2 divert) and a 123done toggle that mirrors AMO's profile-based enforcement. It should land after this one.

How to test

  1. Enable feature flags passkeysEnabled, passkeyRegistrationEnabled, passkeyAuthenticationEnabled
  2. Register a passkey on a fresh account via Settings
  3. Sign out, return to /, then click "Continue with passkey" from email-first or after submitting an email
  4. From a 123done acr_values=AAL2 flow on a passkey-only account, sign in with passkey, should land on /inline_totp_setup, not the RP

Comment thread packages/fxa-settings/src/lib/passkeys/signin-flow.ts Outdated
@vbudhram vbudhram force-pushed the fxa-13101 branch 2 times, most recently from ba74b4a to 72a9f2d Compare May 22, 2026 16:17
@vbudhram vbudhram self-assigned this May 22, 2026
@vbudhram vbudhram marked this pull request as ready for review May 22, 2026 18:12
@vbudhram vbudhram requested a review from a team as a code owner May 22, 2026 18:12
Copilot AI review requested due to automatic review settings May 22, 2026 18:12
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Enforces “passkey required” sign-in policy for accounts that have enrolled a passkey by blocking passwordless OTP endpoints server-side and teaching the Settings content-server UI (and tests) to redirect/show appropriate banners and routing for passkey-only scenarios (including AAL2/TOTP routing for certain OAuth RPs).

Changes:

  • Auth server: gate /account/passwordless/send_code and /confirm_code behind a “no passkey enrolled” check and introduce PASSKEY_AUTHENTICATION_REQUIRED (errno 233).
  • Settings UI: add mustUsePasskey redirect/banner handling; hide unsupported passkey UI on browsers lacking WebAuthn L3; add AAL2→TOTP enrollment diversion for passkey sessions.
  • Tests: add/expand unit + functional passkey test coverage and extend the passkey polyfill with a corruption/tampering mode.

Reviewed changes

Copilot reviewed 27 out of 27 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
packages/fxa-settings/src/pages/Signin/utils.ts Diverts AAL2-requiring OAuth web flows to inline TOTP setup for passkey sessions lacking TOTP.
packages/fxa-settings/src/pages/Signin/utils.test.ts Adds unit coverage for the new passkey-session AAL2/TOTP diversion logic.
packages/fxa-settings/src/pages/Signin/SigninPasswordlessCode/index.stories.tsx Updates/expands Storybook variants for passkey-enabled passwordless code page.
packages/fxa-settings/src/pages/Signin/SigninPasswordlessCode/container.tsx Redirects to /signin with mustUsePasskey when errno 233 is returned by OTP send.
packages/fxa-settings/src/pages/Signin/SigninPasswordlessCode/container.test.tsx Adds test coverage for the errno 233 redirect behavior.
packages/fxa-settings/src/pages/Signin/interfaces.ts Adds mustUsePasskey, plus navigation fields for passkey-session + TOTP status.
packages/fxa-settings/src/pages/Signin/index.tsx Adds mustUsePasskey banners, hides password form when required, gates passkey button on WebAuthn L3.
packages/fxa-settings/src/pages/Signin/index.test.tsx Adds banner tests for mustUsePasskey supported/unsupported browser scenarios.
packages/fxa-settings/src/pages/Signin/index.stories.tsx Updates passkey-related Signin story variants (including Sync/cached paths).
packages/fxa-settings/src/pages/Signin/container.tsx Wires mustUsePasskey from location state into the Signin decider flow.
packages/fxa-settings/src/pages/Signin/components/SigninDecider/index.tsx Plumbs mustUsePasskey into Signin and SigninAlternativeAuthOptions.
packages/fxa-settings/src/pages/Signin/components/SigninAlternativeAuthOptions/index.tsx Adds mustUsePasskey banners and gates passkey button on WebAuthn L3 support.
packages/fxa-settings/src/pages/Signin/components/SigninAlternativeAuthOptions/index.test.tsx Adds tests for mustUsePasskey banners and WebAuthn L3 support conditions.
packages/fxa-settings/src/pages/Signin/components/SigninAlternativeAuthOptions/index.stories.tsx New Storybook file for linked-passwordless alternative auth options (with passkey variants).
packages/fxa-settings/src/pages/Index/index.tsx Gates Index page passkey sign-in button on WebAuthn Level 3 support.
packages/fxa-settings/src/lib/passkeys/signin-flow.ts Surfaces account TOTP status for AAL2 OAuth web RPs to support TOTP setup diversion.
packages/fxa-settings/src/lib/passkeys/signin-flow.test.tsx Adds unit tests covering accountHasTotp propagation behavior.
packages/fxa-settings/src/lib/auth-errors/auth-errors.ts Adds UI mapping for PASSKEY_AUTHENTICATION_REQUIRED (errno 233).
packages/fxa-auth-server/lib/routes/passwordless.ts Adds passkey enrollment gate to passwordless OTP endpoints; fail-closed on lookup errors.
packages/fxa-auth-server/lib/routes/passwordless.spec.ts Adds tests for passkey gate ordering and fail-closed behavior.
packages/functional-tests/tests/passkeyAuth/passkeySetPassword.spec.ts New E2E for passwordless+passkey → Sync routing to set-password.
packages/functional-tests/tests/passkeyAuth/passkeyPasswordFallback.spec.ts Refactors E2E to drive Sync passkey fallback via real UI flow; adds TOTP variant.
packages/functional-tests/tests/passkeyAuth/passkeyEnforcement.spec.ts New E2E for OTP enforcement redirect + passkey sign-in success path.
packages/functional-tests/tests/passkeyAuth/passkey-signin.spec.ts Expands E2E coverage for AAL2/TOTP combinations and unsupported-browser behavior.
packages/functional-tests/lib/passkeyPolyfill.ts Adds corrupt mode to simulate invalid-signature assertions.
libs/accounts/errors/src/constants.ts Adds errno 233 constant.
libs/accounts/errors/src/app-error.ts Adds passkeyAuthenticationRequired() AppError factory.
Comments suppressed due to low confidence (2)

packages/fxa-settings/src/pages/Signin/index.tsx:329

  • The new FTL id signin-passkey-unsupported-browser-banner is referenced here but does not appear to be defined in packages/fxa-settings/src/pages/Signin/en.ftl, so it will fall back to the hardcoded English string and won’t be localizable. Please add the string to the Signin FTL file (and other locales via l10n pipeline as appropriate).
              : ftlMsgResolver.getMsg(
                  'signin-passkey-unsupported-browser-banner',
                  'Sign-in is not supported on this browser. Use a browser that supports passkeys to continue.'
                ),
          }}

packages/fxa-settings/src/pages/Signin/components/SigninAlternativeAuthOptions/index.tsx:113

  • The new FTL id signin-passkey-unsupported-browser-banner is referenced here but does not appear to be defined in packages/fxa-settings/src/pages/Signin/en.ftl, so it will fall back to the hardcoded English string and won’t be localizable. Please add the string to the Signin FTL file (and other locales via l10n pipeline as appropriate).
              : ftlMsgResolver.getMsg(
                  'signin-passkey-unsupported-browser-banner',
                  'Sign-in is not supported on this browser. Use a browser that supports passkeys to continue.'
                ),
          }}

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread packages/fxa-auth-server/lib/routes/passwordless.ts Outdated
Comment thread packages/fxa-settings/src/pages/Signin/index.tsx Outdated
Comment thread packages/fxa-settings/src/pages/Signin/components/SigninCached/index.tsx Outdated
Comment thread packages/fxa-settings/src/lib/passkeys/signin-flow.test.tsx
} from '../../../mocks';
import { MozServices } from '../../../../lib/types';

// Renders for linked-passwordless users: only path forward is alt auth.
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.

Thanks for adding these missing stories

Comment thread packages/fxa-settings/src/lib/passkeys/signin-flow.ts Outdated
Copy link
Copy Markdown
Contributor

@vpomerleau vpomerleau left a comment

Choose a reason for hiding this comment

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

Tested locally and this is working well 🎉 The only change I would request (vs the other questions) is removing the change to SigninCached page and updating the PR description since it no longer matches the changeset.

@vbudhram vbudhram changed the title feat(auth): require passkey for accounts with passkey enrolled add optional passkey signin and AMO AAL2 enforcement May 26, 2026
</div>
</form>

<AlternativeAuthOptions
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.

Can remove?

Adds a "Continue with passkey" button to the email-first signin flow,
gated by the passkeyAuthenticationEnabled feature flag. The button is
shown unconditionally to preserve the privacy invariant that
/account/status does not signal passkey enrolment.

Routes passkey-authenticated sessions through handleNavigation with an
isPasskeySession flag so the OAuth signin path can divert AAL2-requiring
RPs (AMO-style) to /inline_totp_setup when the account has no TOTP.
This matches AMO's profile-based AMR check, which excludes webauthn from
availableAuthenticationMethods even though the passkey session itself
satisfies session-level AAL2.
Copy link
Copy Markdown
Contributor

@vpomerleau vpomerleau left a comment

Choose a reason for hiding this comment

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

Thanks for the edits, LGTM.

PR description/title doesn't quite align and mentions changes that aren't in this diff, would be good to update for posterity. 🙏

@vbudhram vbudhram merged commit 9892cf6 into main May 27, 2026
21 checks passed
@vbudhram vbudhram deleted the fxa-13101 branch May 27, 2026 17:07
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