Add Login and Dashboard
This commit is contained in:
86
src/app/api/auth/refresh/route.ts
Normal file
86
src/app/api/auth/refresh/route.ts
Normal file
@@ -0,0 +1,86 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { API_BASE, COOKIE_SECURE, COOKIE_SAMESITE } from "@/lib/config";
|
||||
import { resolveTenantFromRequest } from "@/lib/server-tenant";
|
||||
import type { UpstreamRefreshResponse } from "@/types/auth";
|
||||
|
||||
const DEBUG_AUTH = (process.env.DEBUG_AUTH ?? "true").toLowerCase() === "true";
|
||||
|
||||
export async function POST(req: NextRequest) {
|
||||
const tenantKey = resolveTenantFromRequest(req);
|
||||
const url = `${API_BASE}/api/authentication/refresh`;
|
||||
const refresh = req.cookies.get("refresh_token")?.value;
|
||||
|
||||
try {
|
||||
const r = await fetch(url, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"X-Tenant": tenantKey,
|
||||
...(refresh ? { Cookie: `refresh_token=${encodeURIComponent(refresh)}` } : {}),
|
||||
},
|
||||
body: JSON.stringify({}),
|
||||
redirect: "manual",
|
||||
});
|
||||
|
||||
const rawText = await r.text();
|
||||
let data: UpstreamRefreshResponse | { _raw?: string };
|
||||
try {
|
||||
data = rawText ? (JSON.parse(rawText) as UpstreamRefreshResponse) : ({} as UpstreamRefreshResponse);
|
||||
} catch {
|
||||
data = { _raw: rawText };
|
||||
}
|
||||
|
||||
if (DEBUG_AUTH) {
|
||||
console.log("[auth/refresh] ← upstream", {
|
||||
status: r.status,
|
||||
hasAccessToken: Boolean((data as UpstreamRefreshResponse)?.access_token),
|
||||
bodyPreview: rawText.slice(0, 160),
|
||||
});
|
||||
}
|
||||
|
||||
if (!r.ok) {
|
||||
return NextResponse.json({ message: (data as { message?: string })?.message ?? "Refresh failed" }, { status: r.status });
|
||||
}
|
||||
|
||||
const nextRes = NextResponse.json(
|
||||
{ token_type: (data as UpstreamRefreshResponse).token_type ?? "Bearer", expires_at: (data as UpstreamRefreshResponse).expires_at },
|
||||
{ status: 200 },
|
||||
);
|
||||
|
||||
if ((data as UpstreamRefreshResponse)?.access_token && (data as UpstreamRefreshResponse)?.expires_at) {
|
||||
nextRes.cookies.set("access_token", (data as UpstreamRefreshResponse).access_token!, {
|
||||
httpOnly: false,
|
||||
secure: COOKIE_SECURE,
|
||||
sameSite: COOKIE_SAMESITE,
|
||||
path: "/",
|
||||
expires: new Date((data as UpstreamRefreshResponse).expires_at!),
|
||||
});
|
||||
}
|
||||
|
||||
const setCookieHeader = r.headers.get("set-cookie") ?? "";
|
||||
const parts = setCookieHeader.split(/,(?=\s*[a-zA-Z0-9_\-]+=)/).map((s) => s.trim());
|
||||
const refreshPart = parts.find((p) => p.toLowerCase().startsWith("refresh_token="));
|
||||
if (refreshPart) {
|
||||
const match = refreshPart.match(/^refresh_token=([^;]+)/i);
|
||||
if (match) {
|
||||
const refreshValue = decodeURIComponent(match[1]);
|
||||
const expMatch = refreshPart.match(/expires=([^;]+)/i);
|
||||
const expires = expMatch ? new Date(expMatch[1]) : undefined;
|
||||
|
||||
nextRes.cookies.set("refresh_token", refreshValue, {
|
||||
httpOnly: true,
|
||||
secure: COOKIE_SECURE,
|
||||
sameSite: COOKIE_SAMESITE,
|
||||
path: "/",
|
||||
expires,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return nextRes;
|
||||
} catch (e) {
|
||||
const err = e as Error;
|
||||
console.error("[auth/refresh] error:", err.message);
|
||||
return NextResponse.json({ message: "Server error", detail: err.message }, { status: 500 });
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user