diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 00000000000..f9db036d2ba --- /dev/null +++ b/.dockerignore @@ -0,0 +1,2 @@ +* +!docker \ No newline at end of file diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml new file mode 100644 index 00000000000..bad19343d35 --- /dev/null +++ b/.github/workflows/docker.yml @@ -0,0 +1,72 @@ +name: Docker + +on: + push: + branches: + - main + +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Check out code + uses: actions/checkout@v4 + with: + fetch-depth: 2 + + - name: Install pnpm + uses: pnpm/action-setup@v4 + + - name: Cache turbo build setup + uses: actions/cache@v4 + with: + path: .turbo + key: ${{ runner.os }}-turbo-${{ github.sha }} + restore-keys: | + ${{ runner.os }}-turbo- + + - name: Setup Node.js environment + uses: actions/setup-node@v4 + with: + node-version: 20 + cache: 'pnpm' + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + with: + driver-opts: 'image=moby/buildkit:v0.11.6' + + - name: Login + uses: docker/login-action@v3 + with: + registry: ${{ secrets.DOCKER_REGISTRY }} + username: ${{ secrets.DOCKER_REGISTRY_USERNAME }} + password: ${{ secrets.DOCKER_REGISTRY_PASSWORD }} + + - name: Docker meta + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ secrets.DOCKER_IMAGE }} + # generate Docker tags based on the following events/attributes + tags: type=sha + + - name: Install dependencies + run: pnpm install + + - name: Build for Docker + run: NEXT_PUBLIC_BASE_PATH=/new-login pnpm build:docker + + - name: Build and Push Image + id: build + uses: docker/build-push-action@v5 + timeout-minutes: 10 + with: + cache-from: type=gha + cache-to: type=gha,mode=max + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + push: true diff --git a/.gitignore b/.gitignore index 5cf3100aa43..cedeed9b036 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,5 @@ packages/zitadel-server/src/app/proto /playwright-report/ /blob-report/ /playwright/.cache/ +/out +/docker diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000000..65f3326053e --- /dev/null +++ b/Dockerfile @@ -0,0 +1,18 @@ +FROM node:20-alpine + +WORKDIR /app + +RUN addgroup --system --gid 1001 nodejs +RUN adduser --system --uid 1001 nextjs + +# If /.env-file/.env is mounted into the container, its variables are made available to the server before it starts up. +RUN mkdir -p /.env-file && touch /.env-file/.env && chown -R nextjs:nodejs /.env-file + +COPY --chown=nextjs:nodejs ./docker/apps/login/.next/standalone ./ +COPY --chown=nextjs:nodejs ./docker/apps/login/.next/static ./apps/login/.next/static +COPY --chown=nextjs:nodejs ./docker/apps/login/public ./apps/login/public + +USER nextjs +ENV HOSTNAME="0.0.0.0" + +CMD ["/bin/sh", "-c", " set -o allexport && . /.env-file/.env && set +o allexport && node apps/login/server.js"] diff --git a/apps/login/next-env-vars.d.ts b/apps/login/next-env-vars.d.ts index 35fcb109197..112eea393f7 100644 --- a/apps/login/next-env-vars.d.ts +++ b/apps/login/next-env-vars.d.ts @@ -10,10 +10,18 @@ declare namespace NodeJS { SYSTEM_USER_PRIVATE_KEY: string; // The fallback service user private key /** - * Self hosting: The instance url + * Self hosting: The Zitadel API url */ ZITADEL_API_URL: string; + /** + * Takes effect only if ZITADEL_API_URL is not empty. + * This is only relevant if Zitadels runtime has the ZITADEL_INSTANCEHOSTHEADERS config changed. + * The default is x-zitadel-instance-host. + * Most users don't need to set this variable. + */ + ZITADEL_INSTANCE_HOST_HEADER: string; + /** * Self hosting: The service user id */ diff --git a/apps/login/next.config.mjs b/apps/login/next.config.mjs index 32209b11e7a..00fa1e19c4d 100755 --- a/apps/login/next.config.mjs +++ b/apps/login/next.config.mjs @@ -34,27 +34,39 @@ const secureHeaders = [ }, ]; +const imageRemotePatterns = [ + { + protocol: "http", + hostname: "localhost", + port: "8080", + pathname: "/**", + }, + { + protocol: "https", + hostname: "*.zitadel.*", + port: "", + pathname: "/**", + }, +]; + +if (process.env.ZITADEL_API_URL) { + imageRemotePatterns.push({ + protocol: "https", + hostname: process.env.ZITADEL_API_URL?.replace("https://", "") || "", + port: "", + pathname: "/**", + }); +} + const nextConfig = { basePath: process.env.NEXT_PUBLIC_BASE_PATH, + output: process.env.NEXT_OUTPUT_MODE || undefined, reactStrictMode: true, // Recommended for the `pages` directory, default in `app`. experimental: { dynamicIO: true, }, images: { - remotePatterns: [ - { - protocol: "https", - hostname: process.env.ZITADEL_API_URL?.replace("https://", "") || "", - port: "", - pathname: "/**", - }, - { - protocol: "http", - hostname: "localhost", - port: "8080", - pathname: "/**", - }, - ], + remotePatterns: imageRemotePatterns, }, async headers() { return [ diff --git a/apps/login/package.json b/apps/login/package.json index c61aed4c118..9411bc6c691 100644 --- a/apps/login/package.json +++ b/apps/login/package.json @@ -23,6 +23,7 @@ "lint:fix": "prettier --write .", "lint-staged": "lint-staged", "build": "next build", + "build:standalone": "NEXT_OUTPUT_MODE=standalone pnpm build", "prestart": "pnpm build", "start": "next start", "start:built": "next start", diff --git a/apps/login/src/app/(login)/accounts/page.tsx b/apps/login/src/app/(login)/accounts/page.tsx index bc63d990c9c..76ce1fe9add 100644 --- a/apps/login/src/app/(login)/accounts/page.tsx +++ b/apps/login/src/app/(login)/accounts/page.tsx @@ -13,19 +13,13 @@ import { getLocale, getTranslations } from "next-intl/server"; import { headers } from "next/headers"; import Link from "next/link"; -async function loadSessions({ - serviceUrl, - serviceRegion, -}: { - serviceUrl: string; - serviceRegion: string; -}) { +async function loadSessions({ serviceUrl }: { serviceUrl: 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 ?? []; @@ -46,24 +40,23 @@ export default async function Page(props: { const organization = searchParams?.organization; const _headers = await headers(); - const { serviceUrl, serviceRegion } = getServiceUrlFromHeaders(_headers); + const { serviceUrl } = getServiceUrlFromHeaders(_headers); let defaultOrganization; if (!organization) { const org: Organization | null = await getDefaultOrg({ serviceUrl, - serviceRegion, }); if (org) { defaultOrganization = org.id; } } - let sessions = await loadSessions({ serviceUrl, serviceRegion }); + let sessions = await loadSessions({ serviceUrl }); 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 634b1168158..55a7eb6946e 100644 --- a/apps/login/src/app/(login)/authenticator/set/page.tsx +++ b/apps/login/src/app/(login)/authenticator/set/page.tsx @@ -30,7 +30,7 @@ export default async function Page(props: { const { loginName, authRequestId, organization, sessionId } = searchParams; const _headers = await headers(); - const { serviceUrl, serviceRegion } = getServiceUrlFromHeaders(_headers); + const { serviceUrl } = getServiceUrlFromHeaders(_headers); const sessionWithData = sessionId ? await loadSessionById(serviceUrl, sessionId, organization) @@ -38,7 +38,7 @@ export default async function Page(props: { async function getAuthMethodsAndUser( serviceUrl: string, - serviceRegion: string, + session?: Session, ) { const userId = session?.factors?.user?.id; @@ -49,10 +49,10 @@ export default async function Page(props: { return listAuthenticationMethodTypes({ serviceUrl, - serviceRegion, + userId, }).then((methods) => { - return getUserByID({ serviceUrl, serviceRegion, userId }).then((user) => { + return getUserByID({ serviceUrl, userId }).then((user) => { const humanUser = user.user?.type.case === "human" ? user.user?.type.value : undefined; @@ -74,13 +74,13 @@ export default async function Page(props: { ) { return loadMostRecentSession({ serviceUrl, - serviceRegion, + sessionParams: { loginName, organization, }, }).then((session) => { - return getAuthMethodsAndUser(serviceUrl, serviceRegion, session); + return getAuthMethodsAndUser(serviceUrl, session); }); } @@ -92,13 +92,13 @@ 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, - serviceRegion, + sessionResponse.session, ); }); @@ -110,19 +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 14ad793014c..9490b62bf22 100644 --- a/apps/login/src/app/(login)/idp/[provider]/failure/page.tsx +++ b/apps/login/src/app/(login)/idp/[provider]/failure/page.tsx @@ -25,17 +25,17 @@ export default async function Page(props: { const { organization, userId } = searchParams; const _headers = await headers(); - const { serviceUrl, serviceRegion } = getServiceUrlFromHeaders(_headers); + const { serviceUrl } = getServiceUrlFromHeaders(_headers); const branding = await getBrandingSettings({ serviceUrl, - serviceRegion, + organization, }); const loginSettings = await getLoginSettings({ serviceUrl, - serviceRegion, + organization, }); @@ -54,7 +54,7 @@ export default async function Page(props: { if (userId) { const userResponse = await getUserByID({ serviceUrl, - serviceRegion, + userId, }); if (userResponse) { @@ -70,7 +70,7 @@ export default async function Page(props: { const authMethodsResponse = await listAuthenticationMethodTypes({ serviceUrl, - serviceRegion, + userId, }); if (authMethodsResponse.authMethodTypes) { 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 425e9f0caf8..0d67b446c4f 100644 --- a/apps/login/src/app/(login)/idp/[provider]/success/page.tsx +++ b/apps/login/src/app/(login)/idp/[provider]/success/page.tsx @@ -40,11 +40,11 @@ export default async function Page(props: { const { provider } = params; const _headers = await headers(); - const { serviceUrl, serviceRegion } = getServiceUrlFromHeaders(_headers); + const { serviceUrl } = getServiceUrlFromHeaders(_headers); const branding = await getBrandingSettings({ serviceUrl, - serviceRegion, + organization, }); @@ -54,7 +54,7 @@ export default async function Page(props: { const intent = await retrieveIDPIntent({ serviceUrl, - serviceRegion, + id, token, }); @@ -79,7 +79,7 @@ export default async function Page(props: { const idp = await getIDPByID({ serviceUrl, - serviceRegion, + id: idpInformation.idpId, }); const options = idp?.config?.options; @@ -100,7 +100,7 @@ export default async function Page(props: { try { idpLink = await addIDPLink({ serviceUrl, - serviceRegion, + idp: { id: idpInformation.idpId, userId: idpInformation.userId, @@ -131,23 +131,21 @@ export default async function Page(props: { const email = PROVIDER_MAPPING[providerType](idpInformation).email?.email; if (options.autoLinking === AutoLinkingOption.EMAIL && email) { - foundUser = await listUsers({ serviceUrl, serviceRegion, email }).then( - (response) => { - return response.result ? response.result[0] : null; - }, - ); + foundUser = await listUsers({ serviceUrl, email }).then((response) => { + return response.result ? response.result[0] : null; + }); } else if (options.autoLinking === AutoLinkingOption.USERNAME) { foundUser = await listUsers( options.autoLinking === AutoLinkingOption.USERNAME - ? { serviceUrl, serviceRegion, userName: idpInformation.userName } - : { serviceUrl, serviceRegion, email }, + ? { serviceUrl, userName: idpInformation.userName } + : { serviceUrl, email }, ).then((response) => { return response.result ? response.result[0] : null; }); } else { foundUser = await listUsers({ serviceUrl, - serviceRegion, + userName: idpInformation.userName, email, }).then((response) => { @@ -160,7 +158,7 @@ export default async function Page(props: { try { idpLink = await addIDPLink({ serviceUrl, - serviceRegion, + idp: { id: idpInformation.idpId, userId: idpInformation.userId, @@ -203,7 +201,7 @@ export default async function Page(props: { // this just returns orgs where the suffix is set as primary domain const orgs = await getOrgsByDomain({ serviceUrl, - serviceRegion, + domain: suffix, }); const orgToCheckForDiscovery = @@ -211,7 +209,7 @@ export default async function Page(props: { const orgLoginSettings = await getLoginSettings({ serviceUrl, - serviceRegion, + organization: orgToCheckForDiscovery, }); if (orgLoginSettings?.allowDomainDiscovery) { @@ -232,7 +230,7 @@ export default async function Page(props: { const newUser = await addHuman({ serviceUrl, - serviceRegion, + request: userData, }); diff --git a/apps/login/src/app/(login)/idp/page.tsx b/apps/login/src/app/(login)/idp/page.tsx index 80829557ecd..6cbe5291be4 100644 --- a/apps/login/src/app/(login)/idp/page.tsx +++ b/apps/login/src/app/(login)/idp/page.tsx @@ -16,11 +16,11 @@ export default async function Page(props: { const organization = searchParams?.organization; const _headers = await headers(); - const { serviceUrl, serviceRegion } = getServiceUrlFromHeaders(_headers); + const { serviceUrl } = getServiceUrlFromHeaders(_headers); const identityProviders = await getActiveIdentityProviders({ serviceUrl, - serviceRegion, + orgId: organization, }).then((resp) => { return resp.identityProviders; @@ -28,7 +28,7 @@ export default async function Page(props: { const branding = await getBrandingSettings({ serviceUrl, - serviceRegion, + organization, }); diff --git a/apps/login/src/app/(login)/invite/page.tsx b/apps/login/src/app/(login)/invite/page.tsx index f9c84058556..1efe8b98a80 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, serviceRegion } = getServiceUrlFromHeaders(_headers); + const { serviceUrl } = getServiceUrlFromHeaders(_headers); if (!organization) { - const org = await getDefaultOrg({ serviceUrl, serviceRegion }); + const org = await getDefaultOrg({ serviceUrl }); if (!org) { throw new Error("No default organization found"); } @@ -34,19 +34,19 @@ export default async function Page(props: { const loginSettings = await getLoginSettings({ serviceUrl, - serviceRegion, + organization, }); const passwordComplexitySettings = await getPasswordComplexitySettings({ serviceUrl, - serviceRegion, + organization, }); const branding = await getBrandingSettings({ serviceUrl, - serviceRegion, + organization, }); diff --git a/apps/login/src/app/(login)/invite/success/page.tsx b/apps/login/src/app/(login)/invite/success/page.tsx index 155849ebb92..b38735aa308 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, serviceRegion } = getServiceUrlFromHeaders(_headers); + const { serviceUrl } = getServiceUrlFromHeaders(_headers); if (!organization) { - const org = await getDefaultOrg({ serviceUrl, serviceRegion }); + const org = await getDefaultOrg({ serviceUrl }); if (!org) { throw new Error("No default organization found"); } @@ -32,7 +32,7 @@ export default async function Page(props: { const branding = await getBrandingSettings({ serviceUrl, - serviceRegion, + organization, }); @@ -41,7 +41,7 @@ export default async function Page(props: { if (userId) { const userResponse = await getUserByID({ serviceUrl, - serviceRegion, + userId, }); if (userResponse) { diff --git a/apps/login/src/app/(login)/loginname/page.tsx b/apps/login/src/app/(login)/loginname/page.tsx index 7f8cb928128..e39bd3cddb0 100644 --- a/apps/login/src/app/(login)/loginname/page.tsx +++ b/apps/login/src/app/(login)/loginname/page.tsx @@ -26,13 +26,12 @@ export default async function Page(props: { const submit: boolean = searchParams?.submit === "true"; const _headers = await headers(); - const { serviceUrl, serviceRegion } = getServiceUrlFromHeaders(_headers); + const { serviceUrl } = getServiceUrlFromHeaders(_headers); let defaultOrganization; if (!organization) { const org: Organization | null = await getDefaultOrg({ serviceUrl, - serviceRegion, }); if (org) { defaultOrganization = org.id; @@ -41,19 +40,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; @@ -61,7 +60,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 53fc650788c..2152c5e069d 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, serviceRegion } = getServiceUrlFromHeaders(_headers); + const { serviceUrl } = getServiceUrlFromHeaders(_headers); const sessionFactors = sessionId ? await loadSessionById(serviceUrl, sessionId, organization) @@ -38,7 +38,7 @@ export default async function Page(props: { ) { return loadMostRecentSession({ serviceUrl, - serviceRegion, + sessionParams: { loginName, organization, @@ -47,7 +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 { @@ -67,14 +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 { @@ -88,7 +88,7 @@ export default async function Page(props: { const branding = await getBrandingSettings({ serviceUrl, - serviceRegion, + organization, }); diff --git a/apps/login/src/app/(login)/mfa/set/page.tsx b/apps/login/src/app/(login)/mfa/set/page.tsx index 64e9cd7605b..04558689c8a 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, serviceRegion } = getServiceUrlFromHeaders(_headers); + const { serviceUrl } = getServiceUrlFromHeaders(_headers); const sessionWithData = sessionId ? await loadSessionById(serviceUrl, sessionId, organization) @@ -67,10 +67,10 @@ export default async function Page(props: { return listAuthenticationMethodTypes({ serviceUrl, - serviceRegion, + userId, }).then((methods) => { - return getUserByID({ serviceUrl, serviceRegion, userId }).then((user) => { + return getUserByID({ serviceUrl, userId }).then((user) => { const humanUser = user.user?.type.case === "human" ? user.user?.type.value : undefined; @@ -92,7 +92,7 @@ export default async function Page(props: { ) { return loadMostRecentSession({ serviceUrl, - serviceRegion, + sessionParams: { loginName, organization, @@ -110,7 +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) => { @@ -120,12 +120,12 @@ export default async function Page(props: { 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 3f3072dd07a..c938167ba1a 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, serviceRegion } = getServiceUrlFromHeaders(_headers); + const { serviceUrl } = getServiceUrlFromHeaders(_headers); const host = _headers.get("host"); if (!host || typeof host !== "string") { @@ -47,7 +47,7 @@ export default async function Page(props: { ? await loadSessionById(serviceUrl, sessionId, organization) : await loadMostRecentSession({ serviceUrl, - serviceRegion, + sessionParams: { loginName, organization }, }); @@ -59,7 +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) => { @@ -72,13 +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 3de97510fd3..6bee1d3d9e9 100644 --- a/apps/login/src/app/(login)/otp/[method]/set/page.tsx +++ b/apps/login/src/app/(login)/otp/[method]/set/page.tsx @@ -34,22 +34,22 @@ export default async function Page(props: { const { method } = params; const _headers = await headers(); - const { serviceUrl, serviceRegion } = getServiceUrlFromHeaders(_headers); + const { serviceUrl } = getServiceUrlFromHeaders(_headers); const branding = await getBrandingSettings({ serviceUrl, - serviceRegion, + organization, }); const loginSettings = await getLoginSettings({ serviceUrl, - serviceRegion, + organization, }); const session = await loadMostRecentSession({ serviceUrl, - serviceRegion, + sessionParams: { loginName, organization, @@ -61,7 +61,7 @@ export default async function Page(props: { if (method === "time-based") { await registerTOTP({ serviceUrl, - serviceRegion, + userId: session.factors.user.id, }) .then((resp) => { @@ -76,7 +76,7 @@ export default async function Page(props: { // does not work await addOTPSMS({ serviceUrl, - serviceRegion, + userId: session.factors.user.id, }).catch((error) => { error = new Error("Could not add OTP via SMS"); @@ -85,7 +85,7 @@ export default async function Page(props: { // works await addOTPEmail({ serviceUrl, - serviceRegion, + userId: session.factors.user.id, }).catch((error) => { error = new Error("Could not add OTP via Email"); diff --git a/apps/login/src/app/(login)/passkey/page.tsx b/apps/login/src/app/(login)/passkey/page.tsx index 312eacc5717..749c16d4847 100644 --- a/apps/login/src/app/(login)/passkey/page.tsx +++ b/apps/login/src/app/(login)/passkey/page.tsx @@ -21,13 +21,13 @@ export default async function Page(props: { searchParams; const _headers = await headers(); - const { serviceUrl, serviceRegion } = getServiceUrlFromHeaders(_headers); + const { serviceUrl } = getServiceUrlFromHeaders(_headers); const sessionFactors = sessionId ? await loadSessionById(serviceUrl, sessionId, organization) : await loadMostRecentSession({ serviceUrl, - serviceRegion, + sessionParams: { loginName, organization }, }); @@ -39,7 +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,7 +51,7 @@ export default async function Page(props: { const branding = await getBrandingSettings({ serviceUrl, - serviceRegion, + organization, }); diff --git a/apps/login/src/app/(login)/passkey/set/page.tsx b/apps/login/src/app/(login)/passkey/set/page.tsx index e2f34ae830a..4617bc756f1 100644 --- a/apps/login/src/app/(login)/passkey/set/page.tsx +++ b/apps/login/src/app/(login)/passkey/set/page.tsx @@ -20,11 +20,11 @@ export default async function Page(props: { searchParams; const _headers = await headers(); - const { serviceUrl, serviceRegion } = getServiceUrlFromHeaders(_headers); + const { serviceUrl } = getServiceUrlFromHeaders(_headers); const session = await loadMostRecentSession({ serviceUrl, - serviceRegion, + sessionParams: { loginName, organization, @@ -33,7 +33,7 @@ export default async function Page(props: { const branding = await getBrandingSettings({ serviceUrl, - serviceRegion, + organization, }); diff --git a/apps/login/src/app/(login)/password/change/page.tsx b/apps/login/src/app/(login)/password/change/page.tsx index 28f77a4b6d8..16aa4d10588 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, serviceRegion } = getServiceUrlFromHeaders(_headers); + const { serviceUrl } = getServiceUrlFromHeaders(_headers); const searchParams = await props.searchParams; const locale = getLocale(); @@ -28,7 +28,7 @@ export default async function Page(props: { // also allow no session to be found (ignoreUnkownUsername) const sessionFactors = await loadMostRecentSession({ serviceUrl, - serviceRegion, + sessionParams: { loginName, organization, @@ -37,19 +37,19 @@ export default async function Page(props: { 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 b9b17568132..a230424b254 100644 --- a/apps/login/src/app/(login)/password/page.tsx +++ b/apps/login/src/app/(login)/password/page.tsx @@ -25,13 +25,12 @@ export default async function Page(props: { let { loginName, organization, authRequestId, alt } = searchParams; const _headers = await headers(); - const { serviceUrl, serviceRegion } = getServiceUrlFromHeaders(_headers); + const { serviceUrl } = getServiceUrlFromHeaders(_headers); let defaultOrganization; if (!organization) { const org: Organization | null = await getDefaultOrg({ serviceUrl, - serviceRegion, }); if (org) { @@ -44,7 +43,7 @@ export default async function Page(props: { try { sessionFactors = await loadMostRecentSession({ serviceUrl, - serviceRegion, + sessionParams: { loginName, organization, @@ -57,12 +56,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 a6537b3513f..9690683f70f 100644 --- a/apps/login/src/app/(login)/password/set/page.tsx +++ b/apps/login/src/app/(login)/password/set/page.tsx @@ -27,14 +27,14 @@ export default async function Page(props: { searchParams; const _headers = await headers(); - const { serviceUrl, serviceRegion } = getServiceUrlFromHeaders(_headers); + const { serviceUrl } = getServiceUrlFromHeaders(_headers); // also allow no session to be found (ignoreUnkownUsername) let session: Session | undefined; if (loginName) { session = await loadMostRecentSession({ serviceUrl, - serviceRegion, + sessionParams: { loginName, organization, @@ -44,19 +44,19 @@ export default async function Page(props: { const branding = await getBrandingSettings({ serviceUrl, - serviceRegion, + organization, }); const passwordComplexity = await getPasswordComplexitySettings({ serviceUrl, - serviceRegion, + organization: session?.factors?.user?.organizationId, }); const loginSettings = await getLoginSettings({ serviceUrl, - serviceRegion, + organization, }); @@ -65,7 +65,7 @@ export default async function Page(props: { if (userId) { const userResponse = await getUserByID({ serviceUrl, - serviceRegion, + userId, }); user = userResponse.user; diff --git a/apps/login/src/app/(login)/register/page.tsx b/apps/login/src/app/(login)/register/page.tsx index 9fe2f3393c8..7f3a17036d4 100644 --- a/apps/login/src/app/(login)/register/page.tsx +++ b/apps/login/src/app/(login)/register/page.tsx @@ -23,12 +23,11 @@ export default async function Page(props: { searchParams; const _headers = await headers(); - const { serviceUrl, serviceRegion } = getServiceUrlFromHeaders(_headers); + const { serviceUrl } = getServiceUrlFromHeaders(_headers); if (!organization) { const org: Organization | null = await getDefaultOrg({ serviceUrl, - serviceRegion, }); if (org) { organization = org.id; @@ -37,24 +36,24 @@ export default async function Page(props: { const legal = await getLegalAndSupportSettings({ serviceUrl, - serviceRegion, + organization, }); const passwordComplexitySettings = await getPasswordComplexitySettings({ serviceUrl, - serviceRegion, + organization, }); const branding = await getBrandingSettings({ serviceUrl, - serviceRegion, + organization, }); const loginSettings = await getLoginSettings({ serviceUrl, - serviceRegion, + organization, }); diff --git a/apps/login/src/app/(login)/register/password/page.tsx b/apps/login/src/app/(login)/register/password/page.tsx index aeda4d56f68..47bb651c3b1 100644 --- a/apps/login/src/app/(login)/register/password/page.tsx +++ b/apps/login/src/app/(login)/register/password/page.tsx @@ -23,12 +23,11 @@ export default async function Page(props: { searchParams; const _headers = await headers(); - const { serviceUrl, serviceRegion } = getServiceUrlFromHeaders(_headers); + const { serviceUrl } = getServiceUrlFromHeaders(_headers); if (!organization) { const org: Organization | null = await getDefaultOrg({ serviceUrl, - serviceRegion, }); if (org) { organization = org.id; @@ -39,24 +38,24 @@ export default async function Page(props: { const legal = await getLegalAndSupportSettings({ serviceUrl, - serviceRegion, + organization, }); const passwordComplexitySettings = await getPasswordComplexitySettings({ serviceUrl, - serviceRegion, + organization, }); const branding = await getBrandingSettings({ serviceUrl, - serviceRegion, + organization, }); const loginSettings = await getLoginSettings({ serviceUrl, - serviceRegion, + organization, }); diff --git a/apps/login/src/app/(login)/signedin/page.tsx b/apps/login/src/app/(login)/signedin/page.tsx index f6897134798..b64e87b56b8 100644 --- a/apps/login/src/app/(login)/signedin/page.tsx +++ b/apps/login/src/app/(login)/signedin/page.tsx @@ -22,7 +22,7 @@ import { redirect } from "next/navigation"; async function loadSession( serviceUrl: string, - serviceRegion: string, + loginName: string, authRequestId?: string, ) { @@ -31,7 +31,7 @@ async function loadSession( if (authRequestId) { return createCallback({ serviceUrl, - serviceRegion, + req: create(CreateCallbackRequestSchema, { authRequestId, callbackKind: { @@ -48,7 +48,7 @@ async function loadSession( } return getSession({ serviceUrl, - serviceRegion, + sessionId: recent.id, sessionToken: recent.token, }).then((response) => { @@ -64,19 +64,19 @@ export default async function Page(props: { searchParams: Promise }) { const t = await getTranslations({ locale, namespace: "signedin" }); const _headers = await headers(); - const { serviceUrl, serviceRegion } = getServiceUrlFromHeaders(_headers); + const { serviceUrl } = getServiceUrlFromHeaders(_headers); const { loginName, authRequestId, organization } = searchParams; const sessionFactors = await loadSession( serviceUrl, - serviceRegion, + loginName, authRequestId, ); const branding = await getBrandingSettings({ serviceUrl, - serviceRegion, + organization, }); @@ -84,7 +84,7 @@ export default async function Page(props: { searchParams: Promise }) { if (!authRequestId) { loginSettings = await getLoginSettings({ serviceUrl, - serviceRegion, + organization, }); } diff --git a/apps/login/src/app/(login)/u2f/page.tsx b/apps/login/src/app/(login)/u2f/page.tsx index e0a21103a87..1b8b30af14c 100644 --- a/apps/login/src/app/(login)/u2f/page.tsx +++ b/apps/login/src/app/(login)/u2f/page.tsx @@ -20,7 +20,7 @@ export default async function Page(props: { const { loginName, authRequestId, sessionId, organization } = searchParams; const _headers = await headers(); - const { serviceUrl, serviceRegion } = getServiceUrlFromHeaders(_headers); + const { serviceUrl } = getServiceUrlFromHeaders(_headers); const host = _headers.get("host"); if (!host || typeof host !== "string") { @@ -29,7 +29,7 @@ export default async function Page(props: { const branding = await getBrandingSettings({ serviceUrl, - serviceRegion, + organization, }); @@ -37,7 +37,7 @@ export default async function Page(props: { ? await loadSessionById(serviceUrl, sessionId, organization) : await loadMostRecentSession({ serviceUrl, - serviceRegion, + sessionParams: { loginName, organization }, }); @@ -49,7 +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 850f2652d0b..f657a3ff8d4 100644 --- a/apps/login/src/app/(login)/u2f/set/page.tsx +++ b/apps/login/src/app/(login)/u2f/set/page.tsx @@ -19,11 +19,11 @@ export default async function Page(props: { const { loginName, organization, authRequestId, checkAfter } = searchParams; const _headers = await headers(); - const { serviceUrl, serviceRegion } = getServiceUrlFromHeaders(_headers); + const { serviceUrl } = getServiceUrlFromHeaders(_headers); const sessionFactors = await loadMostRecentSession({ serviceUrl, - serviceRegion, + sessionParams: { loginName, organization, @@ -32,7 +32,7 @@ export default async function Page(props: { const branding = await getBrandingSettings({ serviceUrl, - serviceRegion, + organization, }); diff --git a/apps/login/src/app/(login)/verify/page.tsx b/apps/login/src/app/(login)/verify/page.tsx index 628d07f36fe..9d35c8ae3d1 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, serviceRegion } = getServiceUrlFromHeaders(_headers); + const { serviceUrl } = getServiceUrlFromHeaders(_headers); const host = _headers.get("host"); if (!host || typeof host !== "string") { @@ -35,7 +35,7 @@ export default async function Page(props: { searchParams: Promise }) { const branding = await getBrandingSettings({ serviceUrl, - serviceRegion, + organization, }); @@ -49,7 +49,7 @@ export default async function Page(props: { searchParams: Promise }) { if ("loginName" in searchParams) { sessionFactors = await loadMostRecentSession({ serviceUrl, - serviceRegion, + sessionParams: { loginName, organization, @@ -59,7 +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` + @@ -73,7 +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` + @@ -86,7 +86,7 @@ export default async function Page(props: { searchParams: Promise }) { const userResponse = await getUserByID({ serviceUrl, - serviceRegion, + userId, }); if (userResponse) { diff --git a/apps/login/src/app/login/route.ts b/apps/login/src/app/login/route.ts index 8114807ac0b..9d95e28d70f 100644 --- a/apps/login/src/app/login/route.ts +++ b/apps/login/src/app/login/route.ts @@ -32,16 +32,14 @@ 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), }); @@ -58,7 +56,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 @@ -71,7 +69,7 @@ async function isSessionValid( const authMethodTypes = await listAuthenticationMethodTypes({ serviceUrl, - serviceRegion, + userId: session.factors.user.id, }); @@ -121,7 +119,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) { @@ -165,7 +163,7 @@ async function isSessionValid( async function findValidSession( serviceUrl: string, - serviceRegion: string, + sessions: Session[], authRequest: AuthRequest, ): Promise { @@ -192,7 +190,7 @@ async function findValidSession( // return the first valid session according to settings for (const session of sessionsWithHint) { - if (await isSessionValid(serviceUrl, serviceRegion, session)) { + if (await isSessionValid(serviceUrl, session)) { return session; } } @@ -200,15 +198,26 @@ async function findValidSession( return undefined; } +function constructUrl(request: NextRequest, path: string) { + const forwardedHost = + request.headers.get("x-zitadel-forward-host") ?? + request.headers.get("host"); + const basePath = process.env.NEXT_PUBLIC_BASE_PATH || ""; + return new URL( + `${basePath}${path}`, + forwardedHost?.startsWith("http") + ? forwardedHost + : `https://${forwardedHost}`, + ); +} + export async function GET(request: NextRequest) { const searchParams = request.nextUrl.searchParams; const authRequestId = searchParams.get("authRequest"); const sessionId = searchParams.get("sessionId"); - console.log("requesturl", request.url); - const _headers = await headers(); - const { serviceUrl, serviceRegion } = getServiceUrlFromHeaders(_headers); + const { serviceUrl } = 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"); @@ -220,7 +229,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, serviceRegion, ids }); + sessions = await loadSessions({ serviceUrl, ids }); } if (authRequestId && sessionId) { @@ -235,7 +244,7 @@ export async function GET(request: NextRequest) { const isValid = await isSessionValid( serviceUrl, - serviceRegion, + selectedSession, ); @@ -253,7 +262,7 @@ export async function GET(request: NextRequest) { const res = await sendLoginname(command); if (res && "redirect" in res && res?.redirect) { - const absoluteUrl = new URL(res.redirect, request.url); + const absoluteUrl = new URL(res.redirect, request.nextUrl); return NextResponse.redirect(absoluteUrl.toString()); } } @@ -272,7 +281,7 @@ export async function GET(request: NextRequest) { try { const { callbackUrl } = await createCallback({ serviceUrl, - serviceRegion, + req: create(CreateCallbackRequestSchema, { authRequestId, callbackKind: { @@ -300,7 +309,7 @@ export async function GET(request: NextRequest) { ) { const loginSettings = await getLoginSettings({ serviceUrl, - serviceRegion, + organization: selectedSession.factors?.user?.organizationId, }); @@ -308,21 +317,30 @@ export async function GET(request: NextRequest) { return NextResponse.redirect(loginSettings.defaultRedirectUri); } - const signedinUrl = new URL("/signedin", request.url); + const signedinUrl = constructUrl(request, "/signedin"); + const params = new URLSearchParams(); if (selectedSession.factors?.user?.loginName) { - signedinUrl.searchParams.set( + params.append( "loginName", selectedSession.factors?.user?.loginName, ); + // signedinUrl.searchParams.set( + // "loginName", + // selectedSession.factors?.user?.loginName, + // ); } if (selectedSession.factors?.user?.organizationId) { - signedinUrl.searchParams.set( + params.append( "organization", selectedSession.factors?.user?.organizationId, ); + // signedinUrl.searchParams.set( + // "organization", + // selectedSession.factors?.user?.organizationId, + // ); } - return NextResponse.redirect(signedinUrl); + return NextResponse.redirect(signedinUrl + "?" + params); } else { return NextResponse.json({ error }, { status: 500 }); } @@ -334,7 +352,7 @@ export async function GET(request: NextRequest) { if (authRequestId) { const { authRequest } = await getAuthRequest({ serviceUrl, - serviceRegion, + authRequestId, }); @@ -365,7 +383,7 @@ export async function GET(request: NextRequest) { if (orgDomain) { const orgs = await getOrgsByDomain({ serviceUrl, - serviceRegion, + domain: orgDomain, }); if (orgs.result && orgs.result.length === 1) { @@ -382,7 +400,7 @@ export async function GET(request: NextRequest) { const identityProviders = await getActiveIdentityProviders({ serviceUrl, - serviceRegion, + orgId: organization ? organization : undefined, }).then((resp) => { return resp.identityProviders; @@ -408,7 +426,7 @@ export async function GET(request: NextRequest) { return startIdentityProviderFlow({ serviceUrl, - serviceRegion, + idpId, urls: { successUrl: @@ -431,27 +449,33 @@ export async function GET(request: NextRequest) { } const gotoAccounts = (): NextResponse => { - const accountsUrl = new URL("/accounts", request.url); + const accountsUrl = constructUrl(request, "/accounts"); + const params = new URLSearchParams(); if (authRequest?.id) { - accountsUrl.searchParams.set("authRequestId", authRequest?.id); + params.append("authRequestId", authRequest.id); + // accountsUrl.searchParams.set("authRequestId", authRequest?.id); } if (organization) { - accountsUrl.searchParams.set("organization", organization); + params.append("organization", organization); + // accountsUrl.searchParams.set("organization", organization); } - return NextResponse.redirect(accountsUrl); + return NextResponse.redirect(accountsUrl + "?" + params); }; if (authRequest && authRequest.prompt.includes(Prompt.CREATE)) { - const registerUrl = new URL("/register", request.url); + const registerUrl = constructUrl(request, "/register"); + const params = new URLSearchParams(); if (authRequest.id) { - registerUrl.searchParams.set("authRequestId", authRequest.id); + params.append("authRequestId", authRequest.id); + // registerUrl.searchParams.set("authRequestId", authRequest.id); } if (organization) { - registerUrl.searchParams.set("organization", organization); + params.append("organization", organization); + // registerUrl.searchParams.set("organization", organization); } - return NextResponse.redirect(registerUrl); + return NextResponse.redirect(registerUrl + "?" + params); } // use existing session and hydrate it for oidc @@ -479,7 +503,7 @@ export async function GET(request: NextRequest) { const res = await sendLoginname(command); if (res && "redirect" in res && res?.redirect) { - const absoluteUrl = new URL(res.redirect, request.url); + const absoluteUrl = new URL(res.redirect, request.nextUrl); return NextResponse.redirect(absoluteUrl.toString()); } } catch (error) { @@ -487,20 +511,27 @@ export async function GET(request: NextRequest) { } } - const loginNameUrl = new URL("/loginname", request.url); + const loginNameUrl = constructUrl(request, "/loginname"); + + const params = new URLSearchParams(); + if (authRequest.id) { - loginNameUrl.searchParams.set("authRequestId", authRequest.id); + params.append("authRequestId", authRequest.id); + // loginNameUrl.searchParams.set("authRequestId", authRequest.id); } if (authRequest.loginHint) { - loginNameUrl.searchParams.set("loginName", authRequest.loginHint); + params.append("loginName", authRequest.loginHint); + // loginNameUrl.searchParams.set("loginName", authRequest.loginHint); } if (organization) { - loginNameUrl.searchParams.set("organization", organization); + params.append("organization", organization); + // loginNameUrl.searchParams.set("organization", organization); } if (suffix) { - loginNameUrl.searchParams.set("suffix", suffix); + params.append("suffix", suffix); + // loginNameUrl.searchParams.set("suffix", suffix); } - return NextResponse.redirect(loginNameUrl); + return NextResponse.redirect(loginNameUrl + "?" + params); } else if (authRequest.prompt.includes(Prompt.NONE)) { /** * With an OIDC none prompt, the authentication server must not display any authentication or consent user interface pages. @@ -509,7 +540,7 @@ export async function GET(request: NextRequest) { **/ const selectedSession = await findValidSession( serviceUrl, - serviceRegion, + sessions, authRequest, ); @@ -539,7 +570,7 @@ export async function GET(request: NextRequest) { const { callbackUrl } = await createCallback({ serviceUrl, - serviceRegion, + req: create(CreateCallbackRequestSchema, { authRequestId, callbackKind: { @@ -553,7 +584,7 @@ export async function GET(request: NextRequest) { // check for loginHint, userId hint and valid sessions let selectedSession = await findValidSession( serviceUrl, - serviceRegion, + sessions, authRequest, ); @@ -578,7 +609,7 @@ export async function GET(request: NextRequest) { try { const { callbackUrl } = await createCallback({ serviceUrl, - serviceRegion, + req: create(CreateCallbackRequestSchema, { authRequestId, callbackKind: { @@ -601,19 +632,24 @@ export async function GET(request: NextRequest) { } } } else { - const loginNameUrl = new URL("/loginname", request.url); + const loginNameUrl = constructUrl(request, "/loginname"); - loginNameUrl.searchParams.set("authRequestId", authRequestId); + const params = new URLSearchParams(); + params.set("authRequestId", authRequestId); + // loginNameUrl.searchParams.set("authRequestId", authRequestId); if (authRequest?.loginHint) { - loginNameUrl.searchParams.set("loginName", authRequest.loginHint); - loginNameUrl.searchParams.set("submit", "true"); // autosubmit + params.set("loginName", authRequest.loginHint); + params.set("submit", "true"); // autosubmit + // loginNameUrl.searchParams.set("loginName", authRequest.loginHint); + // loginNameUrl.searchParams.set("submit", "true"); // autosubmit } if (organization) { - loginNameUrl.searchParams.set("organization", organization); + params.set("organization", organization); + // loginNameUrl.searchParams.set("organization", organization); } - return NextResponse.redirect(loginNameUrl); + return NextResponse.redirect(loginNameUrl + "?" + params); } } else { return NextResponse.json( diff --git a/apps/login/src/lib/api.ts b/apps/login/src/lib/api.ts index 15e85fd2b68..73240073074 100644 --- a/apps/login/src/lib/api.ts +++ b/apps/login/src/lib/api.ts @@ -1,37 +1,14 @@ import { newSystemToken } from "@zitadel/client/node"; -export async function systemAPIToken({ - serviceRegion, -}: { - serviceRegion: string; -}) { - const prefix = serviceRegion.toUpperCase(); +export async function systemAPIToken() { 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"), + audience: process.env.AUDIENCE, + userID: process.env.SYSTEM_USER_ID, + token: Buffer.from(process.env.SYSTEM_USER_PRIVATE_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"), - }; - - return newSystemToken({ - audience: fallbackToken.audience, - subject: fallbackToken.userID, - key: fallbackToken.token, - }); - } - return newSystemToken({ audience: token.audience, subject: token.userID, diff --git a/apps/login/src/lib/self.ts b/apps/login/src/lib/self.ts index 178583fb406..a68ba381802 100644 --- a/apps/login/src/lib/self.ts +++ b/apps/login/src/lib/self.ts @@ -26,13 +26,13 @@ export async function setMyPassword({ password: string; }) { const _headers = await headers(); - const { serviceUrl, serviceRegion } = getServiceUrlFromHeaders(_headers); + const { serviceUrl } = 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 03a421674d1..154a052a7fc 100644 --- a/apps/login/src/lib/server/cookie.ts +++ b/apps/login/src/lib/server/cookie.ts @@ -53,11 +53,11 @@ export async function createSessionAndUpdateCookie( lifetime?: Duration, ): Promise { const _headers = await headers(); - const { serviceUrl, serviceRegion } = getServiceUrlFromHeaders(_headers); + const { serviceUrl } = getServiceUrlFromHeaders(_headers); const createdSession = await createSessionFromChecks({ serviceUrl, - serviceRegion, + checks, challenges, lifetime, @@ -66,7 +66,7 @@ export async function createSessionAndUpdateCookie( if (createdSession) { return getSession({ serviceUrl, - serviceRegion, + sessionId: createdSession.sessionId, sessionToken: createdSession.sessionToken, }).then((response) => { @@ -117,11 +117,11 @@ export async function createSessionForIdpAndUpdateCookie( lifetime?: Duration, ): Promise { const _headers = await headers(); - const { serviceUrl, serviceRegion } = getServiceUrlFromHeaders(_headers); + const { serviceUrl } = getServiceUrlFromHeaders(_headers); const createdSession = await createSessionForUserIdAndIdpIntent({ serviceUrl, - serviceRegion, + userId, idpIntent, lifetime, @@ -142,7 +142,7 @@ export async function createSessionForIdpAndUpdateCookie( const { session } = await getSession({ serviceUrl, - serviceRegion, + sessionId: createdSession.sessionId, sessionToken: createdSession.sessionToken, }); @@ -190,11 +190,11 @@ export async function setSessionAndUpdateCookie( lifetime?: Duration, ) { const _headers = await headers(); - const { serviceUrl, serviceRegion } = getServiceUrlFromHeaders(_headers); + const { serviceUrl } = getServiceUrlFromHeaders(_headers); return setSession({ serviceUrl, - serviceRegion, + sessionId: recentCookie.id, sessionToken: recentCookie.token, challenges, @@ -222,7 +222,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 c12f518fd38..68759f039a4 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, serviceRegion } = getServiceUrlFromHeaders(_headers); + const { serviceUrl } = getServiceUrlFromHeaders(_headers); const host = _headers.get("host"); if (!host) { @@ -28,7 +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}`, @@ -61,7 +61,7 @@ export async function createNewSessionFromIdpIntent( command: CreateNewSessionCommand, ) { const _headers = await headers(); - const { serviceUrl, serviceRegion } = getServiceUrlFromHeaders(_headers); + const { serviceUrl } = getServiceUrlFromHeaders(_headers); const host = _headers.get("host"); if (!host) { @@ -74,7 +74,7 @@ export async function createNewSessionFromIdpIntent( const userResponse = await getUserByID({ serviceUrl, - serviceRegion, + userId: command.userId, }); @@ -84,7 +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 864c91540e4..02dcfc7f75a 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, serviceRegion } = getServiceUrlFromHeaders(_headers); + const { serviceUrl } = getServiceUrlFromHeaders(_headers); const host = _headers.get("host"); if (!host) { @@ -31,7 +31,7 @@ export async function inviteUser(command: InviteUserCommand) { const human = await addHumanUser({ serviceUrl, - serviceRegion, + email: command.email, firstName: command.firstName, lastName: command.lastName, @@ -45,7 +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 7bcf30723d0..e3c01dfa732 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, serviceRegion } = getServiceUrlFromHeaders(_headers); + const { serviceUrl } = getServiceUrlFromHeaders(_headers); const host = _headers.get("host"); if (!host) { @@ -43,7 +43,7 @@ export async function sendLoginname(command: SendLoginnameCommand) { const loginSettingsByContext = await getLoginSettings({ serviceUrl, - serviceRegion, + organization: command.organization, }); @@ -53,7 +53,7 @@ export async function sendLoginname(command: SendLoginnameCommand) { let searchUsersRequest: SearchUsersCommand = { serviceUrl, - serviceRegion, + searchValue: command.loginName, organizationId: command.organization, loginSettings: loginSettingsByContext, @@ -75,7 +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; @@ -83,7 +83,7 @@ export async function sendLoginname(command: SendLoginnameCommand) { if (identityProviders.length === 1) { const _headers = await headers(); - const { serviceUrl, serviceRegion } = getServiceUrlFromHeaders(_headers); + const { serviceUrl } = getServiceUrlFromHeaders(_headers); const host = _headers.get("host"); if (!host) { @@ -106,7 +106,7 @@ export async function sendLoginname(command: SendLoginnameCommand) { const resp = await startIdentityProviderFlow({ serviceUrl, - serviceRegion, + idpId: identityProviders[0].id, urls: { successUrl: @@ -127,7 +127,7 @@ export async function sendLoginname(command: SendLoginnameCommand) { const redirectUserToIDP = async (userId: string) => { const identityProviders = await listIDPLinks({ serviceUrl, - serviceRegion, + userId, }).then((resp) => { return resp.result; @@ -135,7 +135,7 @@ export async function sendLoginname(command: SendLoginnameCommand) { if (identityProviders.length === 1) { const _headers = await headers(); - const { serviceUrl, serviceRegion } = getServiceUrlFromHeaders(_headers); + const { serviceUrl } = getServiceUrlFromHeaders(_headers); const host = _headers.get("host"); if (!host) { @@ -146,7 +146,7 @@ export async function sendLoginname(command: SendLoginnameCommand) { const idp = await getIDPByID({ serviceUrl, - serviceRegion, + id: identityProviderId, }); @@ -171,7 +171,7 @@ export async function sendLoginname(command: SendLoginnameCommand) { const resp = await startIdentityProviderFlow({ serviceUrl, - serviceRegion, + idpId: idp.id, urls: { successUrl: @@ -197,7 +197,7 @@ export async function sendLoginname(command: SendLoginnameCommand) { const userLoginSettings = await getLoginSettings({ serviceUrl, - serviceRegion, + organization: user.details?.resourceOwner, }); @@ -256,7 +256,7 @@ export async function sendLoginname(command: SendLoginnameCommand) { const methods = await listAuthenticationMethodTypes({ serviceUrl, - serviceRegion, + userId: session.factors?.user?.id, }); @@ -415,7 +415,7 @@ export async function sendLoginname(command: SendLoginnameCommand) { // this just returns orgs where the suffix is set as primary domain const orgs = await getOrgsByDomain({ serviceUrl, - serviceRegion, + domain: suffix, }); const orgToCheckForDiscovery = @@ -423,7 +423,7 @@ export async function sendLoginname(command: SendLoginnameCommand) { 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 6d56d0c5385..5fb21872b0b 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, serviceRegion } = getServiceUrlFromHeaders(_headers); + const { serviceUrl } = getServiceUrlFromHeaders(_headers); const recentSession = command.sessionId ? await getSessionCookieById({ sessionId: command.sessionId }).catch( @@ -64,7 +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 819f319bd47..4de844c1be1 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, serviceRegion } = getServiceUrlFromHeaders(_headers); + const { serviceUrl } = getServiceUrlFromHeaders(_headers); const host = _headers.get("host"); if (!host) { @@ -53,7 +53,7 @@ export async function registerPasskeyLink( const sessionCookie = await getSessionCookieById({ sessionId }); const session = await getSession({ serviceUrl, - serviceRegion, + sessionId: sessionCookie.id, sessionToken: sessionCookie.token, }); @@ -74,7 +74,7 @@ export async function registerPasskeyLink( // use session token to add the passkey const registerLink = await createPasskeyRegistrationLink({ serviceUrl, - serviceRegion, + userId, }); @@ -84,7 +84,7 @@ export async function registerPasskeyLink( return registerPasskey({ serviceUrl, - serviceRegion, + userId, code: registerLink.code, domain: hostname, @@ -93,7 +93,7 @@ export async function registerPasskeyLink( export async function verifyPasskeyRegistration(command: VerifyPasskeyCommand) { const _headers = await headers(); - const { serviceUrl, serviceRegion } = getServiceUrlFromHeaders(_headers); + const { serviceUrl } = getServiceUrlFromHeaders(_headers); // if no name is provided, try to generate one from the user agent let passkeyName = command.passkeyName; @@ -112,7 +112,7 @@ export async function verifyPasskeyRegistration(command: VerifyPasskeyCommand) { }); const session = await getSession({ serviceUrl, - serviceRegion, + sessionId: sessionCookie.id, sessionToken: sessionCookie.token, }); @@ -124,7 +124,7 @@ export async function verifyPasskeyRegistration(command: VerifyPasskeyCommand) { return zitadelVerifyPasskeyRegistration({ serviceUrl, - serviceRegion, + request: create(VerifyPasskeyRegistrationRequestSchema, { passkeyId: command.passkeyId, publicKeyCredential: command.publicKeyCredential, @@ -158,11 +158,11 @@ export async function sendPasskey(command: SendPasskeyCommand) { } const _headers = await headers(); - const { serviceUrl, serviceRegion } = getServiceUrlFromHeaders(_headers); + const { serviceUrl } = getServiceUrlFromHeaders(_headers); const loginSettings = await getLoginSettings({ serviceUrl, - serviceRegion, + organization, }); @@ -186,7 +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 9a464e22d89..8b789881756 100644 --- a/apps/login/src/lib/server/password.ts +++ b/apps/login/src/lib/server/password.ts @@ -47,7 +47,7 @@ type ResetPasswordCommand = { export async function resetPassword(command: ResetPasswordCommand) { const _headers = await headers(); - const { serviceUrl, serviceRegion } = getServiceUrlFromHeaders(_headers); + const { serviceUrl } = getServiceUrlFromHeaders(_headers); const host = _headers.get("host"); if (!host || typeof host !== "string") { @@ -56,7 +56,7 @@ export async function resetPassword(command: ResetPasswordCommand) { const users = await listUsers({ serviceUrl, - serviceRegion, + loginName: command.loginName, organizationId: command.organization, }); @@ -72,7 +72,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}}` + @@ -89,7 +89,7 @@ export type UpdateSessionCommand = { export async function sendPassword(command: UpdateSessionCommand) { const _headers = await headers(); - const { serviceUrl, serviceRegion } = getServiceUrlFromHeaders(_headers); + const { serviceUrl } = getServiceUrlFromHeaders(_headers); let sessionCookie = await getSessionCookieByLoginName({ loginName: command.loginName, @@ -105,7 +105,7 @@ export async function sendPassword(command: UpdateSessionCommand) { if (!sessionCookie) { const users = await listUsers({ serviceUrl, - serviceRegion, + loginName: command.loginName, organizationId: command.organization, }); @@ -120,7 +120,7 @@ export async function sendPassword(command: UpdateSessionCommand) { loginSettings = await getLoginSettings({ serviceUrl, - serviceRegion, + organization: command.organization, }); @@ -135,7 +135,7 @@ export async function sendPassword(command: UpdateSessionCommand) { if ("failedAttempts" in error && error.failedAttempts) { const lockoutSettings = await getLockoutSettings({ serviceUrl, - serviceRegion, + orgId: command.organization, }); @@ -167,7 +167,7 @@ export async function sendPassword(command: UpdateSessionCommand) { if ("failedAttempts" in error && error.failedAttempts) { const lockoutSettings = await getLockoutSettings({ serviceUrl, - serviceRegion, + orgId: command.organization, }); @@ -189,7 +189,7 @@ export async function sendPassword(command: UpdateSessionCommand) { const userResponse = await getUserByID({ serviceUrl, - serviceRegion, + userId: session?.factors?.user?.id, }); @@ -203,7 +203,7 @@ export async function sendPassword(command: UpdateSessionCommand) { if (!loginSettings) { loginSettings = await getLoginSettings({ serviceUrl, - serviceRegion, + organization: command.organization ?? session.factors?.user?.organizationId, }); @@ -217,7 +217,7 @@ export async function sendPassword(command: UpdateSessionCommand) { const expirySettings = await getPasswordExpirySettings({ serviceUrl, - serviceRegion, + orgId: command.organization ?? session.factors?.user?.organizationId, }); @@ -256,7 +256,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) { @@ -311,12 +311,12 @@ export async function changePassword(command: { password: string; }) { const _headers = await headers(); - const { serviceUrl, serviceRegion } = getServiceUrlFromHeaders(_headers); + const { serviceUrl } = getServiceUrlFromHeaders(_headers); // check for init state const { user } = await getUserByID({ serviceUrl, - serviceRegion, + userId: command.userId, }); @@ -327,7 +327,7 @@ export async function changePassword(command: { return setUserPassword({ serviceUrl, - serviceRegion, + userId, password: command.password, user, @@ -345,13 +345,13 @@ export async function checkSessionAndSetPassword({ password, }: CheckSessionAndSetPasswordCommand) { const _headers = await headers(); - const { serviceUrl, serviceRegion } = getServiceUrlFromHeaders(_headers); + const { serviceUrl } = getServiceUrlFromHeaders(_headers); const sessionCookie = await getSessionCookieById({ sessionId }); const { session } = await getSession({ serviceUrl, - serviceRegion, + sessionId: sessionCookie.id, sessionToken: sessionCookie.token, }); @@ -370,7 +370,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, }); @@ -391,7 +391,7 @@ export async function checkSessionAndSetPassword({ const loginSettings = await getLoginSettings({ serviceUrl, - serviceRegion, + organization: session.factors.user.organizationId, }); @@ -401,16 +401,14 @@ 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, 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; - } - }, - ); + 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; + } + }); } else { const transport = async (serviceUrl: string, token: string) => { return createServerTransport(token, { diff --git a/apps/login/src/lib/server/register.ts b/apps/login/src/lib/server/register.ts index 2a23af3073b..bd3d2ffc49d 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, serviceRegion } = getServiceUrlFromHeaders(_headers); + const { serviceUrl } = getServiceUrlFromHeaders(_headers); const host = _headers.get("host"); if (!host || typeof host !== "string") { @@ -38,7 +38,7 @@ export async function registerUser(command: RegisterUserCommand) { const addResponse = await addHumanUser({ serviceUrl, - serviceRegion, + email: command.email, firstName: command.firstName, lastName: command.lastName, @@ -52,7 +52,7 @@ export async function registerUser(command: RegisterUserCommand) { const loginSettings = await getLoginSettings({ serviceUrl, - serviceRegion, + organization: command.organization, }); @@ -94,7 +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 7f71ec8f14d..a55b5609041 100644 --- a/apps/login/src/lib/server/session.ts +++ b/apps/login/src/lib/server/session.ts @@ -25,11 +25,11 @@ export async function continueWithSession({ ...session }: Session & { authRequestId?: string }) { const _headers = await headers(); - const { serviceUrl, serviceRegion } = getServiceUrlFromHeaders(_headers); + const { serviceUrl } = getServiceUrlFromHeaders(_headers); const loginSettings = await getLoginSettings({ serviceUrl, - serviceRegion, + organization: session.factors?.user?.organizationId, }); @@ -89,7 +89,7 @@ export async function updateSession(options: UpdateSessionCommand) { } const _headers = await headers(); - const { serviceUrl, serviceRegion } = getServiceUrlFromHeaders(_headers); + const { serviceUrl } = getServiceUrlFromHeaders(_headers); const host = _headers.get("host"); if (!host) { @@ -109,7 +109,7 @@ export async function updateSession(options: UpdateSessionCommand) { const loginSettings = await getLoginSettings({ serviceUrl, - serviceRegion, + organization, }); @@ -136,7 +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) { @@ -158,7 +158,7 @@ type ClearSessionOptions = { export async function clearSession(options: ClearSessionOptions) { const _headers = await headers(); - const { serviceUrl, serviceRegion } = getServiceUrlFromHeaders(_headers); + const { serviceUrl } = getServiceUrlFromHeaders(_headers); const { sessionId } = options; @@ -166,7 +166,7 @@ export async function clearSession(options: ClearSessionOptions) { const deletedSession = await deleteSession({ serviceUrl, - serviceRegion, + sessionId: session.id, sessionToken: session.token, }); @@ -182,13 +182,13 @@ type CleanupSessionCommand = { export async function cleanupSession({ sessionId }: CleanupSessionCommand) { const _headers = await headers(); - const { serviceUrl, serviceRegion } = getServiceUrlFromHeaders(_headers); + const { serviceUrl } = 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 60f1c12b66a..a011a16c114 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, serviceRegion } = getServiceUrlFromHeaders(_headers); + const { serviceUrl } = getServiceUrlFromHeaders(_headers); const host = _headers.get("host"); if (!host || typeof host !== "string") { @@ -38,7 +38,7 @@ export async function addU2F(command: RegisterU2FCommand) { const session = await getSession({ serviceUrl, - serviceRegion, + sessionId: sessionCookie.id, sessionToken: sessionCookie.token, }); @@ -55,12 +55,12 @@ export async function addU2F(command: RegisterU2FCommand) { return { error: "Could not get session" }; } - return registerU2F({ serviceUrl, serviceRegion, userId, domain: hostname }); + return registerU2F({ serviceUrl, userId, domain: hostname }); } export async function verifyU2F(command: VerifyU2FCommand) { const _headers = await headers(); - const { serviceUrl, serviceRegion } = getServiceUrlFromHeaders(_headers); + const { serviceUrl } = getServiceUrlFromHeaders(_headers); const host = _headers.get("host"); if (!host || typeof host !== "string") { @@ -83,7 +83,7 @@ export async function verifyU2F(command: VerifyU2FCommand) { const session = await getSession({ serviceUrl, - serviceRegion, + sessionId: sessionCookie.id, sessionToken: sessionCookie.token, }); @@ -101,5 +101,5 @@ export async function verifyU2F(command: VerifyU2FCommand) { userId, }); - return verifyU2FRegistration({ serviceUrl, serviceRegion, request }); + return verifyU2FRegistration({ serviceUrl, request }); } diff --git a/apps/login/src/lib/server/verify.ts b/apps/login/src/lib/server/verify.ts index 2ab94a92526..e727a8cb07c 100644 --- a/apps/login/src/lib/server/verify.ts +++ b/apps/login/src/lib/server/verify.ts @@ -30,11 +30,11 @@ export async function verifyTOTP( organization?: string, ) { const _headers = await headers(); - const { serviceUrl, serviceRegion } = getServiceUrlFromHeaders(_headers); + const { serviceUrl } = getServiceUrlFromHeaders(_headers); return loadMostRecentSession({ serviceUrl, - serviceRegion, + sessionParams: { loginName, organization, @@ -43,7 +43,7 @@ export async function verifyTOTP( if (session?.factors?.user?.id) { return verifyTOTPRegistration({ serviceUrl, - serviceRegion, + code, userId: session.factors.user.id, }); @@ -64,12 +64,12 @@ type VerifyUserByEmailCommand = { export async function sendVerification(command: VerifyUserByEmailCommand) { const _headers = await headers(); - const { serviceUrl, serviceRegion } = getServiceUrlFromHeaders(_headers); + const { serviceUrl } = getServiceUrlFromHeaders(_headers); const verifyResponse = command.isInvite ? await verifyInviteCode({ serviceUrl, - serviceRegion, + userId: command.userId, verificationCode: command.code, }).catch(() => { @@ -77,7 +77,7 @@ export async function sendVerification(command: VerifyUserByEmailCommand) { }) : await verifyEmail({ serviceUrl, - serviceRegion, + userId: command.userId, verificationCode: command.code, }).catch(() => { @@ -109,7 +109,7 @@ export async function sendVerification(command: VerifyUserByEmailCommand) { session = await getSession({ serviceUrl, - serviceRegion, + sessionId: sessionCookie.id, sessionToken: sessionCookie.token, }).then((response) => { @@ -124,7 +124,7 @@ export async function sendVerification(command: VerifyUserByEmailCommand) { const userResponse = await getUserByID({ serviceUrl, - serviceRegion, + userId: session?.factors?.user?.id, }); @@ -136,7 +136,7 @@ export async function sendVerification(command: VerifyUserByEmailCommand) { } else { const userResponse = await getUserByID({ serviceUrl, - serviceRegion, + userId: command.userId, }); @@ -176,13 +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, }); @@ -253,7 +253,7 @@ type resendVerifyEmailCommand = { export async function resendVerification(command: resendVerifyEmailCommand) { const _headers = await headers(); - const { serviceUrl, serviceRegion } = getServiceUrlFromHeaders(_headers); + const { serviceUrl } = getServiceUrlFromHeaders(_headers); const host = _headers.get("host"); if (!host) { @@ -261,11 +261,11 @@ export async function resendVerification(command: resendVerifyEmailCommand) { } return command.isInvite - ? resendInviteCode({ serviceUrl, serviceRegion, userId: command.userId }) + ? resendInviteCode({ serviceUrl, 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 @@ -276,7 +276,7 @@ export async function resendVerification(command: resendVerifyEmailCommand) { type sendEmailCommand = { serviceUrl: string; - serviceRegion: string; + userId: string; urlTemplate: string; }; @@ -284,7 +284,6 @@ type sendEmailCommand = { export async function sendEmailCode(command: sendEmailCommand) { return zitadelSendEmailCode({ serviceUrl: command.serviceUrl, - serviceRegion: command.serviceRegion, userId: command.userId, urlTemplate: command.urlTemplate, }); @@ -302,7 +301,7 @@ export async function sendVerificationRedirectWithoutCheck( command: SendVerificationRedirectWithoutCheckCommand, ) { const _headers = await headers(); - const { serviceUrl, serviceRegion } = getServiceUrlFromHeaders(_headers); + const { serviceUrl } = getServiceUrlFromHeaders(_headers); if (!("loginName" in command || "userId" in command)) { return { error: "No userId, nor loginname provided" }; @@ -325,7 +324,7 @@ export async function sendVerificationRedirectWithoutCheck( session = await getSession({ serviceUrl, - serviceRegion, + sessionId: sessionCookie.id, sessionToken: sessionCookie.token, }).then((response) => { @@ -340,7 +339,7 @@ export async function sendVerificationRedirectWithoutCheck( const userResponse = await getUserByID({ serviceUrl, - serviceRegion, + userId: session?.factors?.user?.id, }); @@ -352,7 +351,7 @@ export async function sendVerificationRedirectWithoutCheck( } else if ("userId" in command) { const userResponse = await getUserByID({ serviceUrl, - serviceRegion, + userId: command.userId, }); @@ -392,7 +391,7 @@ export async function sendVerificationRedirectWithoutCheck( const authMethodResponse = await listAuthenticationMethodTypes({ serviceUrl, - serviceRegion, + userId: user.userId, }); @@ -418,7 +417,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 fe62bc2c9c9..48a31c1ac6b 100644 --- a/apps/login/src/lib/service.ts +++ b/apps/login/src/lib/service.ts @@ -20,17 +20,16 @@ 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[serviceRegion + "_AUDIENCE"] && - process.env[serviceRegion + "_SYSTEM_USER_ID"] && - process.env[serviceRegion + "_SYSTEM_USER_PRIVATE_KEY"] + process.env.AUDIENCE && + process.env.SYSTEM_USER_ID && + process.env.SYSTEM_USER_PRIVATE_KEY ) { - token = await systemAPIToken({ serviceRegion }); + token = await systemAPIToken(); } else if (process.env.ZITADEL_SERVICE_USER_TOKEN) { token = process.env.ZITADEL_SERVICE_USER_TOKEN; } @@ -43,15 +42,33 @@ export async function createServiceForHost( throw new Error("No token found"); } + const instanceHost = new URL(serviceUrl).host; const transport = createServerTransport(token, { - baseUrl: serviceUrl, + baseUrl: process.env.ZITADEL_API_URL ?? serviceUrl, + interceptors: + (process.env.ZITADEL_API_URL && + process.env.ZITADEL_API_URL != serviceUrl) || + process.env.ZITADEL_INSTANCE_HOST_HEADER + ? [ + (next) => { + return (req) => { + req.header.set( + process.env.ZITADEL_INSTANCE_HOST_HEADER ?? + "x-zitadel-instance-host", + instanceHost, + ); + return next(req); + }; + }, + ] + : undefined, }); return createClientFor(service)(transport); } /** - * Extracts the service url and region from the headers if used in a multitenant context (x-zitadel-forward-host, x-zitade-region header) + * Extracts the service url and region from the headers if used in a multitenant context (host, x-zitadel-forward-host header) * or falls back to the ZITADEL_API_URL for a self hosting deployment * or falls back to the host header for a self hosting deployment using custom domains * @param headers @@ -61,7 +78,6 @@ export async function createServiceForHost( */ export function getServiceUrlFromHeaders(headers: ReadonlyHeaders): { serviceUrl: string; - serviceRegion: string; } { let instanceUrl; @@ -69,7 +85,7 @@ export function getServiceUrlFromHeaders(headers: ReadonlyHeaders): { // use the forwarded host if available (multitenant), otherwise fall back to the host of the deployment itself if (forwardedHost) { instanceUrl = forwardedHost; - instanceUrl = instanceUrl.startsWith("https://") + instanceUrl = instanceUrl.startsWith("http://") ? instanceUrl : `https://${instanceUrl}`; } else if (process.env.ZITADEL_API_URL) { @@ -80,7 +96,7 @@ export function getServiceUrlFromHeaders(headers: ReadonlyHeaders): { if (host) { const [hostname, port] = host.split(":"); if (hostname !== "localhost") { - instanceUrl = host.startsWith("https://") ? host : `https://${host}`; + instanceUrl = host.startsWith("http") ? host : `https://${host}`; } } } @@ -91,6 +107,5 @@ export function getServiceUrlFromHeaders(headers: ReadonlyHeaders): { 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 58fe1d20dfc..b734bf2b2ce 100644 --- a/apps/login/src/lib/session.ts +++ b/apps/login/src/lib/session.ts @@ -5,7 +5,7 @@ import { getSession } from "./zitadel"; type LoadMostRecentSessionParams = { serviceUrl: string; - serviceRegion: string; + sessionParams: { loginName?: string; organization?: string; @@ -14,7 +14,7 @@ type LoadMostRecentSessionParams = { export async function loadMostRecentSession({ serviceUrl, - serviceRegion, + sessionParams, }: LoadMostRecentSessionParams): Promise { const recent = await getMostRecentCookieWithLoginname({ @@ -24,7 +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 535f4fd4cb3..f4b062f5dd0 100644 --- a/apps/login/src/lib/zitadel.ts +++ b/apps/login/src/lib/zitadel.ts @@ -55,15 +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, serviceRegion); + await createServiceForHost(SettingsService, serviceUrl); const callback = settingsService .getBrandingSettings({ ctx: makeReqCtx(organization) }, {}) @@ -74,15 +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, serviceRegion); + await createServiceForHost(SettingsService, serviceUrl); const callback = settingsService .getLoginSettings({ ctx: makeReqCtx(organization) }, {}) @@ -93,15 +93,15 @@ export async function getLoginSettings({ export async function getLockoutSettings({ serviceUrl, - serviceRegion, + orgId, }: { serviceUrl: string; - serviceRegion: string; + orgId?: string; }) { const settingsService: Client = - await createServiceForHost(SettingsService, serviceUrl, serviceRegion); + await createServiceForHost(SettingsService, serviceUrl); const callback = settingsService .getLockoutSettings({ ctx: makeReqCtx(orgId) }, {}) @@ -112,15 +112,15 @@ export async function getLockoutSettings({ export async function getPasswordExpirySettings({ serviceUrl, - serviceRegion, + orgId, }: { serviceUrl: string; - serviceRegion: string; + orgId?: string; }) { const settingsService: Client = - await createServiceForHost(SettingsService, serviceUrl, serviceRegion); + await createServiceForHost(SettingsService, serviceUrl); const callback = settingsService .getPasswordExpirySettings({ ctx: makeReqCtx(orgId) }, {}) @@ -131,17 +131,16 @@ export async function getPasswordExpirySettings({ 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 }, {}); @@ -149,17 +148,16 @@ 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 }, {}); @@ -167,17 +165,16 @@ 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 }, {}); @@ -185,17 +182,16 @@ 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 }, {}); @@ -203,13 +199,11 @@ export async function registerTOTP({ export async function getGeneralSettings({ serviceUrl, - serviceRegion, }: { serviceUrl: string; - serviceRegion: string; }) { const settingsService: Client = - await createServiceForHost(SettingsService, serviceUrl, serviceRegion); + await createServiceForHost(SettingsService, serviceUrl); const callback = settingsService .getGeneralSettings({}, {}) @@ -220,15 +214,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, serviceRegion); + await createServiceForHost(SettingsService, serviceUrl); const callback = settingsService .getLegalAndSupportSettings({ ctx: makeReqCtx(organization) }, {}) @@ -239,15 +233,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, serviceRegion); + await createServiceForHost(SettingsService, serviceUrl); const callback = settingsService .getPasswordComplexitySettings({ ctx: makeReqCtx(organization) }) @@ -258,32 +252,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, serviceRegion); + await createServiceForHost(SessionService, serviceUrl); 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; @@ -292,7 +286,7 @@ export async function createSessionForUserIdAndIdpIntent({ lifetime?: Duration; }) { const sessionService: Client = - await createServiceForHost(SessionService, serviceUrl, serviceRegion); + await createServiceForHost(SessionService, serviceUrl); return sessionService.createSession({ checks: { @@ -310,7 +304,7 @@ export async function createSessionForUserIdAndIdpIntent({ export async function setSession({ serviceUrl, - serviceRegion, + sessionId, sessionToken, challenges, @@ -318,7 +312,7 @@ export async function setSession({ lifetime, }: { serviceUrl: string; - serviceRegion: string; + sessionId: string; sessionToken: string; challenges: RequestChallenges | undefined; @@ -326,7 +320,7 @@ export async function setSession({ lifetime?: Duration; }) { const sessionService: Client = - await createServiceForHost(SessionService, serviceUrl, serviceRegion); + await createServiceForHost(SessionService, serviceUrl); return sessionService.setSession( { @@ -343,51 +337,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, serviceRegion); + await createServiceForHost(SessionService, serviceUrl); 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, serviceRegion); + await createServiceForHost(SessionService, serviceUrl); return sessionService.deleteSession({ sessionId, sessionToken }, {}); } type ListSessionsCommand = { serviceUrl: string; - serviceRegion: string; + ids: string[]; }; export async function listSessions({ serviceUrl, - serviceRegion, + ids, }: ListSessionsCommand) { const sessionService: Client = - await createServiceForHost(SessionService, serviceUrl, serviceRegion); + await createServiceForHost(SessionService, serviceUrl); return sessionService.listSessions( { @@ -406,7 +400,7 @@ export async function listSessions({ export type AddHumanUserData = { serviceUrl: string; - serviceRegion: string; + firstName: string; lastName: string; email: string; @@ -416,7 +410,7 @@ export type AddHumanUserData = { export async function addHumanUser({ serviceUrl, - serviceRegion, + email, firstName, lastName, @@ -426,7 +420,6 @@ export async function addHumanUser({ const userService: Client = await createServiceForHost( UserService, serviceUrl, - serviceRegion, ); return userService.addHumanUser({ @@ -450,17 +443,16 @@ 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); @@ -468,19 +460,18 @@ 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 }, {}); @@ -488,17 +479,16 @@ 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 }, {}); @@ -506,19 +496,18 @@ 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 }, {}); @@ -526,17 +515,16 @@ 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 }, {}); @@ -544,12 +532,12 @@ export async function resendInviteCode({ export async function sendEmailCode({ serviceUrl, - serviceRegion, + userId, urlTemplate, }: { serviceUrl: string; - serviceRegion: string; + userId: string; urlTemplate: string; }) { @@ -568,7 +556,6 @@ export async function sendEmailCode({ const userService: Client = await createServiceForHost( UserService, serviceUrl, - serviceRegion, ); return userService.sendEmailCode(medium, {}); @@ -576,12 +563,12 @@ export async function sendEmailCode({ export async function createInviteCode({ serviceUrl, - serviceRegion, + urlTemplate, userId, }: { serviceUrl: string; - serviceRegion: string; + urlTemplate: string; userId: string; }) { @@ -597,7 +584,6 @@ export async function createInviteCode({ const userService: Client = await createServiceForHost( UserService, serviceUrl, - serviceRegion, ); return userService.createInviteCode( @@ -614,7 +600,7 @@ export async function createInviteCode({ export type ListUsersCommand = { serviceUrl: string; - serviceRegion: string; + loginName?: string; userName?: string; email?: string; @@ -624,7 +610,7 @@ export type ListUsersCommand = { export async function listUsers({ serviceUrl, - serviceRegion, + loginName, userName, phone, @@ -716,7 +702,6 @@ export async function listUsers({ const userService: Client = await createServiceForHost( UserService, serviceUrl, - serviceRegion, ); return userService.listUsers({ queries }); @@ -724,7 +709,7 @@ export async function listUsers({ export type SearchUsersCommand = { serviceUrl: string; - serviceRegion: string; + searchValue: string; loginSettings: LoginSettings; organizationId?: string; @@ -770,7 +755,7 @@ const EmailQuery = (searchValue: string) => * */ export async function searchUsers({ serviceUrl, - serviceRegion, + searchValue, loginSettings, organizationId, @@ -804,7 +789,6 @@ export async function searchUsers({ const userService: Client = await createServiceForHost( UserService, serviceUrl, - serviceRegion, ); const loginNameResult = await userService.listUsers({ queries }); @@ -891,13 +875,11 @@ export async function searchUsers({ export async function getDefaultOrg({ serviceUrl, - serviceRegion, }: { serviceUrl: string; - serviceRegion: string; }): Promise { const orgService: Client = - await createServiceForHost(OrganizationService, serviceUrl, serviceRegion); + await createServiceForHost(OrganizationService, serviceUrl); return orgService .listOrganizations( @@ -918,15 +900,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, serviceRegion); + await createServiceForHost(OrganizationService, serviceUrl); return orgService.listOrganizations( { @@ -945,19 +927,18 @@ 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({ @@ -971,19 +952,18 @@ 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({ @@ -994,18 +974,14 @@ export async function retrieveIdentityProviderInformation({ export async function getAuthRequest({ serviceUrl, - serviceRegion, + authRequestId, }: { serviceUrl: string; - serviceRegion: string; + authRequestId: string; }) { - const oidcService = await createServiceForHost( - OIDCService, - serviceUrl, - serviceRegion, - ); + const oidcService = await createServiceForHost(OIDCService, serviceUrl); return oidcService.getAuthRequest({ authRequestId, @@ -1014,37 +990,32 @@ export async function getAuthRequest({ export async function createCallback({ serviceUrl, - serviceRegion, + req, }: { serviceUrl: string; - serviceRegion: string; + req: CreateCallbackRequest; }) { - const oidcService = await createServiceForHost( - OIDCService, - serviceUrl, - serviceRegion, - ); + const oidcService = await createServiceForHost(OIDCService, serviceUrl); 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( @@ -1058,12 +1029,12 @@ export async function verifyEmail({ export async function resendEmailCode({ serviceUrl, - serviceRegion, + userId, urlTemplate, }: { serviceUrl: string; - serviceRegion: string; + userId: string; urlTemplate: string; }) { @@ -1080,7 +1051,6 @@ export async function resendEmailCode({ const userService: Client = await createServiceForHost( UserService, serviceUrl, - serviceRegion, ); return userService.resendEmailCode(request, {}); @@ -1088,19 +1058,18 @@ 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( @@ -1111,38 +1080,33 @@ export async function retrieveIDPIntent({ export async function getIDPByID({ serviceUrl, - serviceRegion, + id, }: { serviceUrl: string; - serviceRegion: string; + id: string; }) { const idpService: Client = - await createServiceForHost( - IdentityProviderService, - serviceUrl, - serviceRegion, - ); + await createServiceForHost(IdentityProviderService, serviceUrl); 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( @@ -1160,12 +1124,12 @@ export async function addIDPLink({ export async function passwordReset({ serviceUrl, - serviceRegion, + userId, urlTemplate, }: { serviceUrl: string; - serviceRegion: string; + userId: string; urlTemplate?: string; }) { @@ -1181,7 +1145,6 @@ export async function passwordReset({ const userService: Client = await createServiceForHost( UserService, serviceUrl, - serviceRegion, ); return userService.passwordReset( @@ -1198,14 +1161,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; @@ -1222,7 +1185,6 @@ export async function setUserPassword({ if (!code) { const authmethods = await listAuthenticationMethodTypes({ serviceUrl, - serviceRegion, userId, }); @@ -1248,7 +1210,6 @@ export async function setUserPassword({ const userService: Client = await createServiceForHost( UserService, serviceUrl, - serviceRegion, ); return userService.setPassword(payload, {}).catch((error) => { @@ -1263,17 +1224,16 @@ 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, {}); @@ -1287,17 +1247,16 @@ 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({ @@ -1318,19 +1277,18 @@ 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({ @@ -1347,17 +1305,16 @@ 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, {}); @@ -1372,12 +1329,12 @@ export async function verifyU2FRegistration({ */ export async function getActiveIdentityProviders({ serviceUrl, - serviceRegion, + orgId, linking_allowed, }: { serviceUrl: string; - serviceRegion: string; + orgId?: string; linking_allowed?: boolean; }) { @@ -1386,7 +1343,7 @@ export async function getActiveIdentityProviders({ props.linkingAllowed = linking_allowed; } const settingsService: Client = - await createServiceForHost(SettingsService, serviceUrl, serviceRegion); + await createServiceForHost(SettingsService, serviceUrl); return settingsService.getActiveIdentityProviders(props, {}); } @@ -1399,17 +1356,16 @@ 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, {}); @@ -1425,13 +1381,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; @@ -1439,7 +1395,6 @@ export async function registerPasskey({ const userService: Client = await createServiceForHost( UserService, serviceUrl, - serviceRegion, ); return userService.registerPasskey({ @@ -1457,17 +1412,15 @@ 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 8ffe8e58302..e8dda55a260 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, serviceRegion } = getServiceUrlFromHeaders(_headers); + const { serviceUrl } = getServiceUrlFromHeaders(_headers); const instanceHost = `${serviceUrl}`.replace("https://", ""); diff --git a/package.json b/package.json index 5bb10b39369..722cd9ede51 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,7 @@ "scripts": { "generate": "turbo run generate", "build": "turbo run build", + "build:docker": "rm -rf ./out ./docker && mkdir -p ./docker && turbo prune @zitadel/login --docker && cd ./docker && cp -r ../out/json/* . && pnpm install --frozen-lockfile && cp -r ../out/full/* . && turbo run build:standalone && cd ..", "build:packages": "turbo run build --filter=./packages/*", "build:apps": "turbo run build --filter=./apps/*", "test": "turbo run test", diff --git a/packages/zitadel-client/turbo.json b/packages/zitadel-client/turbo.json index ea363690138..2a042b53263 100644 --- a/packages/zitadel-client/turbo.json +++ b/packages/zitadel-client/turbo.json @@ -1,15 +1,13 @@ { - "extends": [ - "//" - ], + "extends": ["//"], "tasks": { "build": { - "outputs": [ - "dist/**" - ], - "dependsOn": [ - "@zitadel/proto#generate" - ] + "outputs": ["dist/**"], + "dependsOn": ["@zitadel/proto#generate"] + }, + "build:standalone": { + "outputs": ["dist/**"], + "dependsOn": ["@zitadel/proto#generate"] } } } diff --git a/turbo.json b/turbo.json index bf02da7ea08..61316b800e2 100644 --- a/turbo.json +++ b/turbo.json @@ -6,25 +6,21 @@ "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", "ZITADEL_API_URL", "ZITADEL_SERVICE_USER_ID", "ZITADEL_SERVICE_USER_TOKEN", - "NEXT_PUBLIC_BASE_PATH" + "NEXT_PUBLIC_BASE_PATH", + "ZITADEL_INSTANCE_HOST_HEADER" ], "tasks": { "generate": { "cache": true }, "build": {}, + "build:standalone": {}, "test": {}, "start": {}, "start:built": {},