Files
vibn-agent-runner/vibn-frontend/app/api/auth/login/route.ts

62 lines
1.8 KiB
TypeScript

import { NextResponse } from "next/server";
import { queryOne } from "@/lib/db-postgres";
import {
verifyPassword,
createDbSession,
SESSION_COOKIE_NAME,
sessionCookieOptions,
} from "@/lib/auth/password";
// POST /api/auth/login { email, password }
// Verifies the scrypt hash stored on the user's fs_users row and, on success,
// creates a database session + sets the session cookie. Google-only accounts
// have no password hash, so they fall through to the generic invalid message.
export async function POST(request: Request) {
let body: { email?: unknown; password?: unknown };
try {
body = await request.json();
} catch {
return NextResponse.json({ error: "Invalid request body." }, { status: 400 });
}
const email = String(body.email ?? "").trim().toLowerCase();
const password = String(body.password ?? "");
if (!email || !password) {
return NextResponse.json(
{ error: "Enter your email and password." },
{ status: 400 },
);
}
const invalid = NextResponse.json(
{ error: "Invalid email or password." },
{ status: 401 },
);
try {
const row = await queryOne<{ user_id: string; hash: string | null }>(
`SELECT user_id, data->>'passwordHash' AS hash
FROM fs_users
WHERE lower(data->>'email') = $1
LIMIT 1`,
[email],
);
if (!row || !row.hash) return invalid;
const ok = await verifyPassword(password, row.hash);
if (!ok) return invalid;
const { token, expires } = await createDbSession(row.user_id);
const res = NextResponse.json({ ok: true });
res.cookies.set(SESSION_COOKIE_NAME, token, sessionCookieOptions(expires));
return res;
} catch (err) {
console.error("[login] exception:", err);
return NextResponse.json(
{ error: "Could not sign you in. Please try again." },
{ status: 500 },
);
}
}