Files
thrilltrack-explorer/src-old/components/auth/MFAChallenge.tsx

98 lines
3.0 KiB
TypeScript

import { useState } from "react";
import { supabase } from "@/lib/supabaseClient";
import { useToast } from "@/hooks/use-toast";
import { handleError } from "@/lib/errorHandler";
import { Button } from "@/components/ui/button";
import { Label } from "@/components/ui/label";
import { InputOTP, InputOTPGroup, InputOTPSlot } from "@/components/ui/input-otp";
import { Shield } from "lucide-react";
interface MFAChallengeProps {
factorId: string;
onSuccess: () => void;
onCancel: () => void;
}
export function MFAChallenge({ factorId, onSuccess, onCancel }: MFAChallengeProps) {
const { toast } = useToast();
const [code, setCode] = useState("");
const [loading, setLoading] = useState(false);
const handleVerify = async () => {
if (code.length !== 6) return;
setLoading(true);
try {
// Create fresh challenge for each verification attempt
const { data: challengeData, error: challengeError } = await supabase.auth.mfa.challenge({ factorId });
if (challengeError) throw challengeError;
// Immediately verify with fresh challenge
const { data, error } = await supabase.auth.mfa.verify({
factorId,
challengeId: challengeData.id,
code: code.trim(),
});
if (error) throw error;
if (data) {
toast({
title: "Welcome back!",
description: "Multi-Factor verification successful.",
});
onSuccess();
}
} catch (error: unknown) {
handleError(error, {
action: 'MFA Verification',
metadata: {
factorId,
codeLength: code.length,
context: 'MFAChallenge'
}
});
setCode("");
} finally {
setLoading(false);
}
};
return (
<div className="space-y-4">
<div className="flex items-center gap-2 text-primary">
<Shield className="w-5 h-5" />
<h3 className="font-semibold">Multi-Factor Authentication</h3>
</div>
<p className="text-sm text-muted-foreground">Enter the 6-digit code from your authenticator app</p>
<div className="space-y-2">
<Label htmlFor="mfa-code">Authentication Code</Label>
<div className="flex justify-center">
<InputOTP maxLength={6} value={code} onChange={setCode} onComplete={handleVerify}>
<InputOTPGroup>
<InputOTPSlot index={0} />
<InputOTPSlot index={1} />
<InputOTPSlot index={2} />
<InputOTPSlot index={3} />
<InputOTPSlot index={4} />
<InputOTPSlot index={5} />
</InputOTPGroup>
</InputOTP>
</div>
</div>
<div className="flex gap-2">
<Button variant="outline" onClick={onCancel} className="flex-1" disabled={loading}>
Cancel
</Button>
<Button onClick={handleVerify} className="flex-1" disabled={code.length !== 6 || loading}>
{loading ? "Verifying..." : "Verify"}
</Button>
</div>
</div>
);
}