// server/api/auth/login.post.js import jwt from "jsonwebtoken"; import { randomUUID } from "crypto"; import { Resend } from "resend"; import Member from "../../models/member.js"; import { connectDB } from "../../utils/mongoose.js"; import { validateBody } from "../../utils/validateBody.js"; import { emailSchema } from "../../utils/schemas.js"; const resend = new Resend(process.env.RESEND_API_KEY); export default defineEventHandler(async (event) => { await connectDB(); const baseUrl = process.env.BASE_URL; if (!baseUrl) { throw createError({ statusCode: 500, statusMessage: "BASE_URL environment variable is not set", }); } const { email } = await validateBody(event, emailSchema); const GENERIC_MESSAGE = "If this email is registered, we've sent a login link."; const member = await Member.findOne({ email }); if (!member) { return { success: true, message: GENERIC_MESSAGE, }; } const config = useRuntimeConfig(event); const jti = randomUUID(); const token = jwt.sign( { memberId: member._id, jti }, config.jwtSecret, { expiresIn: "15m" }, ); // Store jti so we can burn it on first use await Member.findByIdAndUpdate( member._id, { $set: { magicLinkJti: jti, magicLinkJtiUsed: false } }, { runValidators: false } ); // Token goes in the fragment — never sent to server, never logged const magicLink = `${baseUrl}/verify#${token}`; try { await resend.emails.send({ from: "Ghost Guild ", to: email, subject: "Your Ghost Guild login link", text: `Hi, Sign in to Ghost Guild: ${magicLink} This link expires in 15 minutes. If you didn't request it, ignore this email.`, }); return { success: true, message: GENERIC_MESSAGE, }; } catch (error) { console.error("Failed to send email:", error); throw createError({ statusCode: 500, statusMessage: "Failed to send login email. Please try again.", }); } });