Files
zitadel/apps/login/src/lib/server/host.ts
T
b1c8781516 fix(login): lru-cache compatibility, improve session error handling (#12099)
# Which Problems Are Solved

- Logo and heading overlap on login pages due to a -mb-4 negative margin
on the logo container
- The /login route returns a 500 when `listSessions` fails (e.g. stale
session cookies), because loadSessions has no error handling.
- The proxy logs `"fetch() returned undefined"` because
`fetchIframeOrigins` returns undefined, which lru-cache's forceFetch
treats as a fetch failure.

# How the Problems Are Solved

- Remove `-mb-4` from the logo container in DynamicTheme.
- Wrap `loadSessions` in a try/catch — failures fall through as empty
sessions instead of crashing.
- Return `null` instead of `undefined` from `fetchIframeOrigins` so
lru-cache caches it normally.

---------

Co-authored-by: Livio Spring <[email protected]>
Co-authored-by: conblem <[email protected]>
2026-04-30 15:27:44 +02:00

50 lines
1.9 KiB
TypeScript

import { ReadonlyHeaders } from "next/dist/server/web/spec-extension/adapters/headers";
/**
* Gets the original host that the user sees in their browser URL.
* When using rewrites this function prioritizes forwarded headers that preserve the original host.
*
* @returns The host string (e.g., "zitadel.com")
* @throws Error if no host is found
*/
export function getInstanceHost(headers: ReadonlyHeaders): string | null {
// use standard proxy headers (x-forwarded-host → host) for both multi-tenant and self-hosted, do not use x-zitadel-instance-host
const instanceHost =
headers.get("x-zitadel-instance-host") || headers.get("x-zitadel-forward-host") || headers.get("host");
return instanceHost;
}
/**
* Gets the public host that the user sees in their browser URL.
* Only considers standard proxy headers (x-forwarded-host and host).
* Does NOT include x-zitadel-instance-host.
*
* Use this when you need the public-facing host that the user actually sees,
* not the internal instance host used for API routing.
*
* @returns The public host string (e.g., "accounts.company.com")
* @throws Error if no host is found
*/
export function getPublicHost(headers: ReadonlyHeaders): string {
// Only use standard proxy headers (x-zitadel-public-host → x-zitadel-forward-host → x-forwarded-host → host)
// Do NOT use x-zitadel-instance-host as it may differ from what the user sees
const publicHost =
headers.get("x-zitadel-public-host") ||
headers.get("x-zitadel-forward-host") ||
headers.get("x-forwarded-host") ||
headers.get("host");
if (!publicHost || typeof publicHost !== "string") {
throw new Error("No host found in headers");
}
return publicHost;
}
export function getPublicHostWithProtocol(headers: ReadonlyHeaders): string {
const host = getPublicHost(headers);
const protocol = host.includes("localhost") ? "http://" : "https://";
return `${protocol}${host}`;
}