Skip to content

[Due for payment 2026-03-19] [$250] Web - Login - 2nd tab change to Magic code expired page after enter incorrect 2FA code #79647

Closed

Description

@jponikarchuk

If you haven’t already, check out our contributing guidelines for onboarding and email contributors@expensify.com to request to join our Slack channel!


Version Number: v9.3.2-1
Reproducible in staging?: Yes
Reproducible in production?: Yes
If this was caught during regression testing, add the test name, ID and link from BrowserStack: https://test-management.browserstack.com/projects/2219752/test-runs/TR-2966/folder/13176924/41237550/1125946905?sort=%2Bidentifier
Email or phone of affected tester (no customers): applausetester+vq@applause.expensifail.com
Issue reported by: Applause Internal Team
Bug source: Exploratory - Significant User Experience Deterioration
Device used: Windows 10/Chrome
App Component: User Settings

Action Performed:

  1. Log in to NewDot with the account that has 2FA setup
  2. Navigate to email and locate the magic link - change to staging if needed
  3. Open a new tab and navigate to the staging link
  4. Navigate back to the original tab - Keep the second tab open
  5. Enter the incorrect 2FA code
  6. Navigate to the secondary tab

Expected Result:

The two-factor authentication required page remains on the 2nd tab

Actual Result:

2nd tab change to Magic code expired page

Workaround:

Unknown

Platforms:

  • Android: App
  • Android: mWeb Chrome
  • iOS: App
  • iOS: mWeb Safari
  • iOS: mWeb Chrome
  • Windows: Chrome
  • MacOS: Chrome / Safari

Screenshots/Videos

1.mp4

View all open jobs on GitHub

Upwork Automation - Do Not Edit
  • Upwork Job URL: https://www.upwork.com/jobs/~022011939480797251822
  • Upwork Job ID: 2011939480797251822
  • Last Price Increase: 2026-02-12
  • Automatic offers:
    • MobileMage | Contributor | 110513949
Issue OwnerCurrent Issue Owner: @shubham1206agra

