40 lines
1.5 KiB
TypeScript
40 lines
1.5 KiB
TypeScript
import { NextResponse } from "next/server";
|
|
import { cookies } from "next/headers";
|
|
import { getSessionCookieName } from "@/lib/server/auth";
|
|
import { loginUser } from "@/lib/server/auth-service";
|
|
import { enforceAuthRateLimit } from "@/lib/server/rate-limit";
|
|
import { toErrorResponse } from "@/lib/server/errors";
|
|
import { getRequestMeta } from "@/lib/server/request";
|
|
|
|
export async function POST(req: Request) {
|
|
const { requestId, ip } = await getRequestMeta();
|
|
const body = await req.json().catch(() => null);
|
|
const email = String(body?.email || "").trim().toLowerCase();
|
|
const password = String(body?.password || "");
|
|
const remember = Boolean(body?.remember ?? true);
|
|
|
|
let user;
|
|
let session;
|
|
try {
|
|
await enforceAuthRateLimit({ route: "login", ip, identifier: email });
|
|
if (!email || !password)
|
|
return NextResponse.json({ requestId, request_id: requestId, error: { code: "MISSING_CREDENTIALS", message: "Missing credentials" } }, { status: 400 });
|
|
const result = await loginUser({ email, password, remember });
|
|
user = result.user;
|
|
session = result.session;
|
|
} catch (e) {
|
|
const { status, body } = toErrorResponse(e, "POST /api/auth/login", requestId);
|
|
return NextResponse.json(body, { status });
|
|
}
|
|
const cookieStore = await cookies();
|
|
cookieStore.set(getSessionCookieName(), session.token, {
|
|
httpOnly: true,
|
|
sameSite: "lax",
|
|
secure: process.env.NODE_ENV === "production",
|
|
maxAge: Math.floor(session.ttlMs / 1000),
|
|
path: "/"
|
|
});
|
|
|
|
return NextResponse.json({ requestId, request_id: requestId, user });
|
|
}
|