Skip to content

FXA-13463: The “Bad request” page is displayed for account with 2Fa that tried to use backup codes at sign in#20600

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

FXA-13463: The “Bad request” page is displayed for account with 2Fa that tried to use backup codes at sign in#20600
vbudhram wants to merge 1 commit into
mainfrom
fxa-13463

Conversation

@vbudhram
Copy link
Copy Markdown
Contributor

@vbudhram vbudhram commented May 14, 2026

No description provided.

When a user with 2FA enabled follows a passwordless (OTP email code)
sign-in flow and clicks "Trouble entering code?" on the TOTP page, the
recovery code and recovery phone containers were calling useOAuthKeysCheck
without the isPasswordlessFlow skip flag. Passwordless users never derive
keys (no password was entered), so the check incorrectly produced a
TRY_AGAIN error that rendered the "Bad Request" page instead of the
backup authentication code or recovery phone page.

The fix mirrors what SigninTotpCodeContainer already does: pass
isSignInWithThirdPartyAuth || isPasswordlessFlow as the skip flag.
Copilot AI review requested due to automatic review settings May 14, 2026 18:14
@vbudhram vbudhram requested a review from a team as a code owner May 14, 2026 18:14
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

Fixes an FxA Settings sign-in regression where passwordless (OTP email) users with 2FA could hit an OAuth keys “TRY_AGAIN” check when navigating to backup-code or recovery-phone flows, resulting in a “Bad Request” error page instead of the intended recovery UI.

Changes:

  • Skip the OAuth keys check in SigninRecoveryCode and SigninRecoveryPhone when signinState.isPasswordlessFlow is true (matching existing TOTP behavior).
  • Add unit tests asserting the passwordless skip flag is forwarded to useOAuthKeysCheck and that recovery components render when the check is skipped.
  • Refactor/mocking updates in SigninRecoveryCode tests to support the new assertions.

Reviewed changes

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

File Description
packages/fxa-settings/src/pages/Signin/SigninRecoveryPhone/container.tsx Skip OAuth keys check for passwordless recovery-phone sign-in flow.
packages/fxa-settings/src/pages/Signin/SigninRecoveryPhone/container.test.tsx Add tests for passwordless skip behavior and rendering path.
packages/fxa-settings/src/pages/Signin/SigninRecoveryCode/container.tsx Skip OAuth keys check for passwordless recovery-code sign-in flow.
packages/fxa-settings/src/pages/Signin/SigninRecoveryCode/container.test.tsx Add/migrate tests to cover passwordless skip behavior and rendering path.

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

Comment on lines +263 to +277
it('renders the recovery phone component when keys check is skipped for passwordless flow', () => {
(useOAuthKeysCheck as jest.Mock).mockImplementationOnce(
(_integration: any, _kft: any, _ubk: any, skipKeysCheck: boolean) => ({
oAuthKeysCheckError: skipKeysCheck
? null
: { errno: 1, message: 'TRY_AGAIN' },
})
);
mockReachRouter('/signin_recovery_phone', {
signinState: { ...mockSigninLocationState, isPasswordlessFlow: true },
lastFourPhoneDigits: '1234',
});
renderSigninRecoveryPhoneContainer();
expect(currentPageProps).toBeDefined();
});
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.

Seems like good testing feedback.

Copy link
Copy Markdown
Contributor

@dschom dschom left a comment

Choose a reason for hiding this comment

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

LGTM. The co-pilot feedback is easy to address and worth it.

Comment on lines +263 to +277
it('renders the recovery phone component when keys check is skipped for passwordless flow', () => {
(useOAuthKeysCheck as jest.Mock).mockImplementationOnce(
(_integration: any, _kft: any, _ubk: any, skipKeysCheck: boolean) => ({
oAuthKeysCheckError: skipKeysCheck
? null
: { errno: 1, message: 'TRY_AGAIN' },
})
);
mockReachRouter('/signin_recovery_phone', {
signinState: { ...mockSigninLocationState, isPasswordlessFlow: true },
lastFourPhoneDigits: '1234',
});
renderSigninRecoveryPhoneContainer();
expect(currentPageProps).toBeDefined();
});
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.

Seems like good testing feedback.

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