add magic link back
This commit is contained in:
parent
b864da766b
commit
0504460f5b
2 changed files with 101 additions and 20 deletions
|
|
@ -1,20 +1,104 @@
|
|||
import { NextResponse } from "next/server";
|
||||
import { cookies } from "next/headers";
|
||||
import { randomUUID } from "crypto";
|
||||
import { sessions } from "@/lib/schema";
|
||||
import { and, eq, gt, isNull } from "drizzle-orm";
|
||||
|
||||
const sessionId = randomUUID();
|
||||
const expiresAt = new Date(Date.now() + 1000 * 60 * 60 * 24 * 14); // 14 days
|
||||
import { db } from "@/lib/db";
|
||||
import { loginTokens, sessions, users } from "@/lib/schema";
|
||||
import { hashToken } from "@/lib/auth/tokens";
|
||||
|
||||
await db.insert(sessions).values({
|
||||
export async function POST(req: Request) {
|
||||
// --------------------------------------------------
|
||||
// 1️⃣ Parse token from request
|
||||
// --------------------------------------------------
|
||||
const { token } = await req.json();
|
||||
|
||||
if (!token) {
|
||||
return NextResponse.json(
|
||||
{ error: "Missing token" },
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
|
||||
// --------------------------------------------------
|
||||
// 2️⃣ Validate login token (magic link)
|
||||
// --------------------------------------------------
|
||||
const tokenHash = hashToken(token);
|
||||
|
||||
const loginToken = await db
|
||||
.select()
|
||||
.from(loginTokens)
|
||||
.where(
|
||||
and(
|
||||
eq(loginTokens.tokenHash, tokenHash),
|
||||
isNull(loginTokens.usedAt),
|
||||
gt(loginTokens.expiresAt, new Date())
|
||||
)
|
||||
)
|
||||
.limit(1)
|
||||
.then((rows) => rows[0]);
|
||||
|
||||
if (!loginToken) {
|
||||
return NextResponse.json(
|
||||
{ error: "Invalid or expired token" },
|
||||
{ status: 401 }
|
||||
);
|
||||
}
|
||||
|
||||
// --------------------------------------------------
|
||||
// 3️⃣ Ensure user still exists
|
||||
// --------------------------------------------------
|
||||
const user = await db
|
||||
.select()
|
||||
.from(users)
|
||||
.where(eq(users.id, loginToken.userId))
|
||||
.limit(1)
|
||||
.then((rows) => rows[0]);
|
||||
|
||||
if (!user) {
|
||||
return NextResponse.json(
|
||||
{ error: "User not found" },
|
||||
{ status: 404 }
|
||||
);
|
||||
}
|
||||
|
||||
// --------------------------------------------------
|
||||
// 4️⃣ Consume login token (one-time use)
|
||||
// --------------------------------------------------
|
||||
await db
|
||||
.update(loginTokens)
|
||||
.set({ usedAt: new Date() })
|
||||
.where(eq(loginTokens.id, loginToken.id));
|
||||
|
||||
// --------------------------------------------------
|
||||
// 5️⃣ Create DB-backed session
|
||||
// --------------------------------------------------
|
||||
const sessionId = randomUUID();
|
||||
const expiresAt = new Date(
|
||||
Date.now() + 1000 * 60 * 60 * 24 * 14 // 14 days
|
||||
);
|
||||
|
||||
await db.insert(sessions).values({
|
||||
id: sessionId,
|
||||
userId: loginToken.userId,
|
||||
userId: user.id,
|
||||
expiresAt,
|
||||
});
|
||||
});
|
||||
|
||||
const cookieStore = await cookies();
|
||||
cookieStore.set("session", sessionId, {
|
||||
// --------------------------------------------------
|
||||
// 6️⃣ Set secure session cookie
|
||||
// --------------------------------------------------
|
||||
const cookieStore = await cookies();
|
||||
|
||||
cookieStore.set("session", sessionId, {
|
||||
httpOnly: true,
|
||||
sameSite: "strict",
|
||||
secure: process.env.NODE_ENV === "production",
|
||||
path: "/",
|
||||
maxAge: 60 * 60 * 24 * 14,
|
||||
});
|
||||
maxAge: 60 * 60 * 24 * 14, // 14 days
|
||||
});
|
||||
|
||||
// --------------------------------------------------
|
||||
// 7️⃣ Done
|
||||
// --------------------------------------------------
|
||||
return NextResponse.json({ ok: true });
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,7 @@
|
|||
import type { NextConfig } from "next";
|
||||
|
||||
const nextConfig = {
|
||||
output: 'standalone',
|
||||
experimental: {
|
||||
turbo: false, // disables Turbopack in prod builds
|
||||
},
|
||||
output: 'standalone'
|
||||
};
|
||||
|
||||
export default nextConfig;
|
||||
Loading…
Add table
Reference in a new issue