fix: use check-email endpoint instead of sign-in probe for email verification

This commit is contained in:
2026-04-26 08:02:18 -05:00
parent d1d40c297e
commit 8dfbd3ca5e
+41 -46
View File
@@ -36,38 +36,33 @@ export default function LoginForm() {
return
}
// Check if email exists by attempting sign-in with empty password
setIsLoading(true)
const { error } = await authClient.signIn.email(
{ email, password: "" },
{
onError: () => {
// Silently handle - we check the error type below
},
},
)
setIsLoading(false)
try {
const res = await fetch("/api/auth/check-email", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ email }),
})
if (error) {
// If error is about invalid credentials, email exists but password is wrong
// If error is about user not found, email doesn't exist
if (
error.message?.toLowerCase().includes("not found") ||
error.message?.toLowerCase().includes("invalid email") ||
error.status === 404
) {
setError(
"No account found with this email.",
)
if (!res.ok) {
const data = await res.json()
setError(data.error || "Something went wrong. Please try again.")
return
}
const data = await res.json()
if (!data.exists) {
setError("No account found with this email.")
return
}
// Email exists, move to password phase
setPhase("password")
return
} catch {
setError("Something went wrong. Please try again.")
} finally {
setIsLoading(false)
}
// Shouldn't reach here with empty password, but handle it
setPhase("password")
}
const handleLogin = async (e: React.FormEvent) => {
@@ -99,22 +94,22 @@ export default function LoginForm() {
}
return (
<div className="space-y-4">
<div className="space-y-5">
<div className="text-center mb-2">
<h1 className="text-lg font-bold text-[#ebe4f1]">
<h1 className="text-xl font-bold text-text">
Welcome back
</h1>
<p className="text-xs text-[#ebe4f1]/50 mt-1">
<p className="text-sm text-text/50 mt-1">
{phase === "email"
? "Sign in to DeckyVault"
: `Signing in as `}
{phase === "password" && (
<>
<strong className="text-[#ebe4f1]">{email}</strong>
<strong className="text-text">{email}</strong>
{" "}
<button
onClick={handleChangeEmail}
className="text-[#eb3779] hover:underline text-[11px]"
className="text-primary hover:underline text-xs"
>
change
</button>
@@ -126,22 +121,22 @@ export default function LoginForm() {
<SocialButtons />
<div className="flex items-center gap-3">
<div className="flex-1 h-px bg-white/[0.08]" />
<span className="text-[11px] text-[#ebe4f1]/40 uppercase">
<div className="flex-1 h-px bg-border" />
<span className="text-xs text-text/40 uppercase">
or continue with email
</span>
<div className="flex-1 h-px bg-white/[0.08]" />
<div className="flex-1 h-px bg-border" />
</div>
{error && (
<div className="text-red-400 text-xs text-center bg-red-500/10 border border-red-500/20 rounded-lg px-3 py-2">
<div className="text-red-400 text-sm text-center bg-red-500/10 border border-red-500/20 rounded-lg px-4 py-3">
{error}
{error.includes("No account found") && (
<>
{" "}
<Link
href="/signup"
className="text-[#eb3779] font-semibold hover:underline"
className="text-primary font-semibold hover:underline"
>
Create one
</Link>
@@ -153,7 +148,7 @@ export default function LoginForm() {
{phase === "email" ? (
<form onSubmit={handleEmailSubmit} className="space-y-4">
<div>
<label className="text-xs text-[#ebe4f1]/60 block mb-1">
<label className="text-sm text-text/60 block mb-1.5">
Email
</label>
<input
@@ -162,13 +157,13 @@ export default function LoginForm() {
onChange={(e) => setEmail(e.target.value)}
placeholder="you@example.com"
autoComplete="username webauthn"
className="w-full px-3 py-2.5 rounded-lg border border-white/10 bg-white/[0.03] text-[#ebe4f1] text-sm placeholder:text-[#ebe4f1]/40 outline-none focus:border-[#eb3779] focus:ring-2 focus:ring-[#eb3779]/50 transition-colors"
className="w-full px-4 py-3 rounded-lg border border-border bg-text/5 text-text text-sm placeholder:text-text/40 outline-none focus:border-primary focus:ring-2 focus:ring-primary/50 transition-colors"
/>
</div>
<button
type="submit"
disabled={isLoading}
className="w-full py-2.5 rounded-lg bg-[#eb3779] text-white text-sm font-semibold hover:bg-[#eb3779]/90 transition-colors disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center gap-2"
className="w-full py-3 rounded-lg bg-primary text-white text-sm font-semibold hover:bg-primary/90 transition-colors cursor-pointer disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center gap-2"
>
{isLoading && (
<Loader2 className="h-4 w-4 animate-spin" />
@@ -179,7 +174,7 @@ export default function LoginForm() {
) : (
<form onSubmit={handleLogin} className="space-y-4">
<div>
<label className="text-xs text-[#ebe4f1]/60 block mb-1">
<label className="text-sm text-text/60 block mb-1.5">
Password
</label>
<input
@@ -189,13 +184,13 @@ export default function LoginForm() {
placeholder="Enter your password"
autoComplete="current-password webauthn"
autoFocus
className="w-full px-3 py-2.5 rounded-lg border border-white/10 bg-white/[0.03] text-[#ebe4f1] text-sm placeholder:text-[#ebe4f1]/40 outline-none focus:border-[#eb3779] focus:ring-2 focus:ring-[#eb3779]/50 transition-colors"
className="w-full px-4 py-3 rounded-lg border border-border bg-text/5 text-text text-sm placeholder:text-text/40 outline-none focus:border-primary focus:ring-2 focus:ring-primary/50 transition-colors"
/>
</div>
<div className="text-right">
<Link
href="/forgot-password"
className="text-xs text-[#ebe4f1]/50 hover:text-[#ebe4f1] transition-colors"
className="text-sm text-text/50 hover:text-text transition-colors"
>
Forgot password?
</Link>
@@ -203,7 +198,7 @@ export default function LoginForm() {
<button
type="submit"
disabled={isLoading}
className="w-full py-2.5 rounded-lg bg-[#eb3779] text-white text-sm font-semibold hover:bg-[#eb3779]/90 transition-colors disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center gap-2"
className="w-full py-3 rounded-lg bg-primary text-white text-sm font-semibold hover:bg-primary/90 transition-colors cursor-pointer disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center gap-2"
>
{isLoading && (
<Loader2 className="h-4 w-4 animate-spin" />
@@ -211,19 +206,19 @@ export default function LoginForm() {
Sign in
</button>
{/* Passkey hint */}
<div className="text-center p-2.5 rounded-lg bg-[#eb3779]/5 border border-[#eb3779]/10">
<p className="text-xs text-[#ebe4f1]/50">
<div className="text-center p-3 rounded-lg bg-primary/5 border border-primary/10">
<p className="text-xs text-text/50">
Your browser may offer to sign in with a passkey
</p>
</div>
</form>
)}
<p className="text-center text-xs text-[#ebe4f1]/50">
<p className="text-center text-sm text-text/50">
Don&apos;t have an account?{" "}
<Link
href="/signup"
className="text-[#eb3779] hover:underline"
className="text-primary hover:underline"
>
Create one
</Link>