import { useState } from 'react'; import { Link, useNavigate, useSearchParams } from 'react-router'; import { useAuth } from '../components/auth/AuthProvider'; import { Wordmark } from '../components/Logo'; import { Button } from '../components/ui/button'; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '../components/ui/card'; import { InputOTP, InputOTPGroup, InputOTPSlot } from '../components/ui/input-otp'; export default function MFAVerify() { const navigate = useNavigate(); const [searchParams] = useSearchParams(); const { pendingMfaChallenge, mfa, clearMfaChallenge, signOut } = useAuth(); const [code, setCode] = useState(''); const [error, setError] = useState(''); const [loading, setLoading] = useState(false); const handleVerify = async () => { if (code.length !== 6) { setError('Please enter a 6-digit code'); return; } if (!pendingMfaChallenge) { setError('No pending MFA challenge. Please sign in again.'); return; } setError(''); setLoading(true); try { await mfa.verify(pendingMfaChallenge.factorId, pendingMfaChallenge.challengeId, code); // Get redirect URL const redirectParam = searchParams.get('redirect') || '/dashboard'; const safeRedirect = redirectParam.startsWith('/') && !redirectParam.startsWith('//') && !redirectParam.includes(':') ? redirectParam : '/dashboard'; navigate(safeRedirect); } catch (err) { setError(err instanceof Error ? err.message : 'Invalid code. Please try again.'); setCode(''); } finally { setLoading(false); } }; const handleCancel = async () => { clearMfaChallenge(); await signOut(); navigate('/login'); }; // If no pending challenge, show message if (!pendingMfaChallenge) { return (
Session expired Your authentication session has expired. Please sign in again. Sign in
); } return (
{/* Header */}
{/* Main content */}
Two-factor authentication Enter the 6-digit code from your authenticator app {error && (
{error}
)}

Open your authenticator app (Google Authenticator, Authy, etc.) and enter the code shown for this account.

); }