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 }); } }