49 lines
1.2 KiB
TypeScript
49 lines
1.2 KiB
TypeScript
// app/api/auth/request-link/route.ts
|
|
import { NextResponse } from "next/server";
|
|
import { db } from "@/lib/db";
|
|
import { users, loginTokens } from "@/lib/schema";
|
|
import { eq } from "drizzle-orm";
|
|
import { generateToken, hashToken } from "@/lib/auth/tokens";
|
|
import { sendMagicLinkEmail } from "@/lib/email/sendMagicLink";
|
|
|
|
export async function POST(req: Request) {
|
|
const { email } = await req.json();
|
|
|
|
if (!email) {
|
|
return NextResponse.json({ error: "Email required" }, { status: 400 });
|
|
}
|
|
|
|
// 1. find user
|
|
let user = await db
|
|
.select()
|
|
.from(users)
|
|
.where(eq(users.email, email))
|
|
.then((rows) => rows[0]);
|
|
|
|
// 2. create user if missing
|
|
if (!user) {
|
|
const inserted = await db
|
|
.insert(users)
|
|
.values({ email })
|
|
.returning();
|
|
|
|
user = inserted[0];
|
|
}
|
|
|
|
// 3. generate token
|
|
const token = generateToken();
|
|
const tokenHash = hashToken(token);
|
|
|
|
// 4. store login token
|
|
await db.insert(loginTokens).values({
|
|
userId: user.id,
|
|
tokenHash,
|
|
expiresAt: new Date(Date.now() + 15 * 60 * 1000),
|
|
});
|
|
|
|
// 5. send email
|
|
const link = `${process.env.APP_URL}/auth/callback?token=${token}`;
|
|
await sendMagicLinkEmail(email, link);
|
|
|
|
return NextResponse.json({ ok: true });
|
|
}
|