mirror of
https://github.com/andwati/zitadel.git
synced 2026-10-21 23:14:26 +00:00
fix(login): use constructUrl for implicit IdP success/failure URLs (#11389)
Closes #11386 # Which Problems Are Solved This PR fixes an issue where the `successUrl` and `failureUrl` for implicit IdP flows (initiated via OIDC `idp🆔...` scopes) were being constructed using `request.nextUrl.origin`. This failed to account for: - `x-zitadel-forward-host` headers (essential for proper public URL resolution). - `NEXT_PUBLIC_BASE_PATH` configuration. # How the Problems Are Solved The fix replaces the manual string concatenation with the shared `constructUrl` helper, ensuring consistent and correct URL generation. Co-authored-by: Livio Spring <[email protected]>
This commit is contained in:
co-authored by
Livio Spring
parent
1fc6f048a9
commit
a10d13e2ec
@@ -1,3 +1,5 @@
|
||||
import { idpTypeToSlug } from "@/lib/idp";
|
||||
import { sendLoginname, SendLoginnameCommand } from "@/lib/server/loginname";
|
||||
import { constructUrl } from "@/lib/service-url";
|
||||
import { findValidSession } from "@/lib/session";
|
||||
import {
|
||||
@@ -8,11 +10,9 @@ import {
|
||||
getOrgsByDomain,
|
||||
getSAMLRequest,
|
||||
getSecuritySettings,
|
||||
startIdentityProviderFlow,
|
||||
ServiceConfig,
|
||||
startIdentityProviderFlow,
|
||||
} from "@/lib/zitadel";
|
||||
import { sendLoginname, SendLoginnameCommand } from "@/lib/server/loginname";
|
||||
import { idpTypeToSlug } from "@/lib/idp";
|
||||
import { create } from "@zitadel/client";
|
||||
import { Prompt } from "@zitadel/proto/zitadel/oidc/v2/authorization_pb";
|
||||
import { CreateCallbackRequestSchema, SessionSchema } from "@zitadel/proto/zitadel/oidc/v2/oidc_service_pb";
|
||||
@@ -61,8 +61,7 @@ export interface FlowInitiationParams {
|
||||
export async function handleOIDCFlowInitiation(params: FlowInitiationParams): Promise<NextResponse> {
|
||||
const { serviceConfig, requestId, sessions, sessionCookies, request } = params;
|
||||
|
||||
const { authRequest } = await getAuthRequest({ serviceConfig, authRequestId: requestId.replace("oidc_", ""),
|
||||
});
|
||||
const { authRequest } = await getAuthRequest({ serviceConfig, authRequestId: requestId.replace("oidc_", "") });
|
||||
|
||||
let organization = "";
|
||||
let suffix = "";
|
||||
@@ -84,8 +83,7 @@ export async function handleOIDCFlowInitiation(params: FlowInitiationParams): Pr
|
||||
|
||||
console.log("Extracted org domain:", orgDomain);
|
||||
if (orgDomain) {
|
||||
const orgs = await getOrgsByDomain({ serviceConfig, domain: orgDomain,
|
||||
});
|
||||
const orgs = await getOrgsByDomain({ serviceConfig, domain: orgDomain });
|
||||
|
||||
if (orgs.result && orgs.result.length === 1) {
|
||||
organization = orgs.result[0].id ?? "";
|
||||
@@ -99,7 +97,9 @@ export async function handleOIDCFlowInitiation(params: FlowInitiationParams): Pr
|
||||
const matched = IDP_SCOPE_REGEX.exec(idpScope);
|
||||
idpId = matched?.[1] ?? "";
|
||||
|
||||
const identityProviders = await getActiveIdentityProviders({ serviceConfig, orgId: organization ? organization : undefined,
|
||||
const identityProviders = await getActiveIdentityProviders({
|
||||
serviceConfig,
|
||||
orgId: organization ? organization : undefined,
|
||||
}).then((resp) => {
|
||||
return resp.identityProviders;
|
||||
});
|
||||
@@ -107,7 +107,6 @@ export async function handleOIDCFlowInitiation(params: FlowInitiationParams): Pr
|
||||
const idp = identityProviders.find((idp) => idp.id === idpId);
|
||||
|
||||
if (idp) {
|
||||
const origin = request.nextUrl.origin;
|
||||
const identityProviderType = identityProviders[0].type;
|
||||
|
||||
if (identityProviderType === IdentityProviderType.LDAP) {
|
||||
@@ -132,10 +131,12 @@ export async function handleOIDCFlowInitiation(params: FlowInitiationParams): Pr
|
||||
params.set("organization", organization);
|
||||
}
|
||||
|
||||
let url: string | null = await startIdentityProviderFlow({ serviceConfig, idpId,
|
||||
let url: string | null = await startIdentityProviderFlow({
|
||||
serviceConfig,
|
||||
idpId,
|
||||
urls: {
|
||||
successUrl: `${origin}/idp/${provider}/process?` + new URLSearchParams(params),
|
||||
failureUrl: `${origin}/idp/${provider}/failure?` + new URLSearchParams(params),
|
||||
successUrl: constructUrl(request, `/idp/${provider}/process?${params.toString()}`).toString(),
|
||||
failureUrl: constructUrl(request, `/idp/${provider}/failure?${params.toString()}`).toString(),
|
||||
},
|
||||
});
|
||||
|
||||
@@ -208,11 +209,9 @@ export async function handleOIDCFlowInitiation(params: FlowInitiationParams): Pr
|
||||
}
|
||||
return NextResponse.redirect(loginNameUrl);
|
||||
} else if (authRequest.prompt.includes(Prompt.NONE)) {
|
||||
const securitySettings = await getSecuritySettings({ serviceConfig, });
|
||||
const securitySettings = await getSecuritySettings({ serviceConfig });
|
||||
|
||||
const selectedSession = await findValidSession({ serviceConfig, sessions,
|
||||
authRequest,
|
||||
});
|
||||
const selectedSession = await findValidSession({ serviceConfig, sessions, authRequest });
|
||||
|
||||
const noSessionResponse = NextResponse.json({ error: "No active session found" }, { status: 400 });
|
||||
|
||||
@@ -240,7 +239,9 @@ export async function handleOIDCFlowInitiation(params: FlowInitiationParams): Pr
|
||||
sessionToken: cookie.token,
|
||||
};
|
||||
|
||||
const { callbackUrl } = await createCallback({ serviceConfig, req: create(CreateCallbackRequestSchema, {
|
||||
const { callbackUrl } = await createCallback({
|
||||
serviceConfig,
|
||||
req: create(CreateCallbackRequestSchema, {
|
||||
authRequestId: requestId.replace("oidc_", ""),
|
||||
callbackKind: {
|
||||
case: "session",
|
||||
@@ -262,9 +263,7 @@ export async function handleOIDCFlowInitiation(params: FlowInitiationParams): Pr
|
||||
|
||||
return callbackResponse;
|
||||
} else {
|
||||
let selectedSession = await findValidSession({ serviceConfig, sessions,
|
||||
authRequest,
|
||||
});
|
||||
let selectedSession = await findValidSession({ serviceConfig, sessions, authRequest });
|
||||
|
||||
if (!selectedSession || !selectedSession.id) {
|
||||
return gotoAccounts({
|
||||
@@ -290,7 +289,9 @@ export async function handleOIDCFlowInitiation(params: FlowInitiationParams): Pr
|
||||
};
|
||||
|
||||
try {
|
||||
const { callbackUrl } = await createCallback({ serviceConfig, req: create(CreateCallbackRequestSchema, {
|
||||
const { callbackUrl } = await createCallback({
|
||||
serviceConfig,
|
||||
req: create(CreateCallbackRequestSchema, {
|
||||
authRequestId: requestId.replace("oidc_", ""),
|
||||
callbackKind: {
|
||||
case: "session",
|
||||
@@ -344,8 +345,7 @@ export async function handleOIDCFlowInitiation(params: FlowInitiationParams): Pr
|
||||
export async function handleSAMLFlowInitiation(params: FlowInitiationParams): Promise<NextResponse> {
|
||||
const { serviceConfig, requestId, sessions, sessionCookies, request } = params;
|
||||
|
||||
const { samlRequest } = await getSAMLRequest({ serviceConfig, samlRequestId: requestId.replace("saml_", ""),
|
||||
});
|
||||
const { samlRequest } = await getSAMLRequest({ serviceConfig, samlRequestId: requestId.replace("saml_", "") });
|
||||
|
||||
if (!samlRequest) {
|
||||
return NextResponse.json({ error: "No samlRequest found" }, { status: 400 });
|
||||
@@ -359,9 +359,7 @@ export async function handleSAMLFlowInitiation(params: FlowInitiationParams): Pr
|
||||
}
|
||||
|
||||
// Try to find a valid session
|
||||
let selectedSession = await findValidSession({ serviceConfig, sessions,
|
||||
samlRequest,
|
||||
});
|
||||
let selectedSession = await findValidSession({ serviceConfig, sessions, samlRequest });
|
||||
|
||||
// Early return: No valid session found - show account selection
|
||||
if (!selectedSession || !selectedSession.id) {
|
||||
@@ -389,7 +387,9 @@ export async function handleSAMLFlowInitiation(params: FlowInitiationParams): Pr
|
||||
};
|
||||
|
||||
try {
|
||||
const { url, binding } = await createResponse({ serviceConfig, req: create(CreateResponseRequestSchema, {
|
||||
const { url, binding } = await createResponse({
|
||||
serviceConfig,
|
||||
req: create(CreateResponseRequestSchema, {
|
||||
samlRequestId: requestId.replace("saml_", ""),
|
||||
responseKind: {
|
||||
case: "session",
|
||||
|
||||
Reference in New Issue
Block a user