"use client" import { useState, useEffect } from "react" import { createSupabaseBrowserClient } from "@/lib/supabase/client" export function MfaChallenge({ onVerified }: { onVerified: () => void }) { const [verificationCode, setVerificationCode] = useState("") const [errorMessage, setErrorMessage] = useState(null) const [isVerifying, setIsVerifying] = useState(false) const [factorIdentifier, setFactorIdentifier] = useState(null) const supabaseClient = createSupabaseBrowserClient() useEffect(() => { async function loadFactor() { const { data } = await supabaseClient.auth.mfa.listFactors() if (data?.totp && data.totp.length > 0) { const verifiedFactor = data.totp.find( (factor) => factor.status === "verified" ) if (verifiedFactor) { setFactorIdentifier(verifiedFactor.id) } } } loadFactor() // eslint-disable-next-line react-hooks/exhaustive-deps }, []) async function handleVerify(event?: React.FormEvent) { event?.preventDefault() if (!factorIdentifier || verificationCode.length !== 6) return setIsVerifying(true) setErrorMessage(null) const { data: challengeData, error: challengeError } = await supabaseClient.auth.mfa.challenge({ factorId: factorIdentifier, }) if (challengeError) { setIsVerifying(false) setErrorMessage("failed to create challenge — please try again") return } const { error: verifyError } = await supabaseClient.auth.mfa.verify({ factorId: factorIdentifier, challengeId: challengeData.id, code: verificationCode, }) setIsVerifying(false) if (verifyError) { setErrorMessage("invalid code — please try again") setVerificationCode("") return } onVerified() } return (

two-factor authentication

enter the 6-digit code from your authenticator app

{ const filtered = event.target.value.replace(/\D/g, "") setVerificationCode(filtered) }} placeholder="000000" className="w-full border border-border bg-background-secondary px-3 py-3 text-center font-mono text-2xl tracking-[0.5em] text-text-primary outline-none placeholder:text-text-dim focus:border-text-dim" autoFocus /> {errorMessage && (

{errorMessage}

)}
) }