Activity

  1. added
    BugSomething is broken. Auto assigns a BugZero manager.
    on Jan 15, 2026
  2. melvin-bot commented on Jan 15, 2026

    @melvin-bot

    Triggered auto assignment to @twisterdotcom (Bug), see https://stackoverflow.com/c/expensify/questions/14418 for more details. Please add this bug to a GH project, as outlined in the SO.

  3. MobileMage commented on Jan 15, 2026

    @MobileMage
    Contributor

    Proposal

    Please re-state the problem that we are trying to solve in this issue.

    When a user opens a magic link in one tab and then opens a second tab to the same staging URL, if they enter an incorrect 2FA code in the first tab, the second tab unexpectedly changes to show "Magic code expired" instead of remaining on the 2FA authentication page.

    What is the root cause of that problem?

    The autoAuthState is stored in ONYXKEYS.SESSION which is shared across browser tabs via Onyx. When the 2FA validation fails in Tab 1, the signInWithValidateCode function sets autoAuthState: CONST.AUTO_AUTH_STATE.FAILED in its failureData:

    const failureData: Array<OnyxUpdate<typeof ONYXKEYS.ACCOUNT | typeof ONYXKEYS.SESSION>> = [
    {
    onyxMethod: Onyx.METHOD.MERGE,
    key: ONYXKEYS.ACCOUNT,
    value: {
    isLoading: false,
    loadingForm: null,
    },
    },
    {
    onyxMethod: Onyx.METHOD.MERGE,
    key: ONYXKEYS.SESSION,
    value: {autoAuthState: CONST.AUTO_AUTH_STATE.FAILED},
    },
    ];

    This FAILED state propagates to Tab 2 through Onyx. In ValidateLoginPage/index.website.tsx, the component unconditionally shows ExpiredValidateCodeModal whenever autoAuthState === FAILED:

    {autoAuthStateWithDefault === CONST.AUTO_AUTH_STATE.FAILED && <ExpiredValidateCodeModal />}

    The problem is that FAILED is used for both:

    1. Magic code validation failures (expired/invalid code)
    2. 2FA code validation failures

    But these are semantically different errors. If account.requiresTwoFactorAuth is true, it means the magic code was already validated successfully - the user progressed to the 2FA step. A 2FA failure should not trigger "magic code expired".

    What changes do you think we should make in order to solve the problem?

    On line 79 of ValidateLoginPage/index.website.tsx, add a condition to only show ExpiredValidateCodeModal when is2FARequired is false:

    Change from:

    {autoAuthStateWithDefault === CONST.AUTO_AUTH_STATE.FAILED && <ExpiredValidateCodeModal />}
    

    To:

    {autoAuthStateWithDefault === CONST.AUTO_AUTH_STATE.FAILED && !is2FARequired && <ExpiredValidateCodeModal />}
    

    The is2FARequired variable is already computed on line 33 from account?.requiresTwoFactorAuth. When 2FA is required, the magic code was valid, so showing "magic code expired" is incorrect regardless of what caused the FAILED state.

    What alternative solutions did you explore? (Optional)

    Adding a separate AUTO_AUTH_STATE for 2FA failures would work but is more invasive. The existing is2FARequired flag already provides the information needed to distinguish between magic code failures and 2FA failures.

  4. imadirtydog commented on Jan 15, 2026

    @imadirtydog

    Please re-state the problem that we are trying to solve in this issue.

    When a user enters an incorrect two-factor authentication code during magic link sign-in, they see the "Magic code
    expired" modal. This is misleading because the magic code isn't expired — the 2FA code was simply wrong.

    What is the root cause of that problem?

    The signInWithValidateCode function sets autoAuthState to FAILED on any failure, without distinguishing between an expired
    magic link and a failed 2FA attempt:

    {
    onyxMethod: Onyx.METHOD.MERGE,
    key: ONYXKEYS.SESSION,
    value: {autoAuthState: CONST.AUTO_AUTH_STATE.FAILED},
    },

    The ValidateLoginPage then renders ExpiredValidateCodeModal for any FAILED state:

    https://github.com/Expensify/App/blob/728784e0312b0bef5a0099f0f92fc746199de50c/src/pages/ValidateLoginPage/index.website.t
    sx#L79

    There is no separate state to represent a 2FA-specific failure, so both cases show the same expired code message.

    What changes do you think we should make in order to solve the problem?

    1. Add a new TWO_FACTOR_AUTH_FAILED value to CONST.AUTO_AUTH_STATE in src/CONST/index.ts:

      App/src/CONST/index.ts

      Lines 293 to 298 in 728784e

      AUTO_AUTH_STATE: {
      NOT_STARTED: 'not-started',
      SIGNING_IN: 'signing-in',
      JUST_SIGNED_IN: 'just-signed-in',
      FAILED: 'failed',
      },

      AUTO_AUTH_STATE: {
      NOT_STARTED: 'not-started',
      SIGNING_IN: 'signing-in',
      JUST_SIGNED_IN: 'just-signed-in',
      FAILED: 'failed',
      TWO_FACTOR_AUTH_FAILED: 'two-factor-auth-failed',
      },

    2. In signInWithValidateCode in src/libs/actions/Session/index.ts, conditionally set the failure state based on whether a
      twoFactorAuthCode was provided:

      {
      onyxMethod: Onyx.METHOD.MERGE,
      key: ONYXKEYS.SESSION,
      value: {autoAuthState: CONST.AUTO_AUTH_STATE.FAILED},
      },

    value: {autoAuthState: twoFactorAuthCode
    ? CONST.AUTO_AUTH_STATE.TWO_FACTOR_AUTH_FAILED
    : CONST.AUTO_AUTH_STATE.FAILED},

    1. Add translation keys in src/languages/en.ts and src/languages/es.ts under validateCodeModal:

      App/src/languages/en.ts

      Lines 767 to 768 in 728784e

      expiredCodeTitle: 'Magic code expired',
      expiredCodeDescription: 'Go back to the original device and request a new code',

    twoFactorAuthFailedTitle: 'Invalid two-factor authentication code',
    twoFactorAuthFailedDescription: 'The two-factor authentication code you entered is incorrect. Please try again.',

    1. Create a new TwoFactorAuthFailedModal component in src/components/ValidateCode/ with the same layout as
      ExpiredValidateCodeModal but using the new translation keys. Alternatively, we could make the ExpiredValidateCodeModal take some props and reuse the component and change its name.
    2. In ValidateLoginPage (src/pages/ValidateLoginPage/index.website.tsx), render the new modal for the new state:
      https://github.com/Expensify/App/blob/728784e0312b0bef5a0099f0f92fc746199de50c/src/pages/ValidateLoginPage/index.website.t
      sx#L79

    {autoAuthStateWithDefault === CONST.AUTO_AUTH_STATE.FAILED && }
    {autoAuthStateWithDefault === CONST.AUTO_AUTH_STATE.TWO_FACTOR_AUTH_FAILED && }

  5. added
    ExternalAdded to denote the issue can be worked on by a contributor
    on Jan 15, 2026
  6. changed the title [-]Web - Login - 2nd tab change to Magic code expired page after enter incorrect 2FA code[/-] [+][$250] Web - Login - 2nd tab change to Magic code expired page after enter incorrect 2FA code[/+] on Jan 15, 2026
  7. melvin-bot commented on Jan 15, 2026

    @melvin-bot
  8. added
    Help WantedApply this label when an issue is open to proposals by contributors
    on Jan 15, 2026
  9. melvin-bot commented on Jan 15, 2026

    @melvin-bot

    Triggered auto assignment to Contributor-plus team member for initial proposal review - @shubham1206agra (External)

  10. melvin-bot commented on Jan 21, 2026

    @melvin-bot

    @shubham1206agra Eep! 4 days overdue now. Issues have feelings too...

  11. melvin-bot commented on Jan 22, 2026

    @melvin-bot

    📣 It's been a week! Do we have any satisfactory proposals yet? Do we need to adjust the bounty for this issue? 💸

  12. 56 remaining items

  13. melvin-bot commented on Mar 12, 2026

    @melvin-bot

    Triggered auto assignment to @mallenexpensify (Awaiting Payment)

  14. mallenexpensify commented on Mar 20, 2026

    @mallenexpensify
    Contributor

    Payment Summary

    Contributor: @MobileMage paid $250 via Upwork
    Contributor+: @shubham1206agra due $250 via NewDot

    @shubham1206agra plz complete the BZ checklist and tag me in a post once you have. Thx

  15. melvin-bot commented on Mar 23, 2026

    @melvin-bot

    @mallenexpensify Whoops! This issue is 2 days overdue. Let's get this updated quick!

  16. melvin-bot commented on Mar 23, 2026

    @melvin-bot

    @mallenexpensify Uh oh! This issue is overdue by 2 days. Don't forget to update your issues!

  17. cristipaval commented on Mar 24, 2026

    @cristipaval
    Contributor
  18. shubham1206agra commented on Mar 26, 2026

    @shubham1206agra
    Contributor

    BugZero Checklist:

    • [Contributor] The offending PR has been commented on, pointing out the bug it caused and why, so the author and reviewers can learn from the mistake.

      Link to comment: https://github.com/Expensify/App/pull/15505/changes#r2992249470

    • [Contributor] If the regression was CRITICAL (e.g. interrupts a core flow) A discussion in #expensify-open-source has been started about whether any other steps should be taken (e.g. updating the PR review checklist) in order to catch this type of bug sooner.

      Link to discussion: NA

    • [Contributor] If it was decided to create a regression test for the bug, please propose the regression test steps using the template below to ensure the same bug will not reach production again.

    • [BugZero Assignee] Create a GH issue for creating/updating the regression test once above steps have been agreed upon.

      Link to issue:

    Regression Test Proposal

    Test:

    1. Open the app and start signing in to the account where 2FA is enabled.
    2. Navigate to the email and locate the magic link
    3. Open the magic link in a new tab
    4. In the first tab, enter an incorrect 2FA code
    5. Switch to the second tab
    6. Verify the second tab still shows the 2FA required page and does NOT show "Magic code expired" or an empty page

    Do we agree 👍 or 👎

  19. shubham1206agra commented on Mar 26, 2026

    @shubham1206agra
    Contributor

    @mallenexpensify You can close this issue now

  20. garrettmknight commented on Apr 2, 2026

    @garrettmknight
    Contributor

    $250 approved for @shubham1206agra

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

Awaiting PaymentAuto-added when associated PR is deployed to productionBugSomething is broken. Auto assigns a BugZero manager.DailyKSv2ExternalAdded to denote the issue can be worked on by a contributor

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions