Wire up email verification flow for new signups
requireEmailVerification was enabled but no sendVerificationEmail was configured — new users saw "check your email", never received anything, and couldn't log in (403 shown as "wrong email or password"). - email.ts: add verification email template; welcome email no longer claims the account is "confirmed" - auth.ts: configure emailVerification (send on signup, resend on unverified login attempt, auto sign-in after verification, 24h TTL) - register route: callbackURL=/dashboard so the verify link lands in the cabinet - login form: distinguish 403 (unverified — tell user a fresh link was sent) and 429 (rate limit) from wrong credentials Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -10,17 +10,27 @@ export function LoginForm() {
|
||||
const [email, setEmail] = useState("");
|
||||
const [password, setPassword] = useState("");
|
||||
const [error, setError] = useState("");
|
||||
const [needsVerification, setNeedsVerification] = useState(false);
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
async function handleSubmit(e: React.FormEvent) {
|
||||
e.preventDefault();
|
||||
setError("");
|
||||
setNeedsVerification(false);
|
||||
setLoading(true);
|
||||
|
||||
const result = await signIn.email({ email, password });
|
||||
|
||||
if (result.error) {
|
||||
setError("Неверный email или пароль");
|
||||
if (result.error.status === 403) {
|
||||
// Креды верны, но email не подтверждён. Better Auth уже
|
||||
// переотправил письмо подтверждения — сообщаем об этом.
|
||||
setNeedsVerification(true);
|
||||
} else if (result.error.status === 429) {
|
||||
setError("Слишком много попыток входа. Подождите минуту и попробуйте снова.");
|
||||
} else {
|
||||
setError("Неверный email или пароль");
|
||||
}
|
||||
setLoading(false);
|
||||
return;
|
||||
}
|
||||
@@ -82,6 +92,18 @@ export function LoginForm() {
|
||||
placeholder="••••••••"
|
||||
/>
|
||||
</div>
|
||||
{needsVerification && (
|
||||
<div
|
||||
className="text-xs py-3 px-3 space-y-1"
|
||||
style={{ border: "2px solid var(--border)", color: "var(--foreground)" }}
|
||||
>
|
||||
<p className="font-bold">Email не подтверждён</p>
|
||||
<p style={{ color: "var(--muted-foreground)" }}>
|
||||
Мы отправили новое письмо со ссылкой подтверждения на <strong>{email}</strong>.
|
||||
Проверьте почту (и папку «Спам»), затем войдите снова.
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
{error && (
|
||||
<p className="text-sm" style={{ color: "var(--destructive)" }}>
|
||||
{error}
|
||||
|
||||
@@ -83,7 +83,7 @@ export async function POST(request: NextRequest) {
|
||||
"Content-Type": "application/json",
|
||||
Origin: baseUrl,
|
||||
}),
|
||||
body: JSON.stringify({ name, email, password }),
|
||||
body: JSON.stringify({ name, email, password, callbackURL: "/dashboard" }),
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user