diff --git a/apps/remix/app/components/forms/signin.tsx b/apps/remix/app/components/forms/signin.tsx index 91ce3d42f..ab47a19ef 100644 --- a/apps/remix/app/components/forms/signin.tsx +++ b/apps/remix/app/components/forms/signin.tsx @@ -106,6 +106,7 @@ export const SignInForm = ({ const turnstileSiteKey = env('NEXT_PUBLIC_TURNSTILE_SITE_KEY'); const turnstileRef = useRef(null); + const twoFactorTurnstileRef = useRef(null); const [captchaToken, setCaptchaToken] = useState(null); const [isPasskeyLoading, setIsPasskeyLoading] = useState(false); @@ -234,6 +235,11 @@ export const SignInForm = ({ if (error.code === 'TWO_FACTOR_MISSING_CREDENTIALS') { setIsTwoFactorAuthenticationDialogOpen(true); + + // Turnstile tokens are single-use. Clear the consumed one so the + // dialog's fresh widget mounts cleanly and the dialog can't be + // submitted with the stale token before a new one is issued. + setCaptchaToken(null); return; } @@ -393,7 +399,7 @@ export const SignInForm = ({ )} /> - {turnstileSiteKey && ( + {turnstileSiteKey && !isTwoFactorAuthenticationDialogOpen && ( )} + {turnstileSiteKey && ( +
+ setCaptchaToken(null)} + options={{ + size: 'flexible', + appearance: 'interaction-only', + }} + /> +
+ )} +