···
31
+
getVerificationCodeSentAt,
createPasswordResetToken,
verifyPasswordResetToken,
consumePasswordResetToken,
···
const user = await createUser(email, password, name);
// Send verification email - MUST succeed for registration to complete
270
-
const { code, token } = createEmailVerificationToken(user.id);
271
+
const { code, token, sentAt } = createEmailVerificationToken(user.id);
···
user: { id: user.id, email: user.email },
email_verification_required: true,
313
+
verification_code_sent_at: sentAt,
···
325
+
console.error("[Auth] Registration error:", err);
{ error: "Registration failed" },
···
// Check if email is verified
if (!isEmailVerified(user.id)) {
376
+
let codeSentAt = getVerificationCodeSentAt(user.id);
378
+
// If no verification code exists, auto-send one
380
+
const { code, token, sentAt } = createEmailVerificationToken(user.id);
381
+
codeSentAt = sentAt;
386
+
subject: "Verify your email - Thistle",
387
+
html: verifyEmailTemplate({
394
+
console.error("[Email] Failed to send verification email on login:", err);
395
+
// Don't fail login - just return null timestamp so client can try resend
user: { id: user.id, email: user.email },
email_verification_required: true,
404
+
verification_code_sent_at: codeSentAt,
···
421
+
console.error("[Auth] Login error:", error);
return Response.json({ error: "Login failed" }, { status: 500 });
···
return Response.json({ message: "Verification email sent" });
560
+
return handleError(error);
564
+
"/api/auth/resend-verification-code": {
565
+
POST: async (req) => {
567
+
const body = await req.json();
568
+
const { email } = body;
571
+
return Response.json({ error: "Email required" }, { status: 400 });
574
+
// Rate limiting by email
575
+
const rateLimitError = enforceRateLimit(req, "resend-verification-code", {
576
+
account: { max: 3, windowSeconds: 5 * 60, email },
578
+
if (rateLimitError) return rateLimitError;
580
+
// Get user by email
581
+
const user = getUserByEmail(email);
583
+
// Don't reveal if user exists
584
+
return Response.json({ message: "If an account exists with that email, a verification code has been sent" });
587
+
// Check if already verified
588
+
if (isEmailVerified(user.id)) {
589
+
return Response.json(
590
+
{ error: "Email already verified" },
595
+
// Generate new code and send email
596
+
const { code, token, sentAt } = createEmailVerificationToken(user.id);
600
+
subject: "Verify your email - Thistle",
601
+
html: verifyEmailTemplate({
608
+
return Response.json({
609
+
message: "Verification code sent",
610
+
verification_code_sent_at: sentAt,
return handleError(error);