parent
30ac27815f
commit
74036bc2ce
3 changed files with 173 additions and 184 deletions
|
|
@ -3,71 +3,72 @@ 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 identifier =
|
||||
String(body?.identifier ?? body?.email ?? body?.username ?? "").trim();
|
||||
const password = String(body?.password ?? "").trim();
|
||||
let identifier = String(
|
||||
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 });
|
||||
// 1) Try Directus directly with the identifier (email OR username)
|
||||
// Directus expects the field name "email" for both.
|
||||
const tryIds: string[] = [identifier];
|
||||
|
||||
// 2) Fallback: if it doesn’t look like an email, try the canonical email (if any)
|
||||
if (!identifier.includes("@")) {
|
||||
try {
|
||||
const em = await emailForUsername(identifier); // returns string|null
|
||||
if (em && em !== identifier) tryIds.push(em);
|
||||
} catch {
|
||||
// ignore lookup errors, we'll just rely on the first attempt
|
||||
}
|
||||
}
|
||||
|
||||
// Login against Directus; helper returns { access_token, expires } (root or .data)
|
||||
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 }
|
||||
);
|
||||
let tokens: any = null;
|
||||
let lastErr: any = null;
|
||||
for (const id of tryIds) {
|
||||
try {
|
||||
tokens = await loginDirectus(id, password); // { access_token, refresh_token, expires? }
|
||||
if (tokens) break;
|
||||
} catch (e) {
|
||||
lastErr = e;
|
||||
}
|
||||
}
|
||||
|
||||
if (!tokens?.access_token) {
|
||||
const msg =
|
||||
lastErr?.response?.data?.errors?.[0]?.message ||
|
||||
lastErr?.response?.data?.error ||
|
||||
lastErr?.message ||
|
||||
"Invalid credentials.";
|
||||
return NextResponse.json({ error: msg }, { status: 401 });
|
||||
}
|
||||
|
||||
// Set HttpOnly cookies for your middleware
|
||||
const maxAge = 60 * 60; // 1h
|
||||
const res = NextResponse.json({ ok: true });
|
||||
|
||||
// Use provider TTL if present, 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,
|
||||
res.cookies.set("ma_at", tokens.access_token, {
|
||||
path: "/",
|
||||
httpOnly: true,
|
||||
sameSite: "lax",
|
||||
secure,
|
||||
path: "/",
|
||||
maxAge,
|
||||
});
|
||||
|
||||
if (tokens.refresh_token) {
|
||||
res.cookies.set("ma_rt", tokens.refresh_token, {
|
||||
path: "/",
|
||||
httpOnly: true,
|
||||
sameSite: "lax",
|
||||
secure,
|
||||
maxAge: 60 * 60 * 24 * 30, // 30d
|
||||
});
|
||||
}
|
||||
return res;
|
||||
} catch (err: any) {
|
||||
const message =
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue