diff --git a/litellm/proxy/proxy_server.py b/litellm/proxy/proxy_server.py index ddfba140ff2..c8fea12b272 100644 --- a/litellm/proxy/proxy_server.py +++ b/litellm/proxy/proxy_server.py @@ -11029,6 +11029,9 @@ async def login_v2(request: Request): # noqa: PLR0915 litellm_dashboard_ui += "/ui/" litellm_dashboard_ui += "?login=success" + # Token is included in the response body so the UI can set a JS-accessible + # cookie even when a reverse proxy (e.g. nginx-ingress) adds HttpOnly to the + # server-set cookie, which would otherwise cause an infinite login redirect. json_response = JSONResponse( content={"redirect_url": litellm_dashboard_ui, "token": jwt_token}, status_code=status.HTTP_200_OK, diff --git a/ui/litellm-dashboard/src/utils/cookieUtils.test.ts b/ui/litellm-dashboard/src/utils/cookieUtils.test.ts index 84935606d62..0e3ec1eb8c6 100644 --- a/ui/litellm-dashboard/src/utils/cookieUtils.test.ts +++ b/ui/litellm-dashboard/src/utils/cookieUtils.test.ts @@ -140,6 +140,18 @@ describe("cookieUtils", () => { global.document = originalDocument; }); + + it("should not throw when window is undefined (server-side rendering)", () => { + const originalWindow = global.window; + const originalDocument = global.document; + delete (global as any).window; + delete (global as any).document; + + expect(() => setTokenCookie("token")).not.toThrow(); + + global.window = originalWindow; + global.document = originalDocument; + }); }); describe("getCookie", () => { diff --git a/ui/litellm-dashboard/src/utils/cookieUtils.ts b/ui/litellm-dashboard/src/utils/cookieUtils.ts index 3b7b3551ebb..9a6f34a0acc 100644 --- a/ui/litellm-dashboard/src/utils/cookieUtils.ts +++ b/ui/litellm-dashboard/src/utils/cookieUtils.ts @@ -51,7 +51,7 @@ export function clearTokenCookies() { * This ensures the token is JS-accessible even when a reverse proxy adds HttpOnly to server-set cookies. */ export function setTokenCookie(token: string) { - if (typeof document === "undefined") return; + if (typeof window === "undefined" || typeof document === "undefined") return; const isSecure = window.location.protocol === "https:"; document.cookie = `token=${token}; Path=/; SameSite=Lax${isSecure ? "; Secure" : ""}`; }