ghostguild-org/server/api/auth/login.post.js

83 lines
2.2 KiB
JavaScript

// 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}`;
const emailSubject = "Your Ghost Guild login link";
const emailBody = `Hi,\n\nSign in to Ghost Guild:\n${magicLink}\n\nThis link expires in 15 minutes. If you didn't request it, ignore this email.`;
try {
await resend.emails.send({
from: "Ghost Guild <ghostguild@babyghosts.org>",
to: email,
subject: emailSubject,
text: emailBody,
});
logActivity(member._id, 'email_sent', {
emailType: 'magic_link',
subject: emailSubject,
body: emailBody
})
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.",
});
}
});