diff --git a/apps/login/next-env-vars.d.ts b/apps/login/next-env-vars.d.ts index be266fd5a04..35fcb109197 100644 --- a/apps/login/next-env-vars.d.ts +++ b/apps/login/next-env-vars.d.ts @@ -1,19 +1,13 @@ declare namespace NodeJS { interface ProcessEnv { - /** - * Multitenancy: The system api url - */ - AUDIENCE: string; + // Allow any environment variable that matches the pattern + [key: `${string}_AUDIENCE`]: string; // The system api url + [key: `${string}_SYSTEM_USER_ID`]: string; // The service user id + [key: `${string}_SYSTEM_USER_PRIVATE_KEY`]: string; // The service user private key - /** - * Multitenancy: The service user id - */ - SYSTEM_USER_ID: string; - - /** - * Multitenancy: The service user private key - */ - SYSTEM_USER_PRIVATE_KEY: string; + AUDIENCE: string; // The fallback system api url + SYSTEM_USER_ID: string; // The fallback service user id + SYSTEM_USER_PRIVATE_KEY: string; // The fallback service user private key /** * Self hosting: The instance url diff --git a/apps/login/src/app/(login)/accounts/page.tsx b/apps/login/src/app/(login)/accounts/page.tsx index e9518dbfb5b..bc63d990c9c 100644 --- a/apps/login/src/app/(login)/accounts/page.tsx +++ b/apps/login/src/app/(login)/accounts/page.tsx @@ -13,12 +13,19 @@ import { getLocale, getTranslations } from "next-intl/server"; import { headers } from "next/headers"; import Link from "next/link"; -async function loadSessions({ serviceUrl }: { serviceUrl: string }) { +async function loadSessions({ + serviceUrl, + serviceRegion, +}: { + serviceUrl: string; + serviceRegion: string; +}) { const ids: (string | undefined)[] = await getAllSessionCookieIds(); if (ids && ids.length) { const response = await listSessions({ serviceUrl, + serviceRegion, ids: ids.filter((id) => !!id) as string[], }); return response?.sessions ?? []; @@ -39,20 +46,24 @@ export default async function Page(props: { const organization = searchParams?.organization; const _headers = await headers(); - const serviceUrl = getServiceUrlFromHeaders(_headers); + const { serviceUrl, serviceRegion } = getServiceUrlFromHeaders(_headers); let defaultOrganization; if (!organization) { - const org: Organization | null = await getDefaultOrg({ serviceUrl }); + const org: Organization | null = await getDefaultOrg({ + serviceUrl, + serviceRegion, + }); if (org) { defaultOrganization = org.id; } } - let sessions = await loadSessions({ serviceUrl }); + let sessions = await loadSessions({ serviceUrl, serviceRegion }); const branding = await getBrandingSettings({ serviceUrl, + serviceRegion, organization: organization ?? defaultOrganization, }); diff --git a/apps/login/src/app/(login)/authenticator/set/page.tsx b/apps/login/src/app/(login)/authenticator/set/page.tsx index 28bc0b70774..634b1168158 100644 --- a/apps/login/src/app/(login)/authenticator/set/page.tsx +++ b/apps/login/src/app/(login)/authenticator/set/page.tsx @@ -30,37 +30,41 @@ export default async function Page(props: { const { loginName, authRequestId, organization, sessionId } = searchParams; const _headers = await headers(); - const serviceUrl = getServiceUrlFromHeaders(_headers); + const { serviceUrl, serviceRegion } = getServiceUrlFromHeaders(_headers); const sessionWithData = sessionId ? await loadSessionById(serviceUrl, sessionId, organization) : await loadSessionByLoginname(serviceUrl, loginName, organization); - async function getAuthMethodsAndUser(host: string, session?: Session) { + async function getAuthMethodsAndUser( + serviceUrl: string, + serviceRegion: string, + session?: Session, + ) { const userId = session?.factors?.user?.id; if (!userId) { throw Error("Could not get user id from session"); } - return listAuthenticationMethodTypes({ serviceUrl, userId }).then( - (methods) => { - return getUserByID({ serviceUrl, userId }).then((user) => { - const humanUser = - user.user?.type.case === "human" - ? user.user?.type.value - : undefined; + return listAuthenticationMethodTypes({ + serviceUrl, + serviceRegion, + userId, + }).then((methods) => { + return getUserByID({ serviceUrl, serviceRegion, userId }).then((user) => { + const humanUser = + user.user?.type.case === "human" ? user.user?.type.value : undefined; - return { - factors: session?.factors, - authMethods: methods.authMethodTypes ?? [], - phoneVerified: humanUser?.phone?.isVerified ?? false, - emailVerified: humanUser?.email?.isVerified ?? false, - expirationDate: session?.expirationDate, - }; - }); - }, - ); + return { + factors: session?.factors, + authMethods: methods.authMethodTypes ?? [], + phoneVerified: humanUser?.phone?.isVerified ?? false, + emailVerified: humanUser?.email?.isVerified ?? false, + expirationDate: session?.expirationDate, + }; + }); + }); } async function loadSessionByLoginname( @@ -70,12 +74,13 @@ export default async function Page(props: { ) { return loadMostRecentSession({ serviceUrl, + serviceRegion, sessionParams: { loginName, organization, }, }).then((session) => { - return getAuthMethodsAndUser(serviceUrl, session); + return getAuthMethodsAndUser(serviceUrl, serviceRegion, session); }); } @@ -87,10 +92,15 @@ export default async function Page(props: { const recent = await getSessionCookieById({ sessionId, organization }); return getSession({ serviceUrl, + serviceRegion, sessionId: recent.id, sessionToken: recent.token, }).then((sessionResponse) => { - return getAuthMethodsAndUser(serviceUrl, sessionResponse.session); + return getAuthMethodsAndUser( + serviceUrl, + serviceRegion, + sessionResponse.session, + ); }); } @@ -100,16 +110,19 @@ export default async function Page(props: { const branding = await getBrandingSettings({ serviceUrl, + serviceRegion, organization: sessionWithData.factors?.user?.organizationId, }); const loginSettings = await getLoginSettings({ serviceUrl, + serviceRegion, organization: sessionWithData.factors?.user?.organizationId, }); const identityProviders = await getActiveIdentityProviders({ serviceUrl, + serviceRegion, orgId: sessionWithData.factors?.user?.organizationId, linking_allowed: true, }).then((resp) => { diff --git a/apps/login/src/app/(login)/idp/[provider]/failure/page.tsx b/apps/login/src/app/(login)/idp/[provider]/failure/page.tsx index bb1272f332b..c1e4de1b269 100644 --- a/apps/login/src/app/(login)/idp/[provider]/failure/page.tsx +++ b/apps/login/src/app/(login)/idp/[provider]/failure/page.tsx @@ -25,9 +25,13 @@ export default async function Page(props: { const { organization } = searchParams; const _headers = await headers(); - const serviceUrl = getServiceUrlFromHeaders(_headers); + const { serviceUrl, serviceRegion } = getServiceUrlFromHeaders(_headers); - const branding = await getBrandingSettings({ serviceUrl, organization }); + const branding = await getBrandingSettings({ + serviceUrl, + serviceRegion, + organization, + }); return ( diff --git a/apps/login/src/app/(login)/idp/[provider]/success/page.tsx b/apps/login/src/app/(login)/idp/[provider]/success/page.tsx index 0d26606a3e0..425e9f0caf8 100644 --- a/apps/login/src/app/(login)/idp/[provider]/success/page.tsx +++ b/apps/login/src/app/(login)/idp/[provider]/success/page.tsx @@ -40,9 +40,13 @@ export default async function Page(props: { const { provider } = params; const _headers = await headers(); - const serviceUrl = getServiceUrlFromHeaders(_headers); + const { serviceUrl, serviceRegion } = getServiceUrlFromHeaders(_headers); - const branding = await getBrandingSettings({ serviceUrl, organization }); + const branding = await getBrandingSettings({ + serviceUrl, + serviceRegion, + organization, + }); if (!provider || !id || !token) { return loginFailed(branding, "IDP context missing"); @@ -50,6 +54,7 @@ export default async function Page(props: { const intent = await retrieveIDPIntent({ serviceUrl, + serviceRegion, id, token, }); @@ -72,7 +77,11 @@ export default async function Page(props: { return loginFailed(branding, "IDP information missing"); } - const idp = await getIDPByID({ serviceUrl, id: idpInformation.idpId }); + const idp = await getIDPByID({ + serviceUrl, + serviceRegion, + id: idpInformation.idpId, + }); const options = idp?.config?.options; if (!idp) { @@ -91,6 +100,7 @@ export default async function Page(props: { try { idpLink = await addIDPLink({ serviceUrl, + serviceRegion, idp: { id: idpInformation.idpId, userId: idpInformation.userId, @@ -121,20 +131,23 @@ export default async function Page(props: { const email = PROVIDER_MAPPING[providerType](idpInformation).email?.email; if (options.autoLinking === AutoLinkingOption.EMAIL && email) { - foundUser = await listUsers({ serviceUrl, email }).then((response) => { - return response.result ? response.result[0] : null; - }); + foundUser = await listUsers({ serviceUrl, serviceRegion, email }).then( + (response) => { + return response.result ? response.result[0] : null; + }, + ); } else if (options.autoLinking === AutoLinkingOption.USERNAME) { foundUser = await listUsers( options.autoLinking === AutoLinkingOption.USERNAME - ? { serviceUrl, userName: idpInformation.userName } - : { serviceUrl, email }, + ? { serviceUrl, serviceRegion, userName: idpInformation.userName } + : { serviceUrl, serviceRegion, email }, ).then((response) => { return response.result ? response.result[0] : null; }); } else { foundUser = await listUsers({ serviceUrl, + serviceRegion, userName: idpInformation.userName, email, }).then((response) => { @@ -147,6 +160,7 @@ export default async function Page(props: { try { idpLink = await addIDPLink({ serviceUrl, + serviceRegion, idp: { id: idpInformation.idpId, userId: idpInformation.userId, @@ -187,12 +201,17 @@ export default async function Page(props: { const suffix = matched?.[1] ?? ""; // this just returns orgs where the suffix is set as primary domain - const orgs = await getOrgsByDomain({ serviceUrl, domain: suffix }); + const orgs = await getOrgsByDomain({ + serviceUrl, + serviceRegion, + domain: suffix, + }); const orgToCheckForDiscovery = orgs.result && orgs.result.length === 1 ? orgs.result[0].id : undefined; const orgLoginSettings = await getLoginSettings({ serviceUrl, + serviceRegion, organization: orgToCheckForDiscovery, }); if (orgLoginSettings?.allowDomainDiscovery) { @@ -211,7 +230,11 @@ export default async function Page(props: { }); } - const newUser = await addHuman({ serviceUrl, request: userData }); + const newUser = await addHuman({ + serviceUrl, + serviceRegion, + request: userData, + }); if (newUser) { return ( diff --git a/apps/login/src/app/(login)/idp/page.tsx b/apps/login/src/app/(login)/idp/page.tsx index bda16051af9..80829557ecd 100644 --- a/apps/login/src/app/(login)/idp/page.tsx +++ b/apps/login/src/app/(login)/idp/page.tsx @@ -16,16 +16,21 @@ export default async function Page(props: { const organization = searchParams?.organization; const _headers = await headers(); - const serviceUrl = getServiceUrlFromHeaders(_headers); + const { serviceUrl, serviceRegion } = getServiceUrlFromHeaders(_headers); const identityProviders = await getActiveIdentityProviders({ serviceUrl, + serviceRegion, orgId: organization, }).then((resp) => { return resp.identityProviders; }); - const branding = await getBrandingSettings({ serviceUrl, organization }); + const branding = await getBrandingSettings({ + serviceUrl, + serviceRegion, + organization, + }); return ( diff --git a/apps/login/src/app/(login)/invite/page.tsx b/apps/login/src/app/(login)/invite/page.tsx index cc06281eecb..f9c84058556 100644 --- a/apps/login/src/app/(login)/invite/page.tsx +++ b/apps/login/src/app/(login)/invite/page.tsx @@ -21,10 +21,10 @@ export default async function Page(props: { let { firstname, lastname, email, organization } = searchParams; const _headers = await headers(); - const serviceUrl = getServiceUrlFromHeaders(_headers); + const { serviceUrl, serviceRegion } = getServiceUrlFromHeaders(_headers); if (!organization) { - const org = await getDefaultOrg({ serviceUrl }); + const org = await getDefaultOrg({ serviceUrl, serviceRegion }); if (!org) { throw new Error("No default organization found"); } @@ -32,14 +32,23 @@ export default async function Page(props: { organization = org.id; } - const loginSettings = await getLoginSettings({ serviceUrl, organization }); - - const passwordComplexitySettings = await getPasswordComplexitySettings({ + const loginSettings = await getLoginSettings({ serviceUrl, + serviceRegion, organization, }); - const branding = await getBrandingSettings({ serviceUrl, organization }); + const passwordComplexitySettings = await getPasswordComplexitySettings({ + serviceUrl, + serviceRegion, + organization, + }); + + const branding = await getBrandingSettings({ + serviceUrl, + serviceRegion, + organization, + }); return ( diff --git a/apps/login/src/app/(login)/invite/success/page.tsx b/apps/login/src/app/(login)/invite/success/page.tsx index b8692d5c5b3..155849ebb92 100644 --- a/apps/login/src/app/(login)/invite/success/page.tsx +++ b/apps/login/src/app/(login)/invite/success/page.tsx @@ -19,10 +19,10 @@ export default async function Page(props: { let { userId, organization } = searchParams; const _headers = await headers(); - const serviceUrl = getServiceUrlFromHeaders(_headers); + const { serviceUrl, serviceRegion } = getServiceUrlFromHeaders(_headers); if (!organization) { - const org = await getDefaultOrg({ serviceUrl }); + const org = await getDefaultOrg({ serviceUrl, serviceRegion }); if (!org) { throw new Error("No default organization found"); } @@ -30,12 +30,20 @@ export default async function Page(props: { organization = org.id; } - const branding = await getBrandingSettings({ serviceUrl, organization }); + const branding = await getBrandingSettings({ + serviceUrl, + serviceRegion, + organization, + }); let user: User | undefined; let human: HumanUser | undefined; if (userId) { - const userResponse = await getUserByID({ serviceUrl, userId }); + const userResponse = await getUserByID({ + serviceUrl, + serviceRegion, + userId, + }); if (userResponse) { user = userResponse.user; if (user?.type.case === "human") { diff --git a/apps/login/src/app/(login)/loginname/page.tsx b/apps/login/src/app/(login)/loginname/page.tsx index 6e1a97b2b6f..7f8cb928128 100644 --- a/apps/login/src/app/(login)/loginname/page.tsx +++ b/apps/login/src/app/(login)/loginname/page.tsx @@ -26,11 +26,14 @@ export default async function Page(props: { const submit: boolean = searchParams?.submit === "true"; const _headers = await headers(); - const serviceUrl = getServiceUrlFromHeaders(_headers); + const { serviceUrl, serviceRegion } = getServiceUrlFromHeaders(_headers); let defaultOrganization; if (!organization) { - const org: Organization | null = await getDefaultOrg({ serviceUrl }); + const org: Organization | null = await getDefaultOrg({ + serviceUrl, + serviceRegion, + }); if (org) { defaultOrganization = org.id; } @@ -38,16 +41,19 @@ export default async function Page(props: { const loginSettings = await getLoginSettings({ serviceUrl, + serviceRegion, organization: organization ?? defaultOrganization, }); const contextLoginSettings = await getLoginSettings({ serviceUrl, + serviceRegion, organization, }); const identityProviders = await getActiveIdentityProviders({ serviceUrl, + serviceRegion, orgId: organization ?? defaultOrganization, }).then((resp) => { return resp.identityProviders; @@ -55,6 +61,7 @@ export default async function Page(props: { const branding = await getBrandingSettings({ serviceUrl, + serviceRegion, organization: organization ?? defaultOrganization, }); diff --git a/apps/login/src/app/(login)/mfa/page.tsx b/apps/login/src/app/(login)/mfa/page.tsx index ce658129c33..53fc650788c 100644 --- a/apps/login/src/app/(login)/mfa/page.tsx +++ b/apps/login/src/app/(login)/mfa/page.tsx @@ -25,7 +25,7 @@ export default async function Page(props: { const { loginName, authRequestId, organization, sessionId } = searchParams; const _headers = await headers(); - const serviceUrl = getServiceUrlFromHeaders(_headers); + const { serviceUrl, serviceRegion } = getServiceUrlFromHeaders(_headers); const sessionFactors = sessionId ? await loadSessionById(serviceUrl, sessionId, organization) @@ -38,6 +38,7 @@ export default async function Page(props: { ) { return loadMostRecentSession({ serviceUrl, + serviceRegion, sessionParams: { loginName, organization, @@ -46,6 +47,7 @@ export default async function Page(props: { if (session && session.factors?.user?.id) { return listAuthenticationMethodTypes({ serviceUrl, + serviceRegion, userId: session.factors.user.id, }).then((methods) => { return { @@ -65,12 +67,14 @@ export default async function Page(props: { const recent = await getSessionCookieById({ sessionId, organization }); return getSession({ serviceUrl, + serviceRegion, sessionId: recent.id, sessionToken: recent.token, }).then((response) => { if (response?.session && response.session.factors?.user?.id) { return listAuthenticationMethodTypes({ serviceUrl, + serviceRegion, userId: response.session.factors.user.id, }).then((methods) => { return { @@ -82,7 +86,11 @@ export default async function Page(props: { }); } - const branding = await getBrandingSettings({ serviceUrl, organization }); + const branding = await getBrandingSettings({ + serviceUrl, + serviceRegion, + organization, + }); return ( diff --git a/apps/login/src/app/(login)/mfa/set/page.tsx b/apps/login/src/app/(login)/mfa/set/page.tsx index a2a3c5d933f..64e9cd7605b 100644 --- a/apps/login/src/app/(login)/mfa/set/page.tsx +++ b/apps/login/src/app/(login)/mfa/set/page.tsx @@ -52,7 +52,7 @@ export default async function Page(props: { } = searchParams; const _headers = await headers(); - const serviceUrl = getServiceUrlFromHeaders(_headers); + const { serviceUrl, serviceRegion } = getServiceUrlFromHeaders(_headers); const sessionWithData = sessionId ? await loadSessionById(serviceUrl, sessionId, organization) @@ -65,24 +65,24 @@ export default async function Page(props: { throw Error("Could not get user id from session"); } - return listAuthenticationMethodTypes({ serviceUrl, userId }).then( - (methods) => { - return getUserByID({ serviceUrl, userId }).then((user) => { - const humanUser = - user.user?.type.case === "human" - ? user.user?.type.value - : undefined; + return listAuthenticationMethodTypes({ + serviceUrl, + serviceRegion, + userId, + }).then((methods) => { + return getUserByID({ serviceUrl, serviceRegion, userId }).then((user) => { + const humanUser = + user.user?.type.case === "human" ? user.user?.type.value : undefined; - return { - factors: session?.factors, - authMethods: methods.authMethodTypes ?? [], - phoneVerified: humanUser?.phone?.isVerified ?? false, - emailVerified: humanUser?.email?.isVerified ?? false, - expirationDate: session?.expirationDate, - }; - }); - }, - ); + return { + factors: session?.factors, + authMethods: methods.authMethodTypes ?? [], + phoneVerified: humanUser?.phone?.isVerified ?? false, + emailVerified: humanUser?.email?.isVerified ?? false, + expirationDate: session?.expirationDate, + }; + }); + }); } async function loadSessionByLoginname( @@ -92,6 +92,7 @@ export default async function Page(props: { ) { return loadMostRecentSession({ serviceUrl, + serviceRegion, sessionParams: { loginName, organization, @@ -109,6 +110,7 @@ export default async function Page(props: { const recent = await getSessionCookieById({ sessionId, organization }); return getSession({ serviceUrl, + serviceRegion, sessionId: recent.id, sessionToken: recent.token, }).then((sessionResponse) => { @@ -116,9 +118,14 @@ export default async function Page(props: { }); } - const branding = await getBrandingSettings({ serviceUrl, organization }); + const branding = await getBrandingSettings({ + serviceUrl, + serviceRegion, + organization, + }); const loginSettings = await getLoginSettings({ serviceUrl, + serviceRegion, organization: sessionWithData.factors?.user?.organizationId, }); diff --git a/apps/login/src/app/(login)/otp/[method]/page.tsx b/apps/login/src/app/(login)/otp/[method]/page.tsx index 4d29777f6be..3f3072dd07a 100644 --- a/apps/login/src/app/(login)/otp/[method]/page.tsx +++ b/apps/login/src/app/(login)/otp/[method]/page.tsx @@ -24,7 +24,7 @@ export default async function Page(props: { const tError = await getTranslations({ locale, namespace: "error" }); const _headers = await headers(); - const serviceUrl = getServiceUrlFromHeaders(_headers); + const { serviceUrl, serviceRegion } = getServiceUrlFromHeaders(_headers); const host = _headers.get("host"); if (!host || typeof host !== "string") { @@ -47,6 +47,7 @@ export default async function Page(props: { ? await loadSessionById(serviceUrl, sessionId, organization) : await loadMostRecentSession({ serviceUrl, + serviceRegion, sessionParams: { loginName, organization }, }); @@ -58,6 +59,7 @@ export default async function Page(props: { const recent = await getSessionCookieById({ sessionId, organization }); return getSession({ serviceUrl, + serviceRegion, sessionId: recent.id, sessionToken: recent.token, }).then((response) => { @@ -70,11 +72,13 @@ export default async function Page(props: { // email links do not come with organization, thus we need to use the session's organization const branding = await getBrandingSettings({ serviceUrl, + serviceRegion, organization: organization ?? session?.factors?.user?.organizationId, }); const loginSettings = await getLoginSettings({ serviceUrl, + serviceRegion, organization: organization ?? session?.factors?.user?.organizationId, }); diff --git a/apps/login/src/app/(login)/otp/[method]/set/page.tsx b/apps/login/src/app/(login)/otp/[method]/set/page.tsx index 1e80d847a26..3de97510fd3 100644 --- a/apps/login/src/app/(login)/otp/[method]/set/page.tsx +++ b/apps/login/src/app/(login)/otp/[method]/set/page.tsx @@ -34,13 +34,22 @@ export default async function Page(props: { const { method } = params; const _headers = await headers(); - const serviceUrl = getServiceUrlFromHeaders(_headers); + const { serviceUrl, serviceRegion } = getServiceUrlFromHeaders(_headers); - const branding = await getBrandingSettings({ serviceUrl, organization }); - const loginSettings = await getLoginSettings({ serviceUrl, organization }); + const branding = await getBrandingSettings({ + serviceUrl, + serviceRegion, + organization, + }); + const loginSettings = await getLoginSettings({ + serviceUrl, + serviceRegion, + organization, + }); const session = await loadMostRecentSession({ serviceUrl, + serviceRegion, sessionParams: { loginName, organization, @@ -50,7 +59,11 @@ export default async function Page(props: { let totpResponse: RegisterTOTPResponse | undefined, error: Error | undefined; if (session && session.factors?.user?.id) { if (method === "time-based") { - await registerTOTP({ serviceUrl, userId: session.factors.user.id }) + await registerTOTP({ + serviceUrl, + serviceRegion, + userId: session.factors.user.id, + }) .then((resp) => { if (resp) { totpResponse = resp; @@ -61,18 +74,22 @@ export default async function Page(props: { }); } else if (method === "sms") { // does not work - await addOTPSMS({ serviceUrl, userId: session.factors.user.id }).catch( - (error) => { - error = new Error("Could not add OTP via SMS"); - }, - ); + await addOTPSMS({ + serviceUrl, + serviceRegion, + userId: session.factors.user.id, + }).catch((error) => { + error = new Error("Could not add OTP via SMS"); + }); } else if (method === "email") { // works - await addOTPEmail({ serviceUrl, userId: session.factors.user.id }).catch( - (error) => { - error = new Error("Could not add OTP via Email"); - }, - ); + await addOTPEmail({ + serviceUrl, + serviceRegion, + userId: session.factors.user.id, + }).catch((error) => { + error = new Error("Could not add OTP via Email"); + }); } else { throw new Error("Invalid method"); } diff --git a/apps/login/src/app/(login)/passkey/page.tsx b/apps/login/src/app/(login)/passkey/page.tsx index 2ec8b0d6270..312eacc5717 100644 --- a/apps/login/src/app/(login)/passkey/page.tsx +++ b/apps/login/src/app/(login)/passkey/page.tsx @@ -5,11 +5,7 @@ import { UserAvatar } from "@/components/user-avatar"; import { getSessionCookieById } from "@/lib/cookies"; import { getServiceUrlFromHeaders } from "@/lib/service"; import { loadMostRecentSession } from "@/lib/session"; -import { - getBrandingSettings, - getLoginSettings, - getSession, -} from "@/lib/zitadel"; +import { getBrandingSettings, getSession } from "@/lib/zitadel"; import { getLocale, getTranslations } from "next-intl/server"; import { headers } from "next/headers"; @@ -25,12 +21,13 @@ export default async function Page(props: { searchParams; const _headers = await headers(); - const serviceUrl = getServiceUrlFromHeaders(_headers); + const { serviceUrl, serviceRegion } = getServiceUrlFromHeaders(_headers); const sessionFactors = sessionId ? await loadSessionById(serviceUrl, sessionId, organization) : await loadMostRecentSession({ serviceUrl, + serviceRegion, sessionParams: { loginName, organization }, }); @@ -42,6 +39,7 @@ export default async function Page(props: { const recent = await getSessionCookieById({ sessionId, organization }); return getSession({ serviceUrl, + serviceRegion, sessionId: recent.id, sessionToken: recent.token, }).then((response) => { @@ -51,9 +49,11 @@ export default async function Page(props: { }); } - const branding = await getBrandingSettings({ serviceUrl, organization }); - - const loginSettings = await getLoginSettings({ serviceUrl, organization }); + const branding = await getBrandingSettings({ + serviceUrl, + serviceRegion, + organization, + }); return ( diff --git a/apps/login/src/app/(login)/passkey/set/page.tsx b/apps/login/src/app/(login)/passkey/set/page.tsx index 1035f4b55eb..e2f34ae830a 100644 --- a/apps/login/src/app/(login)/passkey/set/page.tsx +++ b/apps/login/src/app/(login)/passkey/set/page.tsx @@ -20,17 +20,22 @@ export default async function Page(props: { searchParams; const _headers = await headers(); - const serviceUrl = getServiceUrlFromHeaders(_headers); + const { serviceUrl, serviceRegion } = getServiceUrlFromHeaders(_headers); const session = await loadMostRecentSession({ serviceUrl, + serviceRegion, sessionParams: { loginName, organization, }, }); - const branding = await getBrandingSettings({ serviceUrl, organization }); + const branding = await getBrandingSettings({ + serviceUrl, + serviceRegion, + organization, + }); return ( diff --git a/apps/login/src/app/(login)/password/change/page.tsx b/apps/login/src/app/(login)/password/change/page.tsx index 4ea08083951..28f77a4b6d8 100644 --- a/apps/login/src/app/(login)/password/change/page.tsx +++ b/apps/login/src/app/(login)/password/change/page.tsx @@ -16,7 +16,7 @@ export default async function Page(props: { searchParams: Promise>; }) { const _headers = await headers(); - const serviceUrl = getServiceUrlFromHeaders(_headers); + const { serviceUrl, serviceRegion } = getServiceUrlFromHeaders(_headers); const searchParams = await props.searchParams; const locale = getLocale(); @@ -28,21 +28,28 @@ export default async function Page(props: { // also allow no session to be found (ignoreUnkownUsername) const sessionFactors = await loadMostRecentSession({ serviceUrl, + serviceRegion, sessionParams: { loginName, organization, }, }); - const branding = await getBrandingSettings({ serviceUrl, organization }); + const branding = await getBrandingSettings({ + serviceUrl, + serviceRegion, + organization, + }); const passwordComplexity = await getPasswordComplexitySettings({ serviceUrl, + serviceRegion, organization: sessionFactors?.factors?.user?.organizationId, }); const loginSettings = await getLoginSettings({ serviceUrl, + serviceRegion, organization: sessionFactors?.factors?.user?.organizationId, }); diff --git a/apps/login/src/app/(login)/password/page.tsx b/apps/login/src/app/(login)/password/page.tsx index e794f7bbbcc..b9b17568132 100644 --- a/apps/login/src/app/(login)/password/page.tsx +++ b/apps/login/src/app/(login)/password/page.tsx @@ -25,11 +25,14 @@ export default async function Page(props: { let { loginName, organization, authRequestId, alt } = searchParams; const _headers = await headers(); - const serviceUrl = getServiceUrlFromHeaders(_headers); + const { serviceUrl, serviceRegion } = getServiceUrlFromHeaders(_headers); let defaultOrganization; if (!organization) { - const org: Organization | null = await getDefaultOrg({ serviceUrl }); + const org: Organization | null = await getDefaultOrg({ + serviceUrl, + serviceRegion, + }); if (org) { defaultOrganization = org.id; @@ -41,6 +44,7 @@ export default async function Page(props: { try { sessionFactors = await loadMostRecentSession({ serviceUrl, + serviceRegion, sessionParams: { loginName, organization, @@ -53,10 +57,12 @@ export default async function Page(props: { const branding = await getBrandingSettings({ serviceUrl, + serviceRegion, organization: organization ?? defaultOrganization, }); const loginSettings = await getLoginSettings({ serviceUrl, + serviceRegion, organization: organization ?? defaultOrganization, }); diff --git a/apps/login/src/app/(login)/password/set/page.tsx b/apps/login/src/app/(login)/password/set/page.tsx index 2f29a66630a..a6537b3513f 100644 --- a/apps/login/src/app/(login)/password/set/page.tsx +++ b/apps/login/src/app/(login)/password/set/page.tsx @@ -27,13 +27,14 @@ export default async function Page(props: { searchParams; const _headers = await headers(); - const serviceUrl = getServiceUrlFromHeaders(_headers); + const { serviceUrl, serviceRegion } = getServiceUrlFromHeaders(_headers); // also allow no session to be found (ignoreUnkownUsername) let session: Session | undefined; if (loginName) { session = await loadMostRecentSession({ serviceUrl, + serviceRegion, sessionParams: { loginName, organization, @@ -41,19 +42,32 @@ export default async function Page(props: { }); } - const branding = await getBrandingSettings({ serviceUrl, organization }); + const branding = await getBrandingSettings({ + serviceUrl, + serviceRegion, + organization, + }); const passwordComplexity = await getPasswordComplexitySettings({ serviceUrl, + serviceRegion, organization: session?.factors?.user?.organizationId, }); - const loginSettings = await getLoginSettings({ serviceUrl, organization }); + const loginSettings = await getLoginSettings({ + serviceUrl, + serviceRegion, + organization, + }); let user: User | undefined; let displayName: string | undefined; if (userId) { - const userResponse = await getUserByID({ serviceUrl, userId }); + const userResponse = await getUserByID({ + serviceUrl, + serviceRegion, + userId, + }); user = userResponse.user; if (user?.type.case === "human") { diff --git a/apps/login/src/app/(login)/register/page.tsx b/apps/login/src/app/(login)/register/page.tsx index adb1f28310e..9fe2f3393c8 100644 --- a/apps/login/src/app/(login)/register/page.tsx +++ b/apps/login/src/app/(login)/register/page.tsx @@ -23,24 +23,40 @@ export default async function Page(props: { searchParams; const _headers = await headers(); - const serviceUrl = getServiceUrlFromHeaders(_headers); + const { serviceUrl, serviceRegion } = getServiceUrlFromHeaders(_headers); if (!organization) { - const org: Organization | null = await getDefaultOrg({ serviceUrl }); + const org: Organization | null = await getDefaultOrg({ + serviceUrl, + serviceRegion, + }); if (org) { organization = org.id; } } - const legal = await getLegalAndSupportSettings({ serviceUrl, organization }); + const legal = await getLegalAndSupportSettings({ + serviceUrl, + serviceRegion, + organization, + }); const passwordComplexitySettings = await getPasswordComplexitySettings({ serviceUrl, + serviceRegion, organization, }); - const branding = await getBrandingSettings({ serviceUrl, organization }); + const branding = await getBrandingSettings({ + serviceUrl, + serviceRegion, + organization, + }); - const loginSettings = await getLoginSettings({ serviceUrl, organization }); + const loginSettings = await getLoginSettings({ + serviceUrl, + serviceRegion, + organization, + }); if (!loginSettings?.allowRegister) { return ( diff --git a/apps/login/src/app/(login)/register/password/page.tsx b/apps/login/src/app/(login)/register/password/page.tsx index 2eac65536db..aeda4d56f68 100644 --- a/apps/login/src/app/(login)/register/password/page.tsx +++ b/apps/login/src/app/(login)/register/password/page.tsx @@ -23,10 +23,13 @@ export default async function Page(props: { searchParams; const _headers = await headers(); - const serviceUrl = getServiceUrlFromHeaders(_headers); + const { serviceUrl, serviceRegion } = getServiceUrlFromHeaders(_headers); if (!organization) { - const org: Organization | null = await getDefaultOrg({ serviceUrl }); + const org: Organization | null = await getDefaultOrg({ + serviceUrl, + serviceRegion, + }); if (org) { organization = org.id; } @@ -34,15 +37,28 @@ export default async function Page(props: { const missingData = !firstname || !lastname || !email; - const legal = await getLegalAndSupportSettings({ serviceUrl, organization }); + const legal = await getLegalAndSupportSettings({ + serviceUrl, + serviceRegion, + organization, + }); const passwordComplexitySettings = await getPasswordComplexitySettings({ serviceUrl, + serviceRegion, organization, }); - const branding = await getBrandingSettings({ serviceUrl, organization }); + const branding = await getBrandingSettings({ + serviceUrl, + serviceRegion, + organization, + }); - const loginSettings = await getLoginSettings({ serviceUrl, organization }); + const loginSettings = await getLoginSettings({ + serviceUrl, + serviceRegion, + organization, + }); return missingData ? ( diff --git a/apps/login/src/app/(login)/signedin/page.tsx b/apps/login/src/app/(login)/signedin/page.tsx index f387925500a..f6897134798 100644 --- a/apps/login/src/app/(login)/signedin/page.tsx +++ b/apps/login/src/app/(login)/signedin/page.tsx @@ -22,6 +22,7 @@ import { redirect } from "next/navigation"; async function loadSession( serviceUrl: string, + serviceRegion: string, loginName: string, authRequestId?: string, ) { @@ -30,6 +31,7 @@ async function loadSession( if (authRequestId) { return createCallback({ serviceUrl, + serviceRegion, req: create(CreateCallbackRequestSchema, { authRequestId, callbackKind: { @@ -46,6 +48,7 @@ async function loadSession( } return getSession({ serviceUrl, + serviceRegion, sessionId: recent.id, sessionToken: recent.token, }).then((response) => { @@ -61,20 +64,29 @@ export default async function Page(props: { searchParams: Promise }) { const t = await getTranslations({ locale, namespace: "signedin" }); const _headers = await headers(); - const serviceUrl = getServiceUrlFromHeaders(_headers); + const { serviceUrl, serviceRegion } = getServiceUrlFromHeaders(_headers); const { loginName, authRequestId, organization } = searchParams; const sessionFactors = await loadSession( serviceUrl, + serviceRegion, loginName, authRequestId, ); - const branding = await getBrandingSettings({ serviceUrl, organization }); + const branding = await getBrandingSettings({ + serviceUrl, + serviceRegion, + organization, + }); let loginSettings; if (!authRequestId) { - loginSettings = await getLoginSettings({ serviceUrl, organization }); + loginSettings = await getLoginSettings({ + serviceUrl, + serviceRegion, + organization, + }); } return ( diff --git a/apps/login/src/app/(login)/u2f/page.tsx b/apps/login/src/app/(login)/u2f/page.tsx index c5db30a21c5..e0a21103a87 100644 --- a/apps/login/src/app/(login)/u2f/page.tsx +++ b/apps/login/src/app/(login)/u2f/page.tsx @@ -20,19 +20,24 @@ export default async function Page(props: { const { loginName, authRequestId, sessionId, organization } = searchParams; const _headers = await headers(); - const serviceUrl = getServiceUrlFromHeaders(_headers); + const { serviceUrl, serviceRegion } = getServiceUrlFromHeaders(_headers); const host = _headers.get("host"); if (!host || typeof host !== "string") { throw new Error("No host found"); } - const branding = await getBrandingSettings({ serviceUrl, organization }); + const branding = await getBrandingSettings({ + serviceUrl, + serviceRegion, + organization, + }); const sessionFactors = sessionId ? await loadSessionById(serviceUrl, sessionId, organization) : await loadMostRecentSession({ serviceUrl, + serviceRegion, sessionParams: { loginName, organization }, }); @@ -44,6 +49,7 @@ export default async function Page(props: { const recent = await getSessionCookieById({ sessionId, organization }); return getSession({ serviceUrl, + serviceRegion, sessionId: recent.id, sessionToken: recent.token, }).then((response) => { diff --git a/apps/login/src/app/(login)/u2f/set/page.tsx b/apps/login/src/app/(login)/u2f/set/page.tsx index 79f5d3ab504..850f2652d0b 100644 --- a/apps/login/src/app/(login)/u2f/set/page.tsx +++ b/apps/login/src/app/(login)/u2f/set/page.tsx @@ -19,17 +19,22 @@ export default async function Page(props: { const { loginName, organization, authRequestId, checkAfter } = searchParams; const _headers = await headers(); - const serviceUrl = getServiceUrlFromHeaders(_headers); + const { serviceUrl, serviceRegion } = getServiceUrlFromHeaders(_headers); const sessionFactors = await loadMostRecentSession({ serviceUrl, + serviceRegion, sessionParams: { loginName, organization, }, }); - const branding = await getBrandingSettings({ serviceUrl, organization }); + const branding = await getBrandingSettings({ + serviceUrl, + serviceRegion, + organization, + }); return ( diff --git a/apps/login/src/app/(login)/verify/page.tsx b/apps/login/src/app/(login)/verify/page.tsx index 833ed663df5..628d07f36fe 100644 --- a/apps/login/src/app/(login)/verify/page.tsx +++ b/apps/login/src/app/(login)/verify/page.tsx @@ -26,7 +26,7 @@ export default async function Page(props: { searchParams: Promise }) { searchParams; const _headers = await headers(); - const serviceUrl = getServiceUrlFromHeaders(_headers); + const { serviceUrl, serviceRegion } = getServiceUrlFromHeaders(_headers); const host = _headers.get("host"); if (!host || typeof host !== "string") { @@ -35,6 +35,7 @@ export default async function Page(props: { searchParams: Promise }) { const branding = await getBrandingSettings({ serviceUrl, + serviceRegion, organization, }); @@ -48,6 +49,7 @@ export default async function Page(props: { searchParams: Promise }) { if ("loginName" in searchParams) { sessionFactors = await loadMostRecentSession({ serviceUrl, + serviceRegion, sessionParams: { loginName, organization, @@ -57,6 +59,7 @@ export default async function Page(props: { searchParams: Promise }) { if (doSend && sessionFactors?.factors?.user?.id) { await sendEmailCode({ serviceUrl, + serviceRegion, userId: sessionFactors?.factors?.user?.id, urlTemplate: `${host.includes("localhost") ? "http://" : "https://"}${host}/verify?code={{.Code}}&userId={{.UserID}}&organization={{.OrgID}}&invite=true` + @@ -70,6 +73,7 @@ export default async function Page(props: { searchParams: Promise }) { if (doSend) { await sendEmailCode({ serviceUrl, + serviceRegion, userId, urlTemplate: `${host.includes("localhost") ? "http://" : "https://"}${host}/verify?code={{.Code}}&userId={{.UserID}}&organization={{.OrgID}}&invite=true` + @@ -80,7 +84,11 @@ export default async function Page(props: { searchParams: Promise }) { }); } - const userResponse = await getUserByID({ serviceUrl, userId }); + const userResponse = await getUserByID({ + serviceUrl, + serviceRegion, + userId, + }); if (userResponse) { user = userResponse.user; if (user?.type.case === "human") { diff --git a/apps/login/src/app/login/route.ts b/apps/login/src/app/login/route.ts index f3663425701..2cea4b3b0b4 100644 --- a/apps/login/src/app/login/route.ts +++ b/apps/login/src/app/login/route.ts @@ -32,13 +32,16 @@ export const fetchCache = "default-no-store"; async function loadSessions({ serviceUrl, + serviceRegion, ids, }: { serviceUrl: string; + serviceRegion: string; ids: string[]; }): Promise { const response = await listSessions({ serviceUrl, + serviceRegion, ids: ids.filter((id: string | undefined) => !!id), }); @@ -55,6 +58,7 @@ const IDP_SCOPE_REGEX = /urn:zitadel:iam:org:idp:id:(.+)/; **/ async function isSessionValid( serviceUrl: string, + serviceRegion: string, session: Session, ): Promise { // session can't be checked without user @@ -67,6 +71,7 @@ async function isSessionValid( const authMethodTypes = await listAuthenticationMethodTypes({ serviceUrl, + serviceRegion, userId: session.factors.user.id, }); @@ -116,6 +121,7 @@ async function isSessionValid( // only check settings if no auth methods are available, as this would require a setup const loginSettings = await getLoginSettings({ serviceUrl, + serviceRegion, organization: session.factors?.user?.organizationId, }); if (loginSettings?.forceMfa || loginSettings?.forceMfaLocalOnly) { @@ -159,6 +165,7 @@ async function isSessionValid( async function findValidSession( serviceUrl: string, + serviceRegion: string, sessions: Session[], authRequest: AuthRequest, ): Promise { @@ -185,7 +192,7 @@ async function findValidSession( // return the first valid session according to settings for (const session of sessionsWithHint) { - if (await isSessionValid(serviceUrl, session)) { + if (await isSessionValid(serviceUrl, serviceRegion, session)) { return session; } } @@ -199,7 +206,7 @@ export async function GET(request: NextRequest) { const sessionId = searchParams.get("sessionId"); const _headers = await headers(); - const serviceUrl = getServiceUrlFromHeaders(_headers); + const { serviceUrl, serviceRegion } = getServiceUrlFromHeaders(_headers); // TODO: find a better way to handle _rsc (react server components) requests and block them to avoid conflicts when creating oidc callback const _rsc = searchParams.get("_rsc"); @@ -211,7 +218,7 @@ export async function GET(request: NextRequest) { const ids = sessionCookies.map((s) => s.id); let sessions: Session[] = []; if (ids && ids.length) { - sessions = await loadSessions({ serviceUrl, ids }); + sessions = await loadSessions({ serviceUrl, serviceRegion, ids }); } if (authRequestId && sessionId) { @@ -224,7 +231,11 @@ export async function GET(request: NextRequest) { if (selectedSession && selectedSession.id) { console.log(`Found session ${selectedSession.id}`); - const isValid = await isSessionValid(serviceUrl, selectedSession); + const isValid = await isSessionValid( + serviceUrl, + serviceRegion, + selectedSession, + ); console.log("Session is valid:", isValid); @@ -259,6 +270,7 @@ export async function GET(request: NextRequest) { try { const { callbackUrl } = await createCallback({ serviceUrl, + serviceRegion, req: create(CreateCallbackRequestSchema, { authRequestId, callbackKind: { @@ -286,6 +298,7 @@ export async function GET(request: NextRequest) { ) { const loginSettings = await getLoginSettings({ serviceUrl, + serviceRegion, organization: selectedSession.factors?.user?.organizationId, }); @@ -317,7 +330,11 @@ export async function GET(request: NextRequest) { } if (authRequestId) { - const { authRequest } = await getAuthRequest({ serviceUrl, authRequestId }); + const { authRequest } = await getAuthRequest({ + serviceUrl, + serviceRegion, + authRequestId, + }); let organization = ""; let suffix = ""; @@ -346,6 +363,7 @@ export async function GET(request: NextRequest) { if (orgDomain) { const orgs = await getOrgsByDomain({ serviceUrl, + serviceRegion, domain: orgDomain, }); if (orgs.result && orgs.result.length === 1) { @@ -362,6 +380,7 @@ export async function GET(request: NextRequest) { const identityProviders = await getActiveIdentityProviders({ serviceUrl, + serviceRegion, orgId: organization ? organization : undefined, }).then((resp) => { return resp.identityProviders; @@ -387,6 +406,7 @@ export async function GET(request: NextRequest) { return startIdentityProviderFlow({ serviceUrl, + serviceRegion, idpId, urls: { successUrl: @@ -487,6 +507,7 @@ export async function GET(request: NextRequest) { **/ const selectedSession = await findValidSession( serviceUrl, + serviceRegion, sessions, authRequest, ); @@ -516,6 +537,7 @@ export async function GET(request: NextRequest) { const { callbackUrl } = await createCallback({ serviceUrl, + serviceRegion, req: create(CreateCallbackRequestSchema, { authRequestId, callbackKind: { @@ -529,6 +551,7 @@ export async function GET(request: NextRequest) { // check for loginHint, userId hint and valid sessions let selectedSession = await findValidSession( serviceUrl, + serviceRegion, sessions, authRequest, ); @@ -553,6 +576,7 @@ export async function GET(request: NextRequest) { try { const { callbackUrl } = await createCallback({ serviceUrl, + serviceRegion, req: create(CreateCallbackRequestSchema, { authRequestId, callbackKind: { diff --git a/apps/login/src/lib/api.ts b/apps/login/src/lib/api.ts index ba70a764f32..15e85fd2b68 100644 --- a/apps/login/src/lib/api.ts +++ b/apps/login/src/lib/api.ts @@ -1,17 +1,40 @@ import { newSystemToken } from "@zitadel/client/node"; -export async function systemAPIToken() { - const audience = process.env.AUDIENCE; - const userID = process.env.SYSTEM_USER_ID; - const key = process.env.SYSTEM_USER_PRIVATE_KEY; +export async function systemAPIToken({ + serviceRegion, +}: { + serviceRegion: string; +}) { + const prefix = serviceRegion.toUpperCase(); + const token = { + audience: process.env[prefix + "_AUDIENCE"], + userID: process.env[prefix + "_SYSTEM_USER_ID"], + token: Buffer.from( + process.env[prefix.toUpperCase() + "_SYSTEM_USER_PRIVATE_KEY"] as string, + "base64", + ).toString("utf-8"), + }; - const decodedToken = Buffer.from(key, "base64").toString("utf-8"); + if (!token.audience || !token.userID || !token.token) { + const fallbackToken = { + audience: process.env.AUDIENCE, + userID: process.env.SYSTEM_USER_ID, + token: Buffer.from( + process.env.SYSTEM_USER_PRIVATE_KEY, + "base64", + ).toString("utf-8"), + }; - const token = newSystemToken({ - audience: audience, - subject: userID, - key: decodedToken, + return newSystemToken({ + audience: fallbackToken.audience, + subject: fallbackToken.userID, + key: fallbackToken.token, + }); + } + + return newSystemToken({ + audience: token.audience, + subject: token.userID, + key: token.token, }); - - return token; } diff --git a/apps/login/src/lib/self.ts b/apps/login/src/lib/self.ts index 0553aef21bf..178583fb406 100644 --- a/apps/login/src/lib/self.ts +++ b/apps/login/src/lib/self.ts @@ -26,12 +26,13 @@ export async function setMyPassword({ password: string; }) { const _headers = await headers(); - const serviceUrl = getServiceUrlFromHeaders(_headers); + const { serviceUrl, serviceRegion } = getServiceUrlFromHeaders(_headers); const sessionCookie = await getSessionCookieById({ sessionId }); const { session } = await getSession({ serviceUrl, + serviceRegion, sessionId: sessionCookie.id, sessionToken: sessionCookie.token, }); diff --git a/apps/login/src/lib/server/cookie.ts b/apps/login/src/lib/server/cookie.ts index 9f20c1a00db..587c7b4c76a 100644 --- a/apps/login/src/lib/server/cookie.ts +++ b/apps/login/src/lib/server/cookie.ts @@ -35,10 +35,11 @@ export async function createSessionAndUpdateCookie( lifetime?: Duration, ): Promise { const _headers = await headers(); - const serviceUrl = getServiceUrlFromHeaders(_headers); + const { serviceUrl, serviceRegion } = getServiceUrlFromHeaders(_headers); const createdSession = await createSessionFromChecks({ serviceUrl, + serviceRegion, checks, challenges, lifetime, @@ -47,6 +48,7 @@ export async function createSessionAndUpdateCookie( if (createdSession) { return getSession({ serviceUrl, + serviceRegion, sessionId: createdSession.sessionId, sessionToken: createdSession.sessionToken, }).then((response) => { @@ -97,10 +99,11 @@ export async function createSessionForIdpAndUpdateCookie( lifetime?: Duration, ): Promise { const _headers = await headers(); - const serviceUrl = getServiceUrlFromHeaders(_headers); + const { serviceUrl, serviceRegion } = getServiceUrlFromHeaders(_headers); const createdSession = await createSessionForUserIdAndIdpIntent({ serviceUrl, + serviceRegion, userId, idpIntent, lifetime, @@ -112,6 +115,7 @@ export async function createSessionForIdpAndUpdateCookie( const { session } = await getSession({ serviceUrl, + serviceRegion, sessionId: createdSession.sessionId, sessionToken: createdSession.sessionToken, }); @@ -159,10 +163,11 @@ export async function setSessionAndUpdateCookie( lifetime?: Duration, ) { const _headers = await headers(); - const serviceUrl = getServiceUrlFromHeaders(_headers); + const { serviceUrl, serviceRegion } = getServiceUrlFromHeaders(_headers); return setSession({ serviceUrl, + serviceRegion, sessionId: recentCookie.id, sessionToken: recentCookie.token, challenges, @@ -189,6 +194,7 @@ export async function setSessionAndUpdateCookie( return getSession({ serviceUrl, + serviceRegion, sessionId: sessionCookie.id, sessionToken: sessionCookie.token, }).then((response) => { diff --git a/apps/login/src/lib/server/idp.ts b/apps/login/src/lib/server/idp.ts index 3e597c50415..c12f518fd38 100644 --- a/apps/login/src/lib/server/idp.ts +++ b/apps/login/src/lib/server/idp.ts @@ -19,7 +19,7 @@ export type StartIDPFlowCommand = { export async function startIDPFlow(command: StartIDPFlowCommand) { const _headers = await headers(); - const serviceUrl = getServiceUrlFromHeaders(_headers); + const { serviceUrl, serviceRegion } = getServiceUrlFromHeaders(_headers); const host = _headers.get("host"); if (!host) { @@ -28,6 +28,7 @@ export async function startIDPFlow(command: StartIDPFlowCommand) { return startIdentityProviderFlow({ serviceUrl, + serviceRegion, idpId: command.idpId, urls: { successUrl: `${host.includes("localhost") ? "http://" : "https://"}${host}${command.successUrl}`, @@ -60,7 +61,7 @@ export async function createNewSessionFromIdpIntent( command: CreateNewSessionCommand, ) { const _headers = await headers(); - const serviceUrl = getServiceUrlFromHeaders(_headers); + const { serviceUrl, serviceRegion } = getServiceUrlFromHeaders(_headers); const host = _headers.get("host"); if (!host) { @@ -73,6 +74,7 @@ export async function createNewSessionFromIdpIntent( const userResponse = await getUserByID({ serviceUrl, + serviceRegion, userId: command.userId, }); @@ -82,6 +84,7 @@ export async function createNewSessionFromIdpIntent( const loginSettings = await getLoginSettings({ serviceUrl, + serviceRegion, organization: userResponse.user.details?.resourceOwner, }); diff --git a/apps/login/src/lib/server/invite.ts b/apps/login/src/lib/server/invite.ts index 56986930f93..864c91540e4 100644 --- a/apps/login/src/lib/server/invite.ts +++ b/apps/login/src/lib/server/invite.ts @@ -22,7 +22,7 @@ export type RegisterUserResponse = { export async function inviteUser(command: InviteUserCommand) { const _headers = await headers(); - const serviceUrl = getServiceUrlFromHeaders(_headers); + const { serviceUrl, serviceRegion } = getServiceUrlFromHeaders(_headers); const host = _headers.get("host"); if (!host) { @@ -31,6 +31,7 @@ export async function inviteUser(command: InviteUserCommand) { const human = await addHumanUser({ serviceUrl, + serviceRegion, email: command.email, firstName: command.firstName, lastName: command.lastName, @@ -44,6 +45,7 @@ export async function inviteUser(command: InviteUserCommand) { const codeResponse = await createInviteCode({ serviceUrl, + serviceRegion, urlTemplate: `${host.includes("localhost") ? "http://" : "https://"}${host}/verify?code={{.Code}}&userId={{.UserID}}&organization={{.OrgID}}&invite=true`, userId: human.userId, }); diff --git a/apps/login/src/lib/server/loginname.ts b/apps/login/src/lib/server/loginname.ts index 13bf7f0ed06..18070ab76cd 100644 --- a/apps/login/src/lib/server/loginname.ts +++ b/apps/login/src/lib/server/loginname.ts @@ -34,7 +34,7 @@ const ORG_SUFFIX_REGEX = /(?<=@)(.+)/; export async function sendLoginname(command: SendLoginnameCommand) { const _headers = await headers(); - const serviceUrl = getServiceUrlFromHeaders(_headers); + const { serviceUrl, serviceRegion } = getServiceUrlFromHeaders(_headers); const host = _headers.get("host"); if (!host) { @@ -43,6 +43,7 @@ export async function sendLoginname(command: SendLoginnameCommand) { const loginSettingsByContext = await getLoginSettings({ serviceUrl, + serviceRegion, organization: command.organization, }); @@ -52,6 +53,7 @@ export async function sendLoginname(command: SendLoginnameCommand) { let searchUsersRequest: SearchUsersCommand = { serviceUrl, + serviceRegion, searchValue: command.loginName, organizationId: command.organization, loginSettings: loginSettingsByContext, @@ -73,6 +75,7 @@ export async function sendLoginname(command: SendLoginnameCommand) { const redirectUserToSingleIDPIfAvailable = async () => { const identityProviders = await getActiveIdentityProviders({ serviceUrl, + serviceRegion, orgId: command.organization, }).then((resp) => { return resp.identityProviders; @@ -80,7 +83,7 @@ export async function sendLoginname(command: SendLoginnameCommand) { if (identityProviders.length === 1) { const _headers = await headers(); - const serviceUrl = getServiceUrlFromHeaders(_headers); + const { serviceUrl, serviceRegion } = getServiceUrlFromHeaders(_headers); const host = _headers.get("host"); if (!host) { @@ -103,6 +106,7 @@ export async function sendLoginname(command: SendLoginnameCommand) { const resp = await startIdentityProviderFlow({ serviceUrl, + serviceRegion, idpId: identityProviders[0].id, urls: { successUrl: @@ -121,15 +125,17 @@ export async function sendLoginname(command: SendLoginnameCommand) { }; const redirectUserToIDP = async (userId: string) => { - const identityProviders = await listIDPLinks({ serviceUrl, userId }).then( - (resp) => { - return resp.result; - }, - ); + const identityProviders = await listIDPLinks({ + serviceUrl, + serviceRegion, + userId, + }).then((resp) => { + return resp.result; + }); if (identityProviders.length === 1) { const _headers = await headers(); - const serviceUrl = getServiceUrlFromHeaders(_headers); + const { serviceUrl, serviceRegion } = getServiceUrlFromHeaders(_headers); const host = _headers.get("host"); if (!host) { @@ -138,7 +144,11 @@ export async function sendLoginname(command: SendLoginnameCommand) { const identityProviderId = identityProviders[0].idpId; - const idp = await getIDPByID({ serviceUrl, id: identityProviderId }); + const idp = await getIDPByID({ + serviceUrl, + serviceRegion, + id: identityProviderId, + }); const idpType = idp?.type; @@ -161,6 +171,7 @@ export async function sendLoginname(command: SendLoginnameCommand) { const resp = await startIdentityProviderFlow({ serviceUrl, + serviceRegion, idpId: idp.id, urls: { successUrl: @@ -186,6 +197,7 @@ export async function sendLoginname(command: SendLoginnameCommand) { const userLoginSettings = await getLoginSettings({ serviceUrl, + serviceRegion, organization: user.details?.resourceOwner, }); @@ -244,6 +256,7 @@ export async function sendLoginname(command: SendLoginnameCommand) { const methods = await listAuthenticationMethodTypes({ serviceUrl, + serviceRegion, userId: session.factors?.user?.id, }); @@ -400,12 +413,17 @@ export async function sendLoginname(command: SendLoginnameCommand) { const suffix = matched?.[1] ?? ""; // this just returns orgs where the suffix is set as primary domain - const orgs = await getOrgsByDomain({ serviceUrl, domain: suffix }); + const orgs = await getOrgsByDomain({ + serviceUrl, + serviceRegion, + domain: suffix, + }); const orgToCheckForDiscovery = orgs.result && orgs.result.length === 1 ? orgs.result[0].id : undefined; const orgLoginSettings = await getLoginSettings({ serviceUrl, + serviceRegion, organization: orgToCheckForDiscovery, }); if (orgLoginSettings?.allowDomainDiscovery) { diff --git a/apps/login/src/lib/server/otp.ts b/apps/login/src/lib/server/otp.ts index 72c663e9fe2..6d56d0c5385 100644 --- a/apps/login/src/lib/server/otp.ts +++ b/apps/login/src/lib/server/otp.ts @@ -27,7 +27,7 @@ export type SetOTPCommand = { export async function setOTP(command: SetOTPCommand) { const _headers = await headers(); - const serviceUrl = getServiceUrlFromHeaders(_headers); + const { serviceUrl, serviceRegion } = getServiceUrlFromHeaders(_headers); const recentSession = command.sessionId ? await getSessionCookieById({ sessionId: command.sessionId }).catch( @@ -64,6 +64,7 @@ export async function setOTP(command: SetOTPCommand) { const loginSettings = await getLoginSettings({ serviceUrl, + serviceRegion, organization: command.organization, }); diff --git a/apps/login/src/lib/server/passkeys.ts b/apps/login/src/lib/server/passkeys.ts index 97255ead863..819f319bd47 100644 --- a/apps/login/src/lib/server/passkeys.ts +++ b/apps/login/src/lib/server/passkeys.ts @@ -43,7 +43,7 @@ export async function registerPasskeyLink( const { sessionId } = command; const _headers = await headers(); - const serviceUrl = getServiceUrlFromHeaders(_headers); + const { serviceUrl, serviceRegion } = getServiceUrlFromHeaders(_headers); const host = _headers.get("host"); if (!host) { @@ -53,6 +53,7 @@ export async function registerPasskeyLink( const sessionCookie = await getSessionCookieById({ sessionId }); const session = await getSession({ serviceUrl, + serviceRegion, sessionId: sessionCookie.id, sessionToken: sessionCookie.token, }); @@ -73,6 +74,7 @@ export async function registerPasskeyLink( // use session token to add the passkey const registerLink = await createPasskeyRegistrationLink({ serviceUrl, + serviceRegion, userId, }); @@ -82,6 +84,7 @@ export async function registerPasskeyLink( return registerPasskey({ serviceUrl, + serviceRegion, userId, code: registerLink.code, domain: hostname, @@ -90,7 +93,7 @@ export async function registerPasskeyLink( export async function verifyPasskeyRegistration(command: VerifyPasskeyCommand) { const _headers = await headers(); - const serviceUrl = getServiceUrlFromHeaders(_headers); + const { serviceUrl, serviceRegion } = getServiceUrlFromHeaders(_headers); // if no name is provided, try to generate one from the user agent let passkeyName = command.passkeyName; @@ -109,6 +112,7 @@ export async function verifyPasskeyRegistration(command: VerifyPasskeyCommand) { }); const session = await getSession({ serviceUrl, + serviceRegion, sessionId: sessionCookie.id, sessionToken: sessionCookie.token, }); @@ -120,6 +124,7 @@ export async function verifyPasskeyRegistration(command: VerifyPasskeyCommand) { return zitadelVerifyPasskeyRegistration({ serviceUrl, + serviceRegion, request: create(VerifyPasskeyRegistrationRequestSchema, { passkeyId: command.passkeyId, publicKeyCredential: command.publicKeyCredential, @@ -153,9 +158,13 @@ export async function sendPasskey(command: SendPasskeyCommand) { } const _headers = await headers(); - const serviceUrl = getServiceUrlFromHeaders(_headers); + const { serviceUrl, serviceRegion } = getServiceUrlFromHeaders(_headers); - const loginSettings = await getLoginSettings({ serviceUrl, organization }); + const loginSettings = await getLoginSettings({ + serviceUrl, + serviceRegion, + organization, + }); const lifetime = checks?.webAuthN ? loginSettings?.multiFactorCheckLifetime // TODO different lifetime for webauthn u2f/passkey @@ -177,6 +186,7 @@ export async function sendPasskey(command: SendPasskeyCommand) { const userResponse = await getUserByID({ serviceUrl, + serviceRegion, userId: session?.factors?.user?.id, }); diff --git a/apps/login/src/lib/server/password.ts b/apps/login/src/lib/server/password.ts index 74518efabee..15459fa734b 100644 --- a/apps/login/src/lib/server/password.ts +++ b/apps/login/src/lib/server/password.ts @@ -45,7 +45,7 @@ type ResetPasswordCommand = { export async function resetPassword(command: ResetPasswordCommand) { const _headers = await headers(); - const serviceUrl = getServiceUrlFromHeaders(_headers); + const { serviceUrl, serviceRegion } = getServiceUrlFromHeaders(_headers); const host = _headers.get("host"); if (!host || typeof host !== "string") { @@ -54,6 +54,7 @@ export async function resetPassword(command: ResetPasswordCommand) { const users = await listUsers({ serviceUrl, + serviceRegion, loginName: command.loginName, organizationId: command.organization, }); @@ -69,6 +70,7 @@ export async function resetPassword(command: ResetPasswordCommand) { return passwordReset({ serviceUrl, + serviceRegion, userId, urlTemplate: `${host.includes("localhost") ? "http://" : "https://"}${host}/password/set?code={{.Code}}&userId={{.UserID}}&organization={{.OrgID}}` + @@ -85,7 +87,7 @@ export type UpdateSessionCommand = { export async function sendPassword(command: UpdateSessionCommand) { const _headers = await headers(); - const serviceUrl = getServiceUrlFromHeaders(_headers); + const { serviceUrl, serviceRegion } = getServiceUrlFromHeaders(_headers); let sessionCookie = await getSessionCookieByLoginName({ loginName: command.loginName, @@ -101,6 +103,7 @@ export async function sendPassword(command: UpdateSessionCommand) { if (!sessionCookie) { const users = await listUsers({ serviceUrl, + serviceRegion, loginName: command.loginName, organizationId: command.organization, }); @@ -115,6 +118,7 @@ export async function sendPassword(command: UpdateSessionCommand) { loginSettings = await getLoginSettings({ serviceUrl, + serviceRegion, organization: command.organization, }); @@ -143,6 +147,7 @@ export async function sendPassword(command: UpdateSessionCommand) { const userResponse = await getUserByID({ serviceUrl, + serviceRegion, userId: session?.factors?.user?.id, }); @@ -156,6 +161,7 @@ export async function sendPassword(command: UpdateSessionCommand) { if (!loginSettings) { loginSettings = await getLoginSettings({ serviceUrl, + serviceRegion, organization: command.organization ?? session.factors?.user?.organizationId, }); @@ -201,6 +207,7 @@ export async function sendPassword(command: UpdateSessionCommand) { if (command.checks && command.checks.password && session.factors?.user?.id) { const response = await listAuthenticationMethodTypes({ serviceUrl, + serviceRegion, userId: session.factors.user.id, }); if (response.authMethodTypes && response.authMethodTypes.length) { @@ -255,10 +262,14 @@ export async function changePassword(command: { password: string; }) { const _headers = await headers(); - const serviceUrl = getServiceUrlFromHeaders(_headers); + const { serviceUrl, serviceRegion } = getServiceUrlFromHeaders(_headers); // check for init state - const { user } = await getUserByID({ serviceUrl, userId: command.userId }); + const { user } = await getUserByID({ + serviceUrl, + serviceRegion, + userId: command.userId, + }); if (!user || user.userId !== command.userId) { return { error: "Could not send Password Reset Link" }; @@ -267,6 +278,7 @@ export async function changePassword(command: { return setUserPassword({ serviceUrl, + serviceRegion, userId, password: command.password, user, @@ -284,12 +296,13 @@ export async function checkSessionAndSetPassword({ password, }: CheckSessionAndSetPasswordCommand) { const _headers = await headers(); - const serviceUrl = getServiceUrlFromHeaders(_headers); + const { serviceUrl, serviceRegion } = getServiceUrlFromHeaders(_headers); const sessionCookie = await getSessionCookieById({ sessionId }); const { session } = await getSession({ serviceUrl, + serviceRegion, sessionId: sessionCookie.id, sessionToken: sessionCookie.token, }); @@ -308,6 +321,7 @@ export async function checkSessionAndSetPassword({ // check if the user has no password set in order to set a password const authmethods = await listAuthenticationMethodTypes({ serviceUrl, + serviceRegion, userId: session.factors.user.id, }); @@ -328,6 +342,7 @@ export async function checkSessionAndSetPassword({ const loginSettings = await getLoginSettings({ serviceUrl, + serviceRegion, organization: session.factors.user.organizationId, }); @@ -337,22 +352,24 @@ export async function checkSessionAndSetPassword({ // if the user has no MFA but MFA is enforced, we can set a password otherwise we use the token of the user if (forceMfa && hasNoMFAMethods) { - return setPassword({ serviceUrl, payload }).catch((error) => { - // throw error if failed precondition (ex. User is not yet initialized) - if (error.code === 9 && error.message) { - return { error: "Failed precondition" }; - } else { - throw error; - } - }); + return setPassword({ serviceUrl, serviceRegion, payload }).catch( + (error) => { + // throw error if failed precondition (ex. User is not yet initialized) + if (error.code === 9 && error.message) { + return { error: "Failed precondition" }; + } else { + throw error; + } + }, + ); } else { - const transport = async (host: string, token: string) => { + const transport = async (serviceUrl: string, token: string) => { return createServerTransport(token, { baseUrl: serviceUrl, }); }; - const myUserService = async (host: string, sessionToken: string) => { + const myUserService = async (serviceUrl: string, sessionToken: string) => { const transportPromise = await transport(serviceUrl, sessionToken); return createUserServiceClient(transportPromise); }; diff --git a/apps/login/src/lib/server/register.ts b/apps/login/src/lib/server/register.ts index 67021f21f65..2a23af3073b 100644 --- a/apps/login/src/lib/server/register.ts +++ b/apps/login/src/lib/server/register.ts @@ -29,7 +29,7 @@ export type RegisterUserResponse = { }; export async function registerUser(command: RegisterUserCommand) { const _headers = await headers(); - const serviceUrl = getServiceUrlFromHeaders(_headers); + const { serviceUrl, serviceRegion } = getServiceUrlFromHeaders(_headers); const host = _headers.get("host"); if (!host || typeof host !== "string") { @@ -38,6 +38,7 @@ export async function registerUser(command: RegisterUserCommand) { const addResponse = await addHumanUser({ serviceUrl, + serviceRegion, email: command.email, firstName: command.firstName, lastName: command.lastName, @@ -51,6 +52,7 @@ export async function registerUser(command: RegisterUserCommand) { const loginSettings = await getLoginSettings({ serviceUrl, + serviceRegion, organization: command.organization, }); @@ -92,6 +94,7 @@ export async function registerUser(command: RegisterUserCommand) { } else { const userResponse = await getUserByID({ serviceUrl, + serviceRegion, userId: session?.factors?.user?.id, }); diff --git a/apps/login/src/lib/server/session.ts b/apps/login/src/lib/server/session.ts index db165dfabd1..7f71ec8f14d 100644 --- a/apps/login/src/lib/server/session.ts +++ b/apps/login/src/lib/server/session.ts @@ -25,10 +25,11 @@ export async function continueWithSession({ ...session }: Session & { authRequestId?: string }) { const _headers = await headers(); - const serviceUrl = getServiceUrlFromHeaders(_headers); + const { serviceUrl, serviceRegion } = getServiceUrlFromHeaders(_headers); const loginSettings = await getLoginSettings({ serviceUrl, + serviceRegion, organization: session.factors?.user?.organizationId, }); @@ -88,7 +89,7 @@ export async function updateSession(options: UpdateSessionCommand) { } const _headers = await headers(); - const serviceUrl = getServiceUrlFromHeaders(_headers); + const { serviceUrl, serviceRegion } = getServiceUrlFromHeaders(_headers); const host = _headers.get("host"); if (!host) { @@ -106,7 +107,11 @@ export async function updateSession(options: UpdateSessionCommand) { challenges.webAuthN.domain = hostname; } - const loginSettings = await getLoginSettings({ serviceUrl, organization }); + const loginSettings = await getLoginSettings({ + serviceUrl, + serviceRegion, + organization, + }); const lifetime = checks?.webAuthN ? loginSettings?.multiFactorCheckLifetime // TODO different lifetime for webauthn u2f/passkey @@ -131,6 +136,7 @@ export async function updateSession(options: UpdateSessionCommand) { if (checks && checks.password && session.factors?.user?.id) { const response = await listAuthenticationMethodTypes({ serviceUrl, + serviceRegion, userId: session.factors.user.id, }); if (response.authMethodTypes && response.authMethodTypes.length) { @@ -152,7 +158,7 @@ type ClearSessionOptions = { export async function clearSession(options: ClearSessionOptions) { const _headers = await headers(); - const serviceUrl = getServiceUrlFromHeaders(_headers); + const { serviceUrl, serviceRegion } = getServiceUrlFromHeaders(_headers); const { sessionId } = options; @@ -160,6 +166,7 @@ export async function clearSession(options: ClearSessionOptions) { const deletedSession = await deleteSession({ serviceUrl, + serviceRegion, sessionId: session.id, sessionToken: session.token, }); @@ -175,12 +182,13 @@ type CleanupSessionCommand = { export async function cleanupSession({ sessionId }: CleanupSessionCommand) { const _headers = await headers(); - const serviceUrl = getServiceUrlFromHeaders(_headers); + const { serviceUrl, serviceRegion } = getServiceUrlFromHeaders(_headers); const sessionCookie = await getSessionCookieById({ sessionId }); const deleteResponse = await deleteSession({ serviceUrl, + serviceRegion, sessionId: sessionCookie.id, sessionToken: sessionCookie.token, }); diff --git a/apps/login/src/lib/server/u2f.ts b/apps/login/src/lib/server/u2f.ts index 5eaabce5326..60f1c12b66a 100644 --- a/apps/login/src/lib/server/u2f.ts +++ b/apps/login/src/lib/server/u2f.ts @@ -21,7 +21,7 @@ type VerifyU2FCommand = { export async function addU2F(command: RegisterU2FCommand) { const _headers = await headers(); - const serviceUrl = getServiceUrlFromHeaders(_headers); + const { serviceUrl, serviceRegion } = getServiceUrlFromHeaders(_headers); const host = _headers.get("host"); if (!host || typeof host !== "string") { @@ -38,6 +38,7 @@ export async function addU2F(command: RegisterU2FCommand) { const session = await getSession({ serviceUrl, + serviceRegion, sessionId: sessionCookie.id, sessionToken: sessionCookie.token, }); @@ -54,12 +55,12 @@ export async function addU2F(command: RegisterU2FCommand) { return { error: "Could not get session" }; } - return registerU2F({ serviceUrl, userId, domain: hostname }); + return registerU2F({ serviceUrl, serviceRegion, userId, domain: hostname }); } export async function verifyU2F(command: VerifyU2FCommand) { const _headers = await headers(); - const serviceUrl = getServiceUrlFromHeaders(_headers); + const { serviceUrl, serviceRegion } = getServiceUrlFromHeaders(_headers); const host = _headers.get("host"); if (!host || typeof host !== "string") { @@ -82,6 +83,7 @@ export async function verifyU2F(command: VerifyU2FCommand) { const session = await getSession({ serviceUrl, + serviceRegion, sessionId: sessionCookie.id, sessionToken: sessionCookie.token, }); @@ -99,5 +101,5 @@ export async function verifyU2F(command: VerifyU2FCommand) { userId, }); - return verifyU2FRegistration({ serviceUrl, request }); + return verifyU2FRegistration({ serviceUrl, serviceRegion, request }); } diff --git a/apps/login/src/lib/server/verify.ts b/apps/login/src/lib/server/verify.ts index 6c07197b875..2ab94a92526 100644 --- a/apps/login/src/lib/server/verify.ts +++ b/apps/login/src/lib/server/verify.ts @@ -30,10 +30,11 @@ export async function verifyTOTP( organization?: string, ) { const _headers = await headers(); - const serviceUrl = getServiceUrlFromHeaders(_headers); + const { serviceUrl, serviceRegion } = getServiceUrlFromHeaders(_headers); return loadMostRecentSession({ serviceUrl, + serviceRegion, sessionParams: { loginName, organization, @@ -42,6 +43,7 @@ export async function verifyTOTP( if (session?.factors?.user?.id) { return verifyTOTPRegistration({ serviceUrl, + serviceRegion, code, userId: session.factors.user.id, }); @@ -62,11 +64,12 @@ type VerifyUserByEmailCommand = { export async function sendVerification(command: VerifyUserByEmailCommand) { const _headers = await headers(); - const serviceUrl = getServiceUrlFromHeaders(_headers); + const { serviceUrl, serviceRegion } = getServiceUrlFromHeaders(_headers); const verifyResponse = command.isInvite ? await verifyInviteCode({ serviceUrl, + serviceRegion, userId: command.userId, verificationCode: command.code, }).catch(() => { @@ -74,6 +77,7 @@ export async function sendVerification(command: VerifyUserByEmailCommand) { }) : await verifyEmail({ serviceUrl, + serviceRegion, userId: command.userId, verificationCode: command.code, }).catch(() => { @@ -105,6 +109,7 @@ export async function sendVerification(command: VerifyUserByEmailCommand) { session = await getSession({ serviceUrl, + serviceRegion, sessionId: sessionCookie.id, sessionToken: sessionCookie.token, }).then((response) => { @@ -119,6 +124,7 @@ export async function sendVerification(command: VerifyUserByEmailCommand) { const userResponse = await getUserByID({ serviceUrl, + serviceRegion, userId: session?.factors?.user?.id, }); @@ -130,6 +136,7 @@ export async function sendVerification(command: VerifyUserByEmailCommand) { } else { const userResponse = await getUserByID({ serviceUrl, + serviceRegion, userId: command.userId, }); @@ -169,11 +176,13 @@ export async function sendVerification(command: VerifyUserByEmailCommand) { const loginSettings = await getLoginSettings({ serviceUrl, + serviceRegion, organization: user.details?.resourceOwner, }); const authMethodResponse = await listAuthenticationMethodTypes({ serviceUrl, + serviceRegion, userId: user.userId, }); @@ -244,7 +253,7 @@ type resendVerifyEmailCommand = { export async function resendVerification(command: resendVerifyEmailCommand) { const _headers = await headers(); - const serviceUrl = getServiceUrlFromHeaders(_headers); + const { serviceUrl, serviceRegion } = getServiceUrlFromHeaders(_headers); const host = _headers.get("host"); if (!host) { @@ -252,10 +261,11 @@ export async function resendVerification(command: resendVerifyEmailCommand) { } return command.isInvite - ? resendInviteCode({ serviceUrl, userId: command.userId }) + ? resendInviteCode({ serviceUrl, serviceRegion, userId: command.userId }) : resendEmailCode({ userId: command.userId, serviceUrl, + serviceRegion, urlTemplate: `${host.includes("localhost") ? "http://" : "https://"}${host}/password/set?code={{.Code}}&userId={{.UserID}}&organization={{.OrgID}}` + (command.authRequestId @@ -266,14 +276,16 @@ export async function resendVerification(command: resendVerifyEmailCommand) { type sendEmailCommand = { serviceUrl: string; + serviceRegion: string; userId: string; urlTemplate: string; }; export async function sendEmailCode(command: sendEmailCommand) { return zitadelSendEmailCode({ - userId: command.userId, serviceUrl: command.serviceUrl, + serviceRegion: command.serviceRegion, + userId: command.userId, urlTemplate: command.urlTemplate, }); } @@ -290,7 +302,7 @@ export async function sendVerificationRedirectWithoutCheck( command: SendVerificationRedirectWithoutCheckCommand, ) { const _headers = await headers(); - const serviceUrl = getServiceUrlFromHeaders(_headers); + const { serviceUrl, serviceRegion } = getServiceUrlFromHeaders(_headers); if (!("loginName" in command || "userId" in command)) { return { error: "No userId, nor loginname provided" }; @@ -313,6 +325,7 @@ export async function sendVerificationRedirectWithoutCheck( session = await getSession({ serviceUrl, + serviceRegion, sessionId: sessionCookie.id, sessionToken: sessionCookie.token, }).then((response) => { @@ -327,6 +340,7 @@ export async function sendVerificationRedirectWithoutCheck( const userResponse = await getUserByID({ serviceUrl, + serviceRegion, userId: session?.factors?.user?.id, }); @@ -338,6 +352,7 @@ export async function sendVerificationRedirectWithoutCheck( } else if ("userId" in command) { const userResponse = await getUserByID({ serviceUrl, + serviceRegion, userId: command.userId, }); @@ -377,6 +392,7 @@ export async function sendVerificationRedirectWithoutCheck( const authMethodResponse = await listAuthenticationMethodTypes({ serviceUrl, + serviceRegion, userId: user.userId, }); @@ -402,6 +418,7 @@ export async function sendVerificationRedirectWithoutCheck( const loginSettings = await getLoginSettings({ serviceUrl, + serviceRegion, organization: user.details?.resourceOwner, }); diff --git a/apps/login/src/lib/service.ts b/apps/login/src/lib/service.ts index f6c70c66d30..e543f35467f 100644 --- a/apps/login/src/lib/service.ts +++ b/apps/login/src/lib/service.ts @@ -20,16 +20,17 @@ type ServiceClass = export async function createServiceForHost( service: T, serviceUrl: string, + serviceRegion: string, ) { let token; // if we are running in a multitenancy context, use the system user token if ( - process.env.AUDIENCE && - process.env.SYSTEM_USER_ID && - process.env.SYSTEM_USER_PRIVATE_KEY + process.env[serviceRegion + "_AUDIENCE"] && + process.env[serviceRegion + "_SYSTEM_USER_ID"] && + process.env[serviceRegion + "_SYSTEM_USER_PRIVATE_KEY"] ) { - token = await systemAPIToken(); + token = await systemAPIToken({ serviceRegion }); } else if (process.env.ZITADEL_SERVICE_USER_TOKEN) { token = process.env.ZITADEL_SERVICE_USER_TOKEN; } @@ -49,7 +50,10 @@ export async function createServiceForHost( return createClientFor(service)(transport); } -export function getServiceUrlFromHeaders(headers: ReadonlyHeaders): string { +export function getServiceUrlFromHeaders(headers: ReadonlyHeaders): { + serviceUrl: string; + serviceRegion: string; +} { let instanceUrl: string = process.env.ZITADEL_API_URL; const forwardedHost = headers.get("x-zitadel-forward-host"); @@ -70,5 +74,8 @@ export function getServiceUrlFromHeaders(headers: ReadonlyHeaders): string { } } - return instanceUrl; + return { + serviceUrl: instanceUrl, + serviceRegion: headers.get("x-zitadel-region") || "", + }; } diff --git a/apps/login/src/lib/session.ts b/apps/login/src/lib/session.ts index 758594845c1..58fe1d20dfc 100644 --- a/apps/login/src/lib/session.ts +++ b/apps/login/src/lib/session.ts @@ -5,6 +5,7 @@ import { getSession } from "./zitadel"; type LoadMostRecentSessionParams = { serviceUrl: string; + serviceRegion: string; sessionParams: { loginName?: string; organization?: string; @@ -13,6 +14,7 @@ type LoadMostRecentSessionParams = { export async function loadMostRecentSession({ serviceUrl, + serviceRegion, sessionParams, }: LoadMostRecentSessionParams): Promise { const recent = await getMostRecentCookieWithLoginname({ @@ -22,6 +24,7 @@ export async function loadMostRecentSession({ return getSession({ serviceUrl, + serviceRegion, sessionId: recent.id, sessionToken: recent.token, }).then((resp: GetSessionResponse) => resp.session); diff --git a/apps/login/src/lib/zitadel.ts b/apps/login/src/lib/zitadel.ts index 5a03e5ece07..ba96481e386 100644 --- a/apps/login/src/lib/zitadel.ts +++ b/apps/login/src/lib/zitadel.ts @@ -55,13 +55,15 @@ async function cacheWrapper(callback: Promise) { export async function getBrandingSettings({ serviceUrl, + serviceRegion, organization, }: { serviceUrl: string; + serviceRegion: string; organization?: string; }) { const settingsService: Client = - await createServiceForHost(SettingsService, serviceUrl); + await createServiceForHost(SettingsService, serviceUrl, serviceRegion); const callback = settingsService .getBrandingSettings({ ctx: makeReqCtx(organization) }, {}) @@ -72,13 +74,15 @@ export async function getBrandingSettings({ export async function getLoginSettings({ serviceUrl, + serviceRegion, organization, }: { serviceUrl: string; + serviceRegion: string; organization?: string; }) { const settingsService: Client = - await createServiceForHost(SettingsService, serviceUrl); + await createServiceForHost(SettingsService, serviceUrl, serviceRegion); const callback = settingsService .getLoginSettings({ ctx: makeReqCtx(organization) }, {}) @@ -89,14 +93,17 @@ export async function getLoginSettings({ export async function listIDPLinks({ serviceUrl, + serviceRegion, userId, }: { serviceUrl: string; + serviceRegion: string; userId: string; }) { const userService: Client = await createServiceForHost( UserService, serviceUrl, + serviceRegion, ); return userService.listIDPLinks({ userId }, {}); @@ -104,14 +111,17 @@ export async function listIDPLinks({ export async function addOTPEmail({ serviceUrl, + serviceRegion, userId, }: { serviceUrl: string; + serviceRegion: string; userId: string; }) { const userService: Client = await createServiceForHost( UserService, serviceUrl, + serviceRegion, ); return userService.addOTPEmail({ userId }, {}); @@ -119,14 +129,17 @@ export async function addOTPEmail({ export async function addOTPSMS({ serviceUrl, + serviceRegion, userId, }: { serviceUrl: string; + serviceRegion: string; userId: string; }) { const userService: Client = await createServiceForHost( UserService, serviceUrl, + serviceRegion, ); return userService.addOTPSMS({ userId }, {}); @@ -134,14 +147,17 @@ export async function addOTPSMS({ export async function registerTOTP({ serviceUrl, + serviceRegion, userId, }: { serviceUrl: string; + serviceRegion: string; userId: string; }) { const userService: Client = await createServiceForHost( UserService, serviceUrl, + serviceRegion, ); return userService.registerTOTP({ userId }, {}); @@ -149,11 +165,13 @@ export async function registerTOTP({ export async function getGeneralSettings({ serviceUrl, + serviceRegion, }: { serviceUrl: string; + serviceRegion: string; }) { const settingsService: Client = - await createServiceForHost(SettingsService, serviceUrl); + await createServiceForHost(SettingsService, serviceUrl, serviceRegion); const callback = settingsService .getGeneralSettings({}, {}) @@ -164,13 +182,15 @@ export async function getGeneralSettings({ export async function getLegalAndSupportSettings({ serviceUrl, + serviceRegion, organization, }: { serviceUrl: string; + serviceRegion: string; organization?: string; }) { const settingsService: Client = - await createServiceForHost(SettingsService, serviceUrl); + await createServiceForHost(SettingsService, serviceUrl, serviceRegion); const callback = settingsService .getLegalAndSupportSettings({ ctx: makeReqCtx(organization) }, {}) @@ -181,13 +201,15 @@ export async function getLegalAndSupportSettings({ export async function getPasswordComplexitySettings({ serviceUrl, + serviceRegion, organization, }: { serviceUrl: string; + serviceRegion: string; organization?: string; }) { const settingsService: Client = - await createServiceForHost(SettingsService, serviceUrl); + await createServiceForHost(SettingsService, serviceUrl, serviceRegion); const callback = settingsService .getPasswordComplexitySettings({ ctx: makeReqCtx(organization) }) @@ -198,28 +220,32 @@ export async function getPasswordComplexitySettings({ export async function createSessionFromChecks({ serviceUrl, + serviceRegion, checks, challenges, lifetime, }: { serviceUrl: string; + serviceRegion: string; checks: Checks; challenges: RequestChallenges | undefined; lifetime?: Duration; }) { const sessionService: Client = - await createServiceForHost(SessionService, serviceUrl); + await createServiceForHost(SessionService, serviceUrl, serviceRegion); return sessionService.createSession({ checks, challenges, lifetime }, {}); } export async function createSessionForUserIdAndIdpIntent({ serviceUrl, + serviceRegion, userId, idpIntent, lifetime, }: { serviceUrl: string; + serviceRegion: string; userId: string; idpIntent: { idpIntentId?: string | undefined; @@ -228,7 +254,7 @@ export async function createSessionForUserIdAndIdpIntent({ lifetime?: Duration; }) { const sessionService: Client = - await createServiceForHost(SessionService, serviceUrl); + await createServiceForHost(SessionService, serviceUrl, serviceRegion); return sessionService.createSession({ checks: { @@ -246,6 +272,7 @@ export async function createSessionForUserIdAndIdpIntent({ export async function setSession({ serviceUrl, + serviceRegion, sessionId, sessionToken, challenges, @@ -253,6 +280,7 @@ export async function setSession({ lifetime, }: { serviceUrl: string; + serviceRegion: string; sessionId: string; sessionToken: string; challenges: RequestChallenges | undefined; @@ -260,7 +288,7 @@ export async function setSession({ lifetime?: Duration; }) { const sessionService: Client = - await createServiceForHost(SessionService, serviceUrl); + await createServiceForHost(SessionService, serviceUrl, serviceRegion); return sessionService.setSession( { @@ -277,42 +305,51 @@ export async function setSession({ export async function getSession({ serviceUrl, + serviceRegion, sessionId, sessionToken, }: { serviceUrl: string; + serviceRegion: string; sessionId: string; sessionToken: string; }) { const sessionService: Client = - await createServiceForHost(SessionService, serviceUrl); + await createServiceForHost(SessionService, serviceUrl, serviceRegion); return sessionService.getSession({ sessionId, sessionToken }, {}); } export async function deleteSession({ serviceUrl, + serviceRegion, sessionId, sessionToken, }: { serviceUrl: string; + serviceRegion: string; sessionId: string; sessionToken: string; }) { const sessionService: Client = - await createServiceForHost(SessionService, serviceUrl); + await createServiceForHost(SessionService, serviceUrl, serviceRegion); return sessionService.deleteSession({ sessionId, sessionToken }, {}); } type ListSessionsCommand = { serviceUrl: string; + serviceRegion: string; ids: string[]; }; -export async function listSessions({ serviceUrl, ids }: ListSessionsCommand) { +export async function listSessions({ + serviceUrl, + serviceRegion, + ids, +}: ListSessionsCommand) { const sessionService: Client = - await createServiceForHost(SessionService, serviceUrl); + await createServiceForHost(SessionService, serviceUrl, serviceRegion); return sessionService.listSessions( { @@ -331,6 +368,7 @@ export async function listSessions({ serviceUrl, ids }: ListSessionsCommand) { export type AddHumanUserData = { serviceUrl: string; + serviceRegion: string; firstName: string; lastName: string; email: string; @@ -340,6 +378,7 @@ export type AddHumanUserData = { export async function addHumanUser({ serviceUrl, + serviceRegion, email, firstName, lastName, @@ -349,6 +388,7 @@ export async function addHumanUser({ const userService: Client = await createServiceForHost( UserService, serviceUrl, + serviceRegion, ); return userService.addHumanUser({ @@ -372,14 +412,17 @@ export async function addHumanUser({ export async function addHuman({ serviceUrl, + serviceRegion, request, }: { serviceUrl: string; + serviceRegion: string; request: AddHumanUserRequest; }) { const userService: Client = await createServiceForHost( UserService, serviceUrl, + serviceRegion, ); return userService.addHumanUser(request); @@ -387,16 +430,19 @@ export async function addHuman({ export async function verifyTOTPRegistration({ serviceUrl, + serviceRegion, code, userId, }: { serviceUrl: string; + serviceRegion: string; code: string; userId: string; }) { const userService: Client = await createServiceForHost( UserService, serviceUrl, + serviceRegion, ); return userService.verifyTOTPRegistration({ code, userId }, {}); @@ -404,14 +450,17 @@ export async function verifyTOTPRegistration({ export async function getUserByID({ serviceUrl, + serviceRegion, userId, }: { serviceUrl: string; + serviceRegion: string; userId: string; }) { const userService: Client = await createServiceForHost( UserService, serviceUrl, + serviceRegion, ); return userService.getUserByID({ userId }, {}); @@ -419,16 +468,19 @@ export async function getUserByID({ export async function verifyInviteCode({ serviceUrl, + serviceRegion, userId, verificationCode, }: { serviceUrl: string; + serviceRegion: string; userId: string; verificationCode: string; }) { const userService: Client = await createServiceForHost( UserService, serviceUrl, + serviceRegion, ); return userService.verifyInviteCode({ userId, verificationCode }, {}); @@ -436,14 +488,17 @@ export async function verifyInviteCode({ export async function resendInviteCode({ serviceUrl, + serviceRegion, userId, }: { serviceUrl: string; + serviceRegion: string; userId: string; }) { const userService: Client = await createServiceForHost( UserService, serviceUrl, + serviceRegion, ); return userService.resendInviteCode({ userId }, {}); @@ -451,10 +506,12 @@ export async function resendInviteCode({ export async function sendEmailCode({ serviceUrl, + serviceRegion, userId, urlTemplate, }: { serviceUrl: string; + serviceRegion: string; userId: string; urlTemplate: string; }) { @@ -473,6 +530,7 @@ export async function sendEmailCode({ const userService: Client = await createServiceForHost( UserService, serviceUrl, + serviceRegion, ); return userService.sendEmailCode(medium, {}); @@ -480,10 +538,12 @@ export async function sendEmailCode({ export async function createInviteCode({ serviceUrl, + serviceRegion, urlTemplate, userId, }: { serviceUrl: string; + serviceRegion: string; urlTemplate: string; userId: string; }) { @@ -499,6 +559,7 @@ export async function createInviteCode({ const userService: Client = await createServiceForHost( UserService, serviceUrl, + serviceRegion, ); return userService.createInviteCode( @@ -515,6 +576,7 @@ export async function createInviteCode({ export type ListUsersCommand = { serviceUrl: string; + serviceRegion: string; loginName?: string; userName?: string; email?: string; @@ -524,6 +586,7 @@ export type ListUsersCommand = { export async function listUsers({ serviceUrl, + serviceRegion, loginName, userName, phone, @@ -615,6 +678,7 @@ export async function listUsers({ const userService: Client = await createServiceForHost( UserService, serviceUrl, + serviceRegion, ); return userService.listUsers({ queries }); @@ -622,6 +686,7 @@ export async function listUsers({ export type SearchUsersCommand = { serviceUrl: string; + serviceRegion: string; searchValue: string; loginSettings: LoginSettings; organizationId?: string; @@ -667,6 +732,7 @@ const EmailQuery = (searchValue: string) => * */ export async function searchUsers({ serviceUrl, + serviceRegion, searchValue, loginSettings, organizationId, @@ -700,6 +766,7 @@ export async function searchUsers({ const userService: Client = await createServiceForHost( UserService, serviceUrl, + serviceRegion, ); const loginNameResult = await userService.listUsers({ queries }); @@ -786,11 +853,13 @@ export async function searchUsers({ export async function getDefaultOrg({ serviceUrl, + serviceRegion, }: { serviceUrl: string; + serviceRegion: string; }): Promise { const orgService: Client = - await createServiceForHost(OrganizationService, serviceUrl); + await createServiceForHost(OrganizationService, serviceUrl, serviceRegion); return orgService .listOrganizations( @@ -811,13 +880,15 @@ export async function getDefaultOrg({ export async function getOrgsByDomain({ serviceUrl, + serviceRegion, domain, }: { serviceUrl: string; + serviceRegion: string; domain: string; }) { const orgService: Client = - await createServiceForHost(OrganizationService, serviceUrl); + await createServiceForHost(OrganizationService, serviceUrl, serviceRegion); return orgService.listOrganizations( { @@ -836,16 +907,19 @@ export async function getOrgsByDomain({ export async function startIdentityProviderFlow({ serviceUrl, + serviceRegion, idpId, urls, }: { serviceUrl: string; + serviceRegion: string; idpId: string; urls: RedirectURLsJson; }) { const userService: Client = await createServiceForHost( UserService, serviceUrl, + serviceRegion, ); return userService.startIdentityProviderIntent({ @@ -859,16 +933,19 @@ export async function startIdentityProviderFlow({ export async function retrieveIdentityProviderInformation({ serviceUrl, + serviceRegion, idpIntentId, idpIntentToken, }: { serviceUrl: string; + serviceRegion: string; idpIntentId: string; idpIntentToken: string; }) { const userService: Client = await createServiceForHost( UserService, serviceUrl, + serviceRegion, ); return userService.retrieveIdentityProviderIntent({ @@ -879,12 +956,18 @@ export async function retrieveIdentityProviderInformation({ export async function getAuthRequest({ serviceUrl, + serviceRegion, authRequestId, }: { serviceUrl: string; + serviceRegion: string; authRequestId: string; }) { - const oidcService = await createServiceForHost(OIDCService, serviceUrl); + const oidcService = await createServiceForHost( + OIDCService, + serviceUrl, + serviceRegion, + ); return oidcService.getAuthRequest({ authRequestId, @@ -893,28 +976,37 @@ export async function getAuthRequest({ export async function createCallback({ serviceUrl, + serviceRegion, req, }: { serviceUrl: string; + serviceRegion: string; req: CreateCallbackRequest; }) { - const oidcService = await createServiceForHost(OIDCService, serviceUrl); + const oidcService = await createServiceForHost( + OIDCService, + serviceUrl, + serviceRegion, + ); return oidcService.createCallback(req); } export async function verifyEmail({ serviceUrl, + serviceRegion, userId, verificationCode, }: { serviceUrl: string; + serviceRegion: string; userId: string; verificationCode: string; }) { const userService: Client = await createServiceForHost( UserService, serviceUrl, + serviceRegion, ); return userService.verifyEmail( @@ -928,10 +1020,12 @@ export async function verifyEmail({ export async function resendEmailCode({ serviceUrl, + serviceRegion, userId, urlTemplate, }: { serviceUrl: string; + serviceRegion: string; userId: string; urlTemplate: string; }) { @@ -948,6 +1042,7 @@ export async function resendEmailCode({ const userService: Client = await createServiceForHost( UserService, serviceUrl, + serviceRegion, ); return userService.resendEmailCode(request, {}); @@ -955,16 +1050,19 @@ export async function resendEmailCode({ export async function retrieveIDPIntent({ serviceUrl, + serviceRegion, id, token, }: { serviceUrl: string; + serviceRegion: string; id: string; token: string; }) { const userService: Client = await createServiceForHost( UserService, serviceUrl, + serviceRegion, ); return userService.retrieveIdentityProviderIntent( @@ -975,29 +1073,38 @@ export async function retrieveIDPIntent({ export async function getIDPByID({ serviceUrl, + serviceRegion, id, }: { serviceUrl: string; + serviceRegion: string; id: string; }) { const idpService: Client = - await createServiceForHost(IdentityProviderService, serviceUrl); + await createServiceForHost( + IdentityProviderService, + serviceUrl, + serviceRegion, + ); return idpService.getIDPByID({ id }, {}).then((resp) => resp.idp); } export async function addIDPLink({ serviceUrl, + serviceRegion, idp, userId, }: { serviceUrl: string; + serviceRegion: string; idp: { id: string; userId: string; userName: string }; userId: string; }) { const userService: Client = await createServiceForHost( UserService, serviceUrl, + serviceRegion, ); return userService.addIDPLink( @@ -1015,10 +1122,12 @@ export async function addIDPLink({ export async function passwordReset({ serviceUrl, + serviceRegion, userId, urlTemplate, }: { serviceUrl: string; + serviceRegion: string; userId: string; urlTemplate?: string; }) { @@ -1034,6 +1143,7 @@ export async function passwordReset({ const userService: Client = await createServiceForHost( UserService, serviceUrl, + serviceRegion, ); return userService.passwordReset( @@ -1050,12 +1160,14 @@ export async function passwordReset({ export async function setUserPassword({ serviceUrl, + serviceRegion, userId, password, user, code, }: { serviceUrl: string; + serviceRegion: string; userId: string; password: string; user: User; @@ -1072,6 +1184,7 @@ export async function setUserPassword({ if (!code) { const authmethods = await listAuthenticationMethodTypes({ serviceUrl, + serviceRegion, userId, }); @@ -1097,6 +1210,7 @@ export async function setUserPassword({ const userService: Client = await createServiceForHost( UserService, serviceUrl, + serviceRegion, ); return userService.setPassword(payload, {}).catch((error) => { @@ -1111,14 +1225,17 @@ export async function setUserPassword({ export async function setPassword({ serviceUrl, + serviceRegion, payload, }: { serviceUrl: string; + serviceRegion: string; payload: SetPasswordRequest; }) { const userService: Client = await createServiceForHost( UserService, serviceUrl, + serviceRegion, ); return userService.setPassword(payload, {}); @@ -1132,14 +1249,17 @@ export async function setPassword({ */ export async function createPasskeyRegistrationLink({ serviceUrl, + serviceRegion, userId, }: { serviceUrl: string; + serviceRegion: string; userId: string; }) { const userService: Client = await createServiceForHost( UserService, serviceUrl, + serviceRegion, ); return userService.createPasskeyRegistrationLink({ @@ -1160,16 +1280,19 @@ export async function createPasskeyRegistrationLink({ */ export async function registerU2F({ serviceUrl, + serviceRegion, userId, domain, }: { serviceUrl: string; + serviceRegion: string; userId: string; domain: string; }) { const userService: Client = await createServiceForHost( UserService, serviceUrl, + serviceRegion, ); return userService.registerU2F({ @@ -1186,14 +1309,17 @@ export async function registerU2F({ */ export async function verifyU2FRegistration({ serviceUrl, + serviceRegion, request, }: { serviceUrl: string; + serviceRegion: string; request: VerifyU2FRegistrationRequest; }) { const userService: Client = await createServiceForHost( UserService, serviceUrl, + serviceRegion, ); return userService.verifyU2FRegistration(request, {}); @@ -1208,10 +1334,12 @@ export async function verifyU2FRegistration({ */ export async function getActiveIdentityProviders({ serviceUrl, + serviceRegion, orgId, linking_allowed, }: { serviceUrl: string; + serviceRegion: string; orgId?: string; linking_allowed?: boolean; }) { @@ -1220,7 +1348,7 @@ export async function getActiveIdentityProviders({ props.linkingAllowed = linking_allowed; } const settingsService: Client = - await createServiceForHost(SettingsService, serviceUrl); + await createServiceForHost(SettingsService, serviceUrl, serviceRegion); return settingsService.getActiveIdentityProviders(props, {}); } @@ -1233,14 +1361,17 @@ export async function getActiveIdentityProviders({ */ export async function verifyPasskeyRegistration({ serviceUrl, + serviceRegion, request, }: { serviceUrl: string; + serviceRegion: string; request: VerifyPasskeyRegistrationRequest; }) { const userService: Client = await createServiceForHost( UserService, serviceUrl, + serviceRegion, ); return userService.verifyPasskeyRegistration(request, {}); @@ -1256,11 +1387,13 @@ export async function verifyPasskeyRegistration({ */ export async function registerPasskey({ serviceUrl, + serviceRegion, userId, code, domain, }: { serviceUrl: string; + serviceRegion: string; userId: string; code: { id: string; code: string }; domain: string; @@ -1268,6 +1401,7 @@ export async function registerPasskey({ const userService: Client = await createServiceForHost( UserService, serviceUrl, + serviceRegion, ); return userService.registerPasskey({ @@ -1285,14 +1419,17 @@ export async function registerPasskey({ */ export async function listAuthenticationMethodTypes({ serviceUrl, + serviceRegion, userId, }: { serviceUrl: string; + serviceRegion: string; userId: string; }) { const userService: Client = await createServiceForHost( UserService, serviceUrl, + serviceRegion, ); return userService.listAuthenticationMethodTypes({ diff --git a/apps/login/src/middleware.ts b/apps/login/src/middleware.ts index cb42234cac4..8ffe8e58302 100644 --- a/apps/login/src/middleware.ts +++ b/apps/login/src/middleware.ts @@ -23,7 +23,7 @@ export async function middleware(request: NextRequest) { const _headers = await headers(); - const serviceUrl = getServiceUrlFromHeaders(_headers); + const { serviceUrl, serviceRegion } = getServiceUrlFromHeaders(_headers); const instanceHost = `${serviceUrl}`.replace("https://", ""); diff --git a/turbo.json b/turbo.json index 1db73e60c96..bf02da7ea08 100644 --- a/turbo.json +++ b/turbo.json @@ -6,6 +6,12 @@ "DEBUG", "VERCEL_URL", "EMAIL_VERIFICATION", + "EU1_AUDIENCE", + "EU1_SYSTEM_USER_ID", + "EU1_SYSTEM_USER_PRIVATE_KEY", + "US1_AUDIENCE", + "US1_SYSTEM_USER_ID", + "US1_SYSTEM_USER_PRIVATE_KEY", "AUDIENCE", "SYSTEM_USER_ID", "SYSTEM_USER_PRIVATE_KEY",