diff --git a/apps/login/src/app/login/route.ts b/apps/login/src/app/login/route.ts index dd91519ee4..2db81e070e 100644 --- a/apps/login/src/app/login/route.ts +++ b/apps/login/src/app/login/route.ts @@ -3,7 +3,7 @@ import { idpTypeToSlug } from "@/lib/idp"; import { loginWithOIDCandSession } from "@/lib/oidc"; import { loginWithSAMLandSession } from "@/lib/saml"; import { sendLoginname, SendLoginnameCommand } from "@/lib/server/loginname"; -import { getServiceUrlFromHeaders } from "@/lib/service"; +import { constructUrl, getServiceUrlFromHeaders } from "@/lib/service"; import { findValidSession } from "@/lib/session"; import { createCallback, @@ -39,7 +39,7 @@ const gotoAccounts = ({ requestId: string; organization?: string; }): NextResponse => { - const accountsUrl = new URL("/accounts", request.url); + const accountsUrl = constructUrl(request, "/accounts"); if (requestId) { accountsUrl.searchParams.set("requestId", requestId); @@ -223,7 +223,7 @@ export async function GET(request: NextRequest) { } if (authRequest && authRequest.prompt.includes(Prompt.CREATE)) { - const registerUrl = new URL("/register", request.url); + const registerUrl = constructUrl(request, "/register"); if (authRequest.id) { registerUrl.searchParams.set("requestId", `oidc_${authRequest.id}`); } @@ -263,7 +263,7 @@ export async function GET(request: NextRequest) { const res = await sendLoginname(command); if (res && "redirect" in res && res?.redirect) { - const absoluteUrl = new URL(res.redirect, request.url); + const absoluteUrl = constructUrl(request, res.redirect); return NextResponse.redirect(absoluteUrl.toString()); } } catch (error) { @@ -271,7 +271,7 @@ export async function GET(request: NextRequest) { } } - const loginNameUrl = new URL("/loginname", request.url); + const loginNameUrl = constructUrl(request, "/loginname"); if (authRequest.id) { loginNameUrl.searchParams.set("requestId", `oidc_${authRequest.id}`); } @@ -398,7 +398,7 @@ export async function GET(request: NextRequest) { } } } else { - const loginNameUrl = new URL("/loginname", request.url); + const loginNameUrl = constructUrl(request, "/loginname"); loginNameUrl.searchParams.set("requestId", requestId); if (authRequest?.loginHint) { diff --git a/apps/login/src/lib/oidc.ts b/apps/login/src/lib/oidc.ts index fd74e57027..c1038d90c4 100644 --- a/apps/login/src/lib/oidc.ts +++ b/apps/login/src/lib/oidc.ts @@ -8,6 +8,7 @@ import { } from "@zitadel/proto/zitadel/oidc/v2/oidc_service_pb"; import { Session } from "@zitadel/proto/zitadel/session/v2/session_pb"; import { NextRequest, NextResponse } from "next/server"; +import { constructUrl } from "./service"; import { isSessionValid } from "./session"; type LoginWithOIDCandSession = { @@ -54,7 +55,7 @@ export async function loginWithOIDCandSession({ const res = await sendLoginname(command); if (res && "redirect" in res && res?.redirect) { - const absoluteUrl = new URL(res.redirect, request.url); + const absoluteUrl = constructUrl(request, res.redirect); return NextResponse.redirect(absoluteUrl.toString()); } } @@ -107,7 +108,7 @@ export async function loginWithOIDCandSession({ return NextResponse.redirect(loginSettings.defaultRedirectUri); } - const signedinUrl = new URL("/signedin", request.url); + const signedinUrl = constructUrl(request, "/signedin"); if (selectedSession.factors?.user?.loginName) { signedinUrl.searchParams.set( diff --git a/apps/login/src/lib/saml.ts b/apps/login/src/lib/saml.ts index d559c8e7df..9b12e48d25 100644 --- a/apps/login/src/lib/saml.ts +++ b/apps/login/src/lib/saml.ts @@ -5,6 +5,7 @@ import { create } from "@zitadel/client"; import { CreateResponseRequestSchema } from "@zitadel/proto/zitadel/saml/v2/saml_service_pb"; import { Session } from "@zitadel/proto/zitadel/session/v2/session_pb"; import { NextRequest, NextResponse } from "next/server"; +import { constructUrl } from "./service"; import { isSessionValid } from "./session"; type LoginWithSAMLandSession = { @@ -52,7 +53,7 @@ export async function loginWithSAMLandSession({ const res = await sendLoginname(command); if (res && "redirect" in res && res?.redirect) { - const absoluteUrl = new URL(res.redirect, request.url); + const absoluteUrl = constructUrl(request, res.redirect); return NextResponse.redirect(absoluteUrl.toString()); } } @@ -105,7 +106,7 @@ export async function loginWithSAMLandSession({ return NextResponse.redirect(loginSettings.defaultRedirectUri); } - const signedinUrl = new URL("/signedin", request.url); + const signedinUrl = constructUrl(request, "/signedin"); if (selectedSession.factors?.user?.loginName) { signedinUrl.searchParams.set( diff --git a/apps/login/src/lib/service.ts b/apps/login/src/lib/service.ts index b6d320c0f4..ec01c619f5 100644 --- a/apps/login/src/lib/service.ts +++ b/apps/login/src/lib/service.ts @@ -8,6 +8,7 @@ import { SessionService } from "@zitadel/proto/zitadel/session/v2/session_servic import { SettingsService } from "@zitadel/proto/zitadel/settings/v2/settings_service_pb"; import { UserService } from "@zitadel/proto/zitadel/user/v2/user_service_pb"; import { ReadonlyHeaders } from "next/dist/server/web/spec-extension/adapters/headers"; +import { NextRequest } from "next/server"; import { systemAPIToken } from "./api"; type ServiceClass = @@ -108,3 +109,16 @@ export function getServiceUrlFromHeaders(headers: ReadonlyHeaders): { serviceUrl: instanceUrl, }; } + +export function constructUrl(request: NextRequest, path: string) { + const forwardedProto = request.headers.get("x-forwarded-proto") + ? `${request.headers.get("x-forwarded-proto")}:` + : request.nextUrl.protocol; + + const forwardedHost = + request.headers.get("x-zitadel-forward-host") ?? + request.headers.get("x-forwarded-host") ?? + request.headers.get("host"); + const basePath = process.env.NEXT_PUBLIC_BASE_PATH || ""; + return new URL(`${basePath}${path}`, `${forwardedProto}//${forwardedHost}`); +}