Skip to content

test(functional): add passkey signin + AMO AAL2 functional coverage#20645

Open
vbudhram wants to merge 1 commit into
mainfrom
fxa-13103
Open

test(functional): add passkey signin + AMO AAL2 functional coverage#20645
vbudhram wants to merge 1 commit into
mainfrom
fxa-13103

Conversation

@vbudhram
Copy link
Copy Markdown
Contributor

Because

  • The passkey signin work in FXA-13101 lacked Playwright coverage for the OAuth flows it touches, including the AAL2 divert that prevents AMO's profile-based bounce loop
  • 123done's existing "Require 2FA" toggle only exercises the session-level AAL2 check; the AMO-style profile-level AMR check (where availableAuthenticationMethods excludes webauthn) had no test fixture

This pull request

  • Adds passkey signin coverage in passkey-signin.spec.ts: email-first sign-in, /signin after submitting an email, error banners, non-AAL2 RPs, AAL2 RPs (with and without TOTP), and the passkeySetPassword.spec.ts passwordless flow
  • Adds two AMO-style profile-AAL2 tests (gated to the local target): a passkey-only user is diverted to /inline_totp_setup before the OAuth grant, and a passkey+TOTP user completes straight to the RP
  • Extends 123done with a Sign In (Require Profile AAL2) toggle that mirrors AMO: checks profile.twoFactorAuthentication after the grant and bounces back to FxA once if the account lacks TOTP. Surfaces both session-AAL2 (🔒) and account-AAL2 (🛡) on the post-auth page

Issue that this pull request solves

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

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

Depends on: FXA-13101 (PR #20635). The AMO profile-AAL2 tests rely on the FxA-side divert in packages/fxa-settings/src/pages/Signin/utils.ts. This PR should land after that one.

How to test locally:

cd packages/functional-tests
yarn test-local --grep "passkey sign-in"
yarn test-local --grep "AMO-style profile AAL2"

The two AMO tests skip on stage/prod (target.name !== 'local') because the /api/profile_aal2 toggle lives only in local 123done.

@vbudhram vbudhram marked this pull request as ready for review May 27, 2026 18:07
@vbudhram vbudhram requested a review from a team as a code owner May 27, 2026 18:07
Copilot AI review requested due to automatic review settings May 27, 2026 18:07
@vbudhram vbudhram self-assigned this May 27, 2026
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

This PR expands Playwright functional coverage for passkey sign-in flows (including Sync OAuth edge-cases) and adds an AMO-like “profile AAL2” enforcement mode to the 123done test relier to validate the FxA-side divert behavior for passkey-only accounts.

Changes:

  • Add new functional tests for passkey sign-in across email-first, Sync OAuth fallback/set-password flows, and AAL2 + profile-AAL2 scenarios.
  • Extend the passkey polyfill with a “corrupt assertion” mode to exercise invalid-signature server handling.
  • Update 123done to support “Require Profile AAL2” (post-grant profile check + one-bounce behavior) and surface account-level AAL2 state in UI + test page object helpers.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
packages/functional-tests/tests/passkeyAuth/passkeySetPassword.spec.ts Adds Sync OAuth coverage for passwordless+passkey routing through /post_verify/passkey/set_password (with/without TOTP).
packages/functional-tests/tests/passkeyAuth/passkeyPasswordFallback.spec.ts Reworks Sync passkey fallback test to be UI-driven and adds TOTP-enrolled “no re-prompt” coverage.
packages/functional-tests/tests/passkeyAuth/passkey-signin.spec.ts Adds broad passkey sign-in functional coverage, including AAL2 and AMO-style profile-AAL2 scenarios.
packages/functional-tests/pages/relier.ts Adds relier actions and badge checks for the new profile-AAL2 toggle and account/session AAL2 markers.
packages/functional-tests/lib/passkeyPolyfill.ts Adds a “corrupt” mode that tampers with the assertion signature for negative-path testing.
packages/123done/static/js/123done.js Displays account-level AAL2 marker and wires up the new “Require Profile AAL2” button.
packages/123done/static/index.html Adds the “Sign In (Require Profile AAL2)” button.
packages/123done/server.js Exposes account_aal2 via /api/auth_status for UI/tests.
packages/123done/oauth.js Adds /api/profile_aal2 flow and profile-based post-grant bounce logic to mirror AMO-style enforcement.

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

Comment on lines +410 to +412
await clearSession(page);
await page.goto(target.contentServerUrl);

Comment on lines 70 to 72
await clearSession(page);
await page.goto(target.contentServerUrl);

@vpomerleau vpomerleau self-requested a review May 27, 2026 18:27
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.

Tests cases look good and thorough on first pass 💎 I'll have a closer look and do some manual testing after the weekly meeting, mainly for the 123done flows

@@ -42,6 +42,12 @@
>
Sign In (Require 2FA)
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.

I see the difference as Require AAL2 session vs Require 2FA-enabled account, but not sure if this would be clear for others? Either option feels like it needs more explanation 😅

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.

It looks like the labels might be reversed? This one here requires an AAL2 session and the one below require 2FA-enabled account

return account;
}

function findPasswordlessPassword(
Copy link
Copy Markdown
Contributor

@vpomerleau vpomerleau May 28, 2026

Choose a reason for hiding this comment

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

findPasswordlessPassword - just from the name that's a tad odd. Looks like the test account tracker artificially creates a password before the account actually has one set? Feels like that would be worth a follow-up cleanup to more closely align with real user flows.

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.

Ok, I see this is now returned by the testAccountTracker now. Still odd, but out of scope here.

Comment thread packages/functional-tests/tests/passkeyAuth/passkeyPasswordFallback.spec.ts Outdated
});
});

test('shows the passkey button on /signin even when the account has no passkeys (no hasPasskeys leak)', async ({
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.

Is this necessary? We're guarding against state that isn't passed in /account/status?

Comment thread packages/123done/oauth.js
Adds Playwright coverage for the passkey signin flow introduced in
FXA-13101, including:

- Passkey-only sign-in into a non-AAL2 RP and into an RP that requires
  AAL2 (account with TOTP enrolled and without).
- The AMO-style profile-AAL2 divert: a passkey-only user hitting an RP
  that enforces profile-level AAL2 is sent to /inline_totp_setup before
  the OAuth grant completes, preventing AMO's bounce-loop.
- Passkey + password fallback for Sync, and the passwordless
  set-password flow.

Extends 123done with a Sign In (Require AAL2 Session) toggle that
mirrors AMO's post-grant profile.twoFactorAuthentication check and
bounces back to FxA once if the account lacks TOTP. The two AMO tests
are gated to the local target (the toggle is local-only).
);
});

test('passwordless+passkey signin into Sync routes through /post_verify/passkey/set_password', async ({
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.

Github isn't flagging a merge conflict (or test failure?), but this route was standardized to post_verify/set_password for all sign in methods

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