"use client"; import { useRef, useState } from "react"; import Link from "next/link"; import { useRouter, useSearchParams } from "next/navigation"; import { Loader2 } from "lucide-react"; import { toast } from "sonner"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/components/ui/card"; import { signIn } from "@/lib/auth/auth-client"; import { safeRedirect } from "@/lib/utils"; import { GoogleButton } from "./google-button"; import { Turnstile, type TurnstileHandle } from "./turnstile"; export function SignInForm({ googleEnabled, turnstileSiteKey, }: { googleEnabled: boolean; turnstileSiteKey: string | null; }) { const router = useRouter(); const params = useSearchParams(); // Validate the ?redirect param to prevent open-redirect attacks. const redirectTo = safeRedirect(params.get("redirect")); const [loading, setLoading] = useState(false); // Turnstile is only rendered when configured; when it is, a solved token is // required before the form can be submitted. The server rejects a missing or // reused token regardless, so this is UX, not the security boundary. const [captchaToken, setCaptchaToken] = useState(""); const turnstileRef = useRef(null); const captchaRequired = !!turnstileSiteKey; async function onSubmit(e: React.FormEvent) { e.preventDefault(); setLoading(true); const form = new FormData(e.currentTarget); const { error } = await signIn.email( { email: String(form.get("email")), password: String(form.get("password")), }, captchaRequired ? { headers: { "x-captcha-response": captchaToken } } : undefined ); if (error) { // Turnstile tokens are single-use — issue a fresh challenge for the retry, // otherwise the next submit fails verification instead of on credentials. turnstileRef.current?.reset(); toast.error(error.message ?? "Invalid email or password"); setLoading(false); return; } router.push(redirectTo); router.refresh(); } return ( Welcome back Sign in to your Podcast Distribution AI account. {googleEnabled && ( <>
or
)}
Forgot?
{turnstileSiteKey && ( toast.error("Could not load the security check. Please refresh.")} className="flex justify-center" /> )}

Don't have an account?{" "} Sign up

); }