From ce02517dd23519808ae68d9549ef6405cb1d6f14 Mon Sep 17 00:00:00 2001 From: Alex Carpenter Date: Tue, 3 Feb 2026 16:12:58 -0500 Subject: [PATCH 1/2] fix(ui): prevent infinite loading spinner on factor-two without active 2FA session When users land on the factor-two sign-in route without an active 2FA session (e.g., via a force redirect URL), they would get stuck on an infinite loading spinner. This fix adds a status check to redirect users back to the sign-in start page if the sign-in status is not 'needs_second_factor', matching the pattern already implemented in SignInFactorOne. Co-Authored-By: Claude Haiku 4.5 --- .../src/components/SignIn/SignInFactorTwo.tsx | 18 ++++++++++++++++++ .../SignIn/__tests__/SignInFactorTwo.test.tsx | 13 +++++++++++-- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/packages/ui/src/components/SignIn/SignInFactorTwo.tsx b/packages/ui/src/components/SignIn/SignInFactorTwo.tsx index caa771ed0e3..4cced739797 100644 --- a/packages/ui/src/components/SignIn/SignInFactorTwo.tsx +++ b/packages/ui/src/components/SignIn/SignInFactorTwo.tsx @@ -1,8 +1,12 @@ +import { useClerk } from '@clerk/shared/react'; +import React from 'react'; + import { withCardStateProvider } from '@/ui/elements/contexts'; import { LoadingCard } from '@/ui/elements/LoadingCard'; import { withRedirectToAfterSignIn, withRedirectToSignInTask } from '../../common'; import { useCoreSignIn } from '../../contexts'; +import { useRouter } from '../../router'; import { SignInFactorTwoAlternativeMethods } from './SignInFactorTwoAlternativeMethods'; import { SignInFactorTwoBackupCodeCard } from './SignInFactorTwoBackupCodeCard'; import { SignInFactorTwoEmailCodeCard } from './SignInFactorTwoEmailCodeCard'; @@ -12,7 +16,9 @@ import { SignInFactorTwoTOTPCard } from './SignInFactorTwoTOTPCard'; import { useSecondFactorSelection } from './useSecondFactorSelection'; function SignInFactorTwoInternal(): JSX.Element { + const { __internal_setActiveInProgress } = useClerk(); const signIn = useCoreSignIn(); + const router = useRouter(); const { currentFactor, factorAlreadyPrepared, @@ -22,6 +28,18 @@ function SignInFactorTwoInternal(): JSX.Element { toggleAllStrategies, } = useSecondFactorSelection(signIn.supportedSecondFactors); + React.useEffect(() => { + if (__internal_setActiveInProgress) { + return; + } + + // If the sign-in doesn't require second factor verification, + // redirect back to the start of the sign-in flow + if (signIn.status !== 'needs_second_factor') { + void router.navigate('../'); + } + }, [__internal_setActiveInProgress, signIn.status, router]); + if (!currentFactor) { return ; } diff --git a/packages/ui/src/components/SignIn/__tests__/SignInFactorTwo.test.tsx b/packages/ui/src/components/SignIn/__tests__/SignInFactorTwo.test.tsx index 3d944954df9..63f9e05cf80 100644 --- a/packages/ui/src/components/SignIn/__tests__/SignInFactorTwo.test.tsx +++ b/packages/ui/src/components/SignIn/__tests__/SignInFactorTwo.test.tsx @@ -18,8 +18,17 @@ describe('SignInFactorTwo', () => { }); describe('Navigation', () => { - //This isn't yet implemented in the component - it.todo('navigates to SignInStart component if user lands on SignInFactorTwo page but they should not'); + it('navigates to SignInStart component if sign-in status is not needs_second_factor', async () => { + const { wrapper, fixtures } = await createFixtures(f => { + f.withEmailAddress(); + // Note: We do NOT call f.startSignInFactorTwo() here, so the sign-in status + // will be null/needs_identifier, not 'needs_second_factor' + }); + render(, { wrapper }); + await waitFor(() => { + expect(fixtures.router.navigate).toHaveBeenCalledWith('../'); + }); + }); }); describe('Submitting', () => { From 9942e3683a9c249a8975576ed0b49239ead25c89 Mon Sep 17 00:00:00 2001 From: Alex Carpenter Date: Tue, 3 Feb 2026 16:15:06 -0500 Subject: [PATCH 2/2] chore: add changeset --- .changeset/fix-signin-factor-two-spinner.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/fix-signin-factor-two-spinner.md diff --git a/.changeset/fix-signin-factor-two-spinner.md b/.changeset/fix-signin-factor-two-spinner.md new file mode 100644 index 00000000000..a55b2122ffd --- /dev/null +++ b/.changeset/fix-signin-factor-two-spinner.md @@ -0,0 +1,5 @@ +--- +'@clerk/ui': patch +--- + +Fix infinite loading spinner when navigating to factor-two sign-in route without an active 2FA session