// app/api/auth/login/route.ts import { NextRequest, NextResponse } from "next/server"; import { emailForUsername, loginDirectus } from "@/lib/directus"; export const runtime = "nodejs"; const secure = process.env.NODE_ENV === "production"; /** * Accepts any of: * - { identifier: string, password: string } // email or username in `identifier` * - { email: string, password: string } * - { username: string, password: string } * * On success: sets HttpOnly "ma_at" cookie and returns { ok: true }. */ export async function POST(req: NextRequest) { try { const body = await req.json().catch(() => ({} as any)); const { password } = body as { identifier?: string; email?: string; username?: string; password?: string }; let identifier = (body?.identifier ?? body?.email ?? body?.username ?? "").trim(); if (!identifier || !password) { return NextResponse.json({ error: "Missing credentials" }, { status: 400 }); } // Resolve to an email for Directus login: // - If identifier looks like an email, use it directly. // - Otherwise treat it as a username and look up the email. let email = identifier.includes("@") ? identifier : null; if (!email) { email = await emailForUsername(identifier); if (!email) { return NextResponse.json({ error: "User not found" }, { status: 404 }); } } // Login against Directus; helper returns { access_token, refresh_token?, expires? } in .data or root const data = await loginDirectus(email, password); const access = data?.access_token ?? data?.data?.access_token ?? null; const expiresSec = data?.expires ?? data?.data?.expires ?? null; if (!access) { return NextResponse.json({ error: "Invalid response from auth provider" }, { status: 502 }); } const res = NextResponse.json({ ok: true }); // Set access token cookie // - HttpOnly so JS can't read it // - SameSite=Lax to allow normal navigation // - Secure in production // - Max-Age from Directus if provided; else fallback to 8h const maxAge = typeof expiresSec === "number" ? Math.max(0, Math.floor(expiresSec)) : 60 * 60 * 8; res.cookies.set({ name: "ma_at", value: access, httpOnly: true, sameSite: "lax", secure, path: "/", maxAge, }); return res; } catch (err: any) { const message = err?.response?.data?.error || err?.message || "Login failed"; // Return 401 for auth problems; 400 for others const status = /unauth|invalid|credentials/i.test(message) ? 401 : 400; return NextResponse.json({ error: message }, { status }); } }