From 3398b0ce3179d5b1025fef6e934ac7fa6607df4e Mon Sep 17 00:00:00 2001 From: Elio Bischof Date: Thu, 6 Feb 2025 10:36:15 +0100 Subject: [PATCH 01/48] chore: connect vercel env From 1527f0f070d767ec2590b83e80fa53a467096565 Mon Sep 17 00:00:00 2001 From: Elio Bischof Date: Thu, 6 Feb 2025 11:03:21 +0100 Subject: [PATCH 02/48] deploy From 6b1f826b0f7fbfe9d45b6c8b0a50694b6aff1192 Mon Sep 17 00:00:00 2001 From: Max Peintner Date: Thu, 6 Feb 2025 11:50:35 +0100 Subject: [PATCH 03/48] trigger From 4e71e20c76d4c88f7f2a86d905ca5478fcdb4c3e Mon Sep 17 00:00:00 2001 From: Max Peintner Date: Thu, 6 Feb 2025 12:03:10 +0100 Subject: [PATCH 04/48] fix remote patterns --- apps/login/next.config.mjs | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/apps/login/next.config.mjs b/apps/login/next.config.mjs index 32209b11e7a..a728bab6774 100755 --- a/apps/login/next.config.mjs +++ b/apps/login/next.config.mjs @@ -34,6 +34,24 @@ const secureHeaders = [ }, ]; +const imageRemotePatterns = [ + { + protocol: "http", + hostname: "localhost", + port: "8080", + 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, reactStrictMode: true, // Recommended for the `pages` directory, default in `app`. @@ -41,20 +59,7 @@ const nextConfig = { 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 [ From 15b5a2f08c84304bd3181f28c537336dbfbb51d1 Mon Sep 17 00:00:00 2001 From: Elio Bischof Date: Thu, 6 Feb 2025 12:51:26 +0100 Subject: [PATCH 05/48] deploy From 7774de4b6c49f20b2b78c8721448c289b2cd83f6 Mon Sep 17 00:00:00 2001 From: Elio Bischof Date: Thu, 6 Feb 2025 15:25:19 +0100 Subject: [PATCH 06/48] debug href --- apps/login/src/middleware.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/login/src/middleware.ts b/apps/login/src/middleware.ts index 8ffe8e58302..647f0f7d4be 100644 --- a/apps/login/src/middleware.ts +++ b/apps/login/src/middleware.ts @@ -44,7 +44,9 @@ export async function middleware(request: NextRequest) { responseHeaders.set("Access-Control-Allow-Origin", "*"); responseHeaders.set("Access-Control-Allow-Headers", "*"); - request.nextUrl.href = `${serviceUrl}${request.nextUrl.pathname}${request.nextUrl.search}`; + const href = `${serviceUrl}${request.nextUrl.pathname}${request.nextUrl.search}`; + console.log("changing request href", "old", request.nextUrl.href, "new", href) + request.nextUrl.href = href; return NextResponse.rewrite(request.nextUrl, { request: { headers: requestHeaders, From 8f4eab3334b0dc232b451c4f58af98dc35862889 Mon Sep 17 00:00:00 2001 From: Elio Bischof Date: Thu, 6 Feb 2025 15:57:45 +0100 Subject: [PATCH 07/48] try image remote pattern --- apps/login/next.config.mjs | 6 ++++++ apps/login/src/middleware.ts | 4 +--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/apps/login/next.config.mjs b/apps/login/next.config.mjs index a728bab6774..6f3efe0ef77 100755 --- a/apps/login/next.config.mjs +++ b/apps/login/next.config.mjs @@ -41,6 +41,12 @@ const imageRemotePatterns = [ port: "8080", pathname: "/**", }, + { + protocol: "https", + hostname: "eu1-znjkwx.eu1.orbos.app", + port: "", + pathname: "/**", + }, ]; if (process.env.ZITADEL_API_URL) { diff --git a/apps/login/src/middleware.ts b/apps/login/src/middleware.ts index 647f0f7d4be..8ffe8e58302 100644 --- a/apps/login/src/middleware.ts +++ b/apps/login/src/middleware.ts @@ -44,9 +44,7 @@ export async function middleware(request: NextRequest) { responseHeaders.set("Access-Control-Allow-Origin", "*"); responseHeaders.set("Access-Control-Allow-Headers", "*"); - const href = `${serviceUrl}${request.nextUrl.pathname}${request.nextUrl.search}`; - console.log("changing request href", "old", request.nextUrl.href, "new", href) - request.nextUrl.href = href; + request.nextUrl.href = `${serviceUrl}${request.nextUrl.pathname}${request.nextUrl.search}`; return NextResponse.rewrite(request.nextUrl, { request: { headers: requestHeaders, From 91a05bb14303d7552eede0231e5e74e1bcd994c6 Mon Sep 17 00:00:00 2001 From: Elio Bischof Date: Thu, 6 Feb 2025 16:59:42 +0100 Subject: [PATCH 08/48] cleanup --- apps/login/next.config.mjs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/apps/login/next.config.mjs b/apps/login/next.config.mjs index 6f3efe0ef77..a728bab6774 100755 --- a/apps/login/next.config.mjs +++ b/apps/login/next.config.mjs @@ -41,12 +41,6 @@ const imageRemotePatterns = [ port: "8080", pathname: "/**", }, - { - protocol: "https", - hostname: "eu1-znjkwx.eu1.orbos.app", - port: "", - pathname: "/**", - }, ]; if (process.env.ZITADEL_API_URL) { From 144068e3e74ca48a7934c92b7021320f94825648 Mon Sep 17 00:00:00 2001 From: Max Peintner Date: Fri, 7 Feb 2025 08:56:01 +0100 Subject: [PATCH 09/48] headers route --- apps/login/src/app/headers/route.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 apps/login/src/app/headers/route.ts diff --git a/apps/login/src/app/headers/route.ts b/apps/login/src/app/headers/route.ts new file mode 100644 index 00000000000..13a67f87f43 --- /dev/null +++ b/apps/login/src/app/headers/route.ts @@ -0,0 +1,13 @@ +import { NextRequest, NextResponse } from "next/server"; +export const dynamic = "force-dynamic"; +export const revalidate = false; +export const fetchCache = "default-no-store"; +export async function GET(request: NextRequest) { + const headers = request.headers; + // Convert headers to a plain object + const headersObject: Record = {}; + headers.forEach((value, key) => { + headersObject[key] = value; + }); + return NextResponse.json(headersObject); +} From 26cd39e4cd47098e7b29301ba0a5479e0886b5b7 Mon Sep 17 00:00:00 2001 From: Elio Bischof Date: Fri, 7 Feb 2025 09:30:53 +0100 Subject: [PATCH 10/48] deploy From 8461a0739d8c11607c08b4e898293829886f2817 Mon Sep 17 00:00:00 2001 From: Max Peintner Date: Fri, 7 Feb 2025 10:46:34 +0100 Subject: [PATCH 11/48] log --- apps/login/src/app/login/route.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/login/src/app/login/route.ts b/apps/login/src/app/login/route.ts index 8114807ac0b..83ea901d819 100644 --- a/apps/login/src/app/login/route.ts +++ b/apps/login/src/app/login/route.ts @@ -487,7 +487,11 @@ export async function GET(request: NextRequest) { } } - const loginNameUrl = new URL("/loginname", request.url); + const loginNameUrl = new URL("/loginname"); + console.log("loginNameUrl", loginNameUrl); + console.log("request.url", request.url); + console.log("nexturl", request.nextUrl); + if (authRequest.id) { loginNameUrl.searchParams.set("authRequestId", authRequest.id); } From 9a93c63ee93a730fb579fd16e3a70b7c2ca08c2b Mon Sep 17 00:00:00 2001 From: Max Peintner Date: Fri, 7 Feb 2025 10:49:48 +0100 Subject: [PATCH 12/48] log --- apps/login/src/app/login/route.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/login/src/app/login/route.ts b/apps/login/src/app/login/route.ts index 83ea901d819..16bbc861d53 100644 --- a/apps/login/src/app/login/route.ts +++ b/apps/login/src/app/login/route.ts @@ -205,7 +205,10 @@ export async function GET(request: NextRequest) { const authRequestId = searchParams.get("authRequest"); const sessionId = searchParams.get("sessionId"); - console.log("requesturl", request.url); + const loginNameUrl = new URL("/loginname"); + console.log("loginNameUrl", loginNameUrl); + console.log("request.url", request.url); + console.log("nexturl", request.nextUrl); const _headers = await headers(); const { serviceUrl, serviceRegion } = getServiceUrlFromHeaders(_headers); From b262fd831a41fb7e178cb95229f5a53d6b0e4216 Mon Sep 17 00:00:00 2001 From: Max Peintner Date: Fri, 7 Feb 2025 10:53:26 +0100 Subject: [PATCH 13/48] use nexturl --- apps/login/src/app/login/route.ts | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/apps/login/src/app/login/route.ts b/apps/login/src/app/login/route.ts index 16bbc861d53..50af4eaa904 100644 --- a/apps/login/src/app/login/route.ts +++ b/apps/login/src/app/login/route.ts @@ -205,8 +205,6 @@ export async function GET(request: NextRequest) { const authRequestId = searchParams.get("authRequest"); const sessionId = searchParams.get("sessionId"); - const loginNameUrl = new URL("/loginname"); - console.log("loginNameUrl", loginNameUrl); console.log("request.url", request.url); console.log("nexturl", request.nextUrl); @@ -256,7 +254,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()); } } @@ -311,7 +309,7 @@ export async function GET(request: NextRequest) { return NextResponse.redirect(loginSettings.defaultRedirectUri); } - const signedinUrl = new URL("/signedin", request.url); + const signedinUrl = new URL("/signedin", request.nextUrl); if (selectedSession.factors?.user?.loginName) { signedinUrl.searchParams.set( @@ -434,7 +432,7 @@ export async function GET(request: NextRequest) { } const gotoAccounts = (): NextResponse => { - const accountsUrl = new URL("/accounts", request.url); + const accountsUrl = new URL("/accounts", request.nextUrl); if (authRequest?.id) { accountsUrl.searchParams.set("authRequestId", authRequest?.id); } @@ -446,7 +444,7 @@ export async function GET(request: NextRequest) { }; if (authRequest && authRequest.prompt.includes(Prompt.CREATE)) { - const registerUrl = new URL("/register", request.url); + const registerUrl = new URL("/register", request.nextUrl); if (authRequest.id) { registerUrl.searchParams.set("authRequestId", authRequest.id); } @@ -482,7 +480,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) { @@ -490,7 +488,7 @@ export async function GET(request: NextRequest) { } } - const loginNameUrl = new URL("/loginname"); + const loginNameUrl = new URL("/loginname", request.nextUrl); console.log("loginNameUrl", loginNameUrl); console.log("request.url", request.url); console.log("nexturl", request.nextUrl); @@ -608,7 +606,7 @@ export async function GET(request: NextRequest) { } } } else { - const loginNameUrl = new URL("/loginname", request.url); + const loginNameUrl = new URL("/loginname", request.nextUrl); loginNameUrl.searchParams.set("authRequestId", authRequestId); if (authRequest?.loginHint) { From dd835cd8b19e87d99099e794c9aedc41a43bb6dc Mon Sep 17 00:00:00 2001 From: Max Peintner Date: Fri, 7 Feb 2025 10:58:25 +0100 Subject: [PATCH 14/48] construct url using basepath --- apps/login/src/app/login/route.ts | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/apps/login/src/app/login/route.ts b/apps/login/src/app/login/route.ts index 50af4eaa904..86597df0d63 100644 --- a/apps/login/src/app/login/route.ts +++ b/apps/login/src/app/login/route.ts @@ -200,6 +200,11 @@ async function findValidSession( return undefined; } +function constructUrl(request: NextRequest, path: string) { + const basePath = request.nextUrl.basePath || ""; + return new URL(`${basePath}${path}`, request.nextUrl.origin); +} + export async function GET(request: NextRequest) { const searchParams = request.nextUrl.searchParams; const authRequestId = searchParams.get("authRequest"); @@ -309,7 +314,7 @@ export async function GET(request: NextRequest) { return NextResponse.redirect(loginSettings.defaultRedirectUri); } - const signedinUrl = new URL("/signedin", request.nextUrl); + const signedinUrl = constructUrl(request, "/signedin"); if (selectedSession.factors?.user?.loginName) { signedinUrl.searchParams.set( @@ -432,7 +437,8 @@ export async function GET(request: NextRequest) { } const gotoAccounts = (): NextResponse => { - const accountsUrl = new URL("/accounts", request.nextUrl); + const accountsUrl = constructUrl(request, "/accounts"); + if (authRequest?.id) { accountsUrl.searchParams.set("authRequestId", authRequest?.id); } @@ -444,7 +450,7 @@ export async function GET(request: NextRequest) { }; if (authRequest && authRequest.prompt.includes(Prompt.CREATE)) { - const registerUrl = new URL("/register", request.nextUrl); + const registerUrl = constructUrl(request, "/register"); if (authRequest.id) { registerUrl.searchParams.set("authRequestId", authRequest.id); } @@ -488,7 +494,7 @@ export async function GET(request: NextRequest) { } } - const loginNameUrl = new URL("/loginname", request.nextUrl); + const loginNameUrl = constructUrl(request, "/loginname"); console.log("loginNameUrl", loginNameUrl); console.log("request.url", request.url); console.log("nexturl", request.nextUrl); @@ -606,7 +612,7 @@ export async function GET(request: NextRequest) { } } } else { - const loginNameUrl = new URL("/loginname", request.nextUrl); + const loginNameUrl = constructUrl(request, "/loginname"); loginNameUrl.searchParams.set("authRequestId", authRequestId); if (authRequest?.loginHint) { From c56e2de4fc65a05fa40ec8f95ab1daf330cf962f Mon Sep 17 00:00:00 2001 From: Max Peintner Date: Fri, 7 Feb 2025 11:03:12 +0100 Subject: [PATCH 15/48] yolo --- apps/login/src/app/login/route.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/login/src/app/login/route.ts b/apps/login/src/app/login/route.ts index 86597df0d63..900d9233c97 100644 --- a/apps/login/src/app/login/route.ts +++ b/apps/login/src/app/login/route.ts @@ -201,7 +201,7 @@ async function findValidSession( } function constructUrl(request: NextRequest, path: string) { - const basePath = request.nextUrl.basePath || ""; + const basePath = process.env.NEXT_PUBLIC_BASE_PATH || ""; return new URL(`${basePath}${path}`, request.nextUrl.origin); } From 0f551181b40fa3c77df0548da2aa4592a038837e Mon Sep 17 00:00:00 2001 From: Max Peintner Date: Fri, 7 Feb 2025 11:11:09 +0100 Subject: [PATCH 16/48] new url construction --- apps/login/src/app/login/route.ts | 70 ++++++++++++++++++++----------- 1 file changed, 46 insertions(+), 24 deletions(-) diff --git a/apps/login/src/app/login/route.ts b/apps/login/src/app/login/route.ts index 900d9233c97..de8d9a6b8f7 100644 --- a/apps/login/src/app/login/route.ts +++ b/apps/login/src/app/login/route.ts @@ -202,7 +202,7 @@ async function findValidSession( function constructUrl(request: NextRequest, path: string) { const basePath = process.env.NEXT_PUBLIC_BASE_PATH || ""; - return new URL(`${basePath}${path}`, request.nextUrl.origin); + return `${basePath}${path}`; } export async function GET(request: NextRequest) { @@ -315,20 +315,29 @@ export async function GET(request: NextRequest) { } 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 }); } @@ -438,27 +447,32 @@ export async function GET(request: NextRequest) { const gotoAccounts = (): NextResponse => { 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 = 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 @@ -495,23 +509,26 @@ export async function GET(request: NextRequest) { } const loginNameUrl = constructUrl(request, "/loginname"); - console.log("loginNameUrl", loginNameUrl); - console.log("request.url", request.url); - console.log("nexturl", request.nextUrl); + + 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. @@ -614,17 +631,22 @@ export async function GET(request: NextRequest) { } else { 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( From 5c90dec400fe95e5317fe607998e8cf265448a0a Mon Sep 17 00:00:00 2001 From: Max Peintner Date: Fri, 7 Feb 2025 11:24:10 +0100 Subject: [PATCH 17/48] use forwarded host for redirect --- apps/login/src/app/login/route.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/apps/login/src/app/login/route.ts b/apps/login/src/app/login/route.ts index de8d9a6b8f7..cdfa367942e 100644 --- a/apps/login/src/app/login/route.ts +++ b/apps/login/src/app/login/route.ts @@ -201,8 +201,14 @@ async function findValidSession( } function constructUrl(request: NextRequest, path: string) { + const forwardedHost = request.headers.get("x-zitadel-forward-host"); const basePath = process.env.NEXT_PUBLIC_BASE_PATH || ""; - return `${basePath}${path}`; + return new URL( + `${basePath}${path}`, + forwardedHost?.startsWith("https://") + ? forwardedHost + : `https://${forwardedHost}`, + ); } export async function GET(request: NextRequest) { From 79b2180df5df381b951d55da8d8d4626975fd103 Mon Sep 17 00:00:00 2001 From: Elio Bischof Date: Mon, 10 Feb 2025 15:42:23 +0100 Subject: [PATCH 18/48] docker image --- .dockerignore | 5 ++++ Dockerfile | 55 ++++++++++++++++++++++++++++++++++++++ apps/login/next.config.mjs | 1 + 3 files changed, 61 insertions(+) create mode 100644 .dockerignore create mode 100644 Dockerfile diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 00000000000..4f75c9513f5 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,5 @@ +node_modules +.git +.gitignore +*.md +dist diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000000..0609559966b --- /dev/null +++ b/Dockerfile @@ -0,0 +1,55 @@ +# Inspired by https://pnpm.io/docker#example-3-build-on-cicd +# Inspired by https://pnpm.io/docker#minimizing-docker-image-size-and-build-time + +FROM node:20-slim AS base + +ENV PNPM_HOME="/pnpm" +ENV PATH="$PNPM_HOME:$PATH" +RUN apt-get update +RUN apt-get install -y git +RUN npm install -g corepack +RUN corepack enable +RUN corepack prepare pnpm@latest --activate +RUN pnpm install turbo@^2 --global + +FROM base AS builder +# Set working directory +WORKDIR /app +# Replace with the major version installed in your repository. For example: +RUN pnpm install turbo@^2 --global +COPY . . + +# Generate a partial monorepo with a pruned lockfile for a target workspace. +# Assuming "web" is the name entered in the project's package.json: { name: "web" } +RUN turbo prune @zitadel/login --docker + +# Add lockfile and package.json's of isolated subworkspace +FROM base AS installer + +WORKDIR /app + +# First install the dependencies (as they change less often) +COPY --from=builder /app/out/json/ . +RUN pnpm install --frozen-lockfile + +# Build the project +COPY --from=builder /app/out/full/ . + +RUN turbo run build + +FROM base AS runner +WORKDIR /app + +# Don't run production as root +RUN addgroup --system --gid 1001 nodejs +RUN adduser --system --uid 1001 nextjs +USER nextjs + +# Automatically leverage output traces to reduce image size +# https://nextjs.org/docs/advanced-features/output-file-tracing +COPY --from=installer --chown=nextjs:nodejs /app/apps/login/.next/standalone ./ +COPY --from=installer --chown=nextjs:nodejs /app/apps/login/.next/static ./apps/login/.next/static +COPY --from=installer --chown=nextjs:nodejs /app/apps/login/public ./apps/login/public + +ENV HOSTNAME="0.0.0.0" +CMD node apps/login/server.js \ No newline at end of file diff --git a/apps/login/next.config.mjs b/apps/login/next.config.mjs index 32209b11e7a..12ca5f18981 100755 --- a/apps/login/next.config.mjs +++ b/apps/login/next.config.mjs @@ -36,6 +36,7 @@ const secureHeaders = [ const nextConfig = { basePath: process.env.NEXT_PUBLIC_BASE_PATH, + output: 'standalone', reactStrictMode: true, // Recommended for the `pages` directory, default in `app`. experimental: { dynamicIO: true, From 4eec1ecee886c1cbcc84ee0d8ea57a20470ee1bc Mon Sep 17 00:00:00 2001 From: Max Peintner Date: Mon, 10 Feb 2025 15:55:07 +0100 Subject: [PATCH 19/48] remove region --- apps/login/src/app/login/route.ts | 2 +- apps/login/src/lib/api.ts | 35 ++++++------------------------- apps/login/src/lib/service.ts | 14 ++++++------- 3 files changed, 14 insertions(+), 37 deletions(-) diff --git a/apps/login/src/app/login/route.ts b/apps/login/src/app/login/route.ts index cdfa367942e..57ea66cbf73 100644 --- a/apps/login/src/app/login/route.ts +++ b/apps/login/src/app/login/route.ts @@ -201,7 +201,7 @@ async function findValidSession( } function constructUrl(request: NextRequest, path: string) { - const forwardedHost = request.headers.get("x-zitadel-forward-host"); + const forwardedHost = request.headers.get("host"); const basePath = process.env.NEXT_PUBLIC_BASE_PATH || ""; return new URL( `${basePath}${path}`, 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/service.ts b/apps/login/src/lib/service.ts index fe62bc2c9c9..ab519185e40 100644 --- a/apps/login/src/lib/service.ts +++ b/apps/login/src/lib/service.ts @@ -20,17 +20,17 @@ type ServiceClass = export async function createServiceForHost( service: T, serviceUrl: string, - serviceRegion: 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; } @@ -51,7 +51,7 @@ export async function createServiceForHost( } /** - * 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-zitade-region 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 @@ -65,7 +65,7 @@ export function getServiceUrlFromHeaders(headers: ReadonlyHeaders): { } { let instanceUrl; - const forwardedHost = headers.get("x-zitadel-forward-host"); + const forwardedHost = headers.get("host"); // use the forwarded host if available (multitenant), otherwise fall back to the host of the deployment itself if (forwardedHost) { instanceUrl = forwardedHost; From 9a3d90238ec355395bb05031a26c13923e8a70b7 Mon Sep 17 00:00:00 2001 From: Max Peintner Date: Mon, 10 Feb 2025 16:12:44 +0100 Subject: [PATCH 20/48] log vars --- apps/login/src/lib/service.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/login/src/lib/service.ts b/apps/login/src/lib/service.ts index ab519185e40..41fdf85d7d8 100644 --- a/apps/login/src/lib/service.ts +++ b/apps/login/src/lib/service.ts @@ -40,6 +40,11 @@ export async function createServiceForHost( } if (!token) { + console.log( + process.env.AUDIENCE, + process.env.SYSTEM_USER_ID, + process.env.SYSTEM_USER_PRIVATE_KEY, + ); throw new Error("No token found"); } From 9851b6a72b2c6d78acafbd86b0ce57d72bf31f6b Mon Sep 17 00:00:00 2001 From: Max Peintner Date: Mon, 10 Feb 2025 16:13:23 +0100 Subject: [PATCH 21/48] log --- apps/login/src/lib/service.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/login/src/lib/service.ts b/apps/login/src/lib/service.ts index 41fdf85d7d8..c834e01cb1c 100644 --- a/apps/login/src/lib/service.ts +++ b/apps/login/src/lib/service.ts @@ -41,9 +41,10 @@ export async function createServiceForHost( if (!token) { console.log( - process.env.AUDIENCE, - process.env.SYSTEM_USER_ID, - process.env.SYSTEM_USER_PRIVATE_KEY, + `env vars: + ${process.env.AUDIENCE}, + ${process.env.SYSTEM_USER_ID}, + ${process.env.SYSTEM_USER_PRIVATE_KEY}`, ); throw new Error("No token found"); } From dcd73742f772b9f68f5ed13665f8fc89525adaf3 Mon Sep 17 00:00:00 2001 From: Max Peintner Date: Mon, 10 Feb 2025 17:34:16 +0100 Subject: [PATCH 22/48] api to 8080 of localhost --- apps/login/src/app/login/route.ts | 6 ++++-- apps/login/src/lib/service.ts | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/apps/login/src/app/login/route.ts b/apps/login/src/app/login/route.ts index 57ea66cbf73..fb1486efb25 100644 --- a/apps/login/src/app/login/route.ts +++ b/apps/login/src/app/login/route.ts @@ -201,11 +201,13 @@ async function findValidSession( } function constructUrl(request: NextRequest, path: string) { - const forwardedHost = request.headers.get("host"); + // TODO: remove localhost + const forwardedHost = + request.headers.get("x-zitadel-forward-host") ?? "http://localhost:8080"; const basePath = process.env.NEXT_PUBLIC_BASE_PATH || ""; return new URL( `${basePath}${path}`, - forwardedHost?.startsWith("https://") + forwardedHost?.startsWith("http") ? forwardedHost : `https://${forwardedHost}`, ); diff --git a/apps/login/src/lib/service.ts b/apps/login/src/lib/service.ts index c834e01cb1c..398d6574095 100644 --- a/apps/login/src/lib/service.ts +++ b/apps/login/src/lib/service.ts @@ -81,12 +81,14 @@ export function getServiceUrlFromHeaders(headers: ReadonlyHeaders): { } else if (process.env.ZITADEL_API_URL) { instanceUrl = process.env.ZITADEL_API_URL; } else { - const host = headers.get("host"); + // TODO: remove this fallback once the host header is always set + const host = + headers.get("x-zitadel-forward-host") ?? "http://localhost:8080"; if (host) { const [hostname, port] = host.split(":"); if (hostname !== "localhost") { - instanceUrl = host.startsWith("https://") ? host : `https://${host}`; + instanceUrl = host.startsWith("http") ? host : `https://${host}`; } } } From 0779f0b8074eb4dc3dedf1f27dba5407ba2b86fd Mon Sep 17 00:00:00 2001 From: Max Peintner Date: Mon, 10 Feb 2025 17:38:41 +0100 Subject: [PATCH 23/48] log service --- apps/login/src/lib/service.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/login/src/lib/service.ts b/apps/login/src/lib/service.ts index 398d6574095..43b72bfb98a 100644 --- a/apps/login/src/lib/service.ts +++ b/apps/login/src/lib/service.ts @@ -97,6 +97,8 @@ export function getServiceUrlFromHeaders(headers: ReadonlyHeaders): { throw new Error("Service URL could not be determined"); } + console.log("Service URL", instanceUrl); + return { serviceUrl: instanceUrl, serviceRegion: headers.get("x-zitadel-region") || "", From cc356d868e16aada514bf793b2609a26e7a2823a Mon Sep 17 00:00:00 2001 From: Max Peintner Date: Mon, 10 Feb 2025 17:45:53 +0100 Subject: [PATCH 24/48] check for forward-host again --- apps/login/src/lib/service.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/login/src/lib/service.ts b/apps/login/src/lib/service.ts index 43b72bfb98a..a71ecaa3ab6 100644 --- a/apps/login/src/lib/service.ts +++ b/apps/login/src/lib/service.ts @@ -71,7 +71,7 @@ export function getServiceUrlFromHeaders(headers: ReadonlyHeaders): { } { let instanceUrl; - const forwardedHost = headers.get("host"); + const forwardedHost = headers.get("x-zitadel-forward-host"); // use the forwarded host if available (multitenant), otherwise fall back to the host of the deployment itself if (forwardedHost) { instanceUrl = forwardedHost; From 78a6c1765d8e16d9a38ce9044902d949e8fb75e6 Mon Sep 17 00:00:00 2001 From: Max Peintner Date: Mon, 10 Feb 2025 17:55:00 +0100 Subject: [PATCH 25/48] fix condition --- apps/login/src/lib/service.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/login/src/lib/service.ts b/apps/login/src/lib/service.ts index a71ecaa3ab6..81c95bdbb7a 100644 --- a/apps/login/src/lib/service.ts +++ b/apps/login/src/lib/service.ts @@ -75,7 +75,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) { From cc2f603a67b0b389f137e211b766b0e9183f564c Mon Sep 17 00:00:00 2001 From: Elio Bischof Date: Tue, 11 Feb 2025 17:48:11 +0100 Subject: [PATCH 26/48] docker --- .dockerignore | 7 +--- .github/workflows/docker.yml | 75 +++++++++++++++++++++++++++++++++++ .gitignore | 2 + Dockerfile | 46 ++------------------- apps/login/src/lib/service.ts | 3 +- package.json | 1 + 6 files changed, 85 insertions(+), 49 deletions(-) create mode 100644 .github/workflows/docker.yml diff --git a/.dockerignore b/.dockerignore index 4f75c9513f5..f9db036d2ba 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,5 +1,2 @@ -node_modules -.git -.gitignore -*.md -dist +* +!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..cd23e6c9b77 --- /dev/null +++ b/.github/workflows/docker.yml @@ -0,0 +1,75 @@ +name: Docker + +on: + push: + branches: + - main + - dev + +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 + with: + version: 10 + + - 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: 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 index 0609559966b..c883c37878e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,43 +1,5 @@ -# Inspired by https://pnpm.io/docker#example-3-build-on-cicd -# Inspired by https://pnpm.io/docker#minimizing-docker-image-size-and-build-time +FROM node:20-slim -FROM node:20-slim AS base - -ENV PNPM_HOME="/pnpm" -ENV PATH="$PNPM_HOME:$PATH" -RUN apt-get update -RUN apt-get install -y git -RUN npm install -g corepack -RUN corepack enable -RUN corepack prepare pnpm@latest --activate -RUN pnpm install turbo@^2 --global - -FROM base AS builder -# Set working directory -WORKDIR /app -# Replace with the major version installed in your repository. For example: -RUN pnpm install turbo@^2 --global -COPY . . - -# Generate a partial monorepo with a pruned lockfile for a target workspace. -# Assuming "web" is the name entered in the project's package.json: { name: "web" } -RUN turbo prune @zitadel/login --docker - -# Add lockfile and package.json's of isolated subworkspace -FROM base AS installer - -WORKDIR /app - -# First install the dependencies (as they change less often) -COPY --from=builder /app/out/json/ . -RUN pnpm install --frozen-lockfile - -# Build the project -COPY --from=builder /app/out/full/ . - -RUN turbo run build - -FROM base AS runner WORKDIR /app # Don't run production as root @@ -47,9 +9,9 @@ USER nextjs # Automatically leverage output traces to reduce image size # https://nextjs.org/docs/advanced-features/output-file-tracing -COPY --from=installer --chown=nextjs:nodejs /app/apps/login/.next/standalone ./ -COPY --from=installer --chown=nextjs:nodejs /app/apps/login/.next/static ./apps/login/.next/static -COPY --from=installer --chown=nextjs:nodejs /app/apps/login/public ./apps/login/public +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 ENV HOSTNAME="0.0.0.0" CMD node apps/login/server.js \ No newline at end of file diff --git a/apps/login/src/lib/service.ts b/apps/login/src/lib/service.ts index 81c95bdbb7a..a3d505d953c 100644 --- a/apps/login/src/lib/service.ts +++ b/apps/login/src/lib/service.ts @@ -81,9 +81,8 @@ export function getServiceUrlFromHeaders(headers: ReadonlyHeaders): { } else if (process.env.ZITADEL_API_URL) { instanceUrl = process.env.ZITADEL_API_URL; } else { - // TODO: remove this fallback once the host header is always set const host = - headers.get("x-zitadel-forward-host") ?? "http://localhost:8080"; + headers.get("x-zitadel-forward-host") ?? headers.get("host"); if (host) { const [hostname, port] = host.split(":"); diff --git a/package.json b/package.json index 560bf823325..24e447658f0 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 && cd ..", "build:packages": "turbo run build --filter=./packages/*", "build:apps": "turbo run build --filter=./apps/*", "test": "turbo run test", From 269b7df90f241ef2110edc3161d1cd8527bef1f6 Mon Sep 17 00:00:00 2001 From: Elio Bischof Date: Tue, 11 Feb 2025 17:49:38 +0100 Subject: [PATCH 27/48] use repo pnpm version --- .github/workflows/docker.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index cd23e6c9b77..41b8e7fdaf1 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -17,8 +17,6 @@ jobs: - name: Install pnpm uses: pnpm/action-setup@v4 - with: - version: 10 - name: Cache turbo build setup uses: actions/cache@v4 From c74e825495602c039ab2d5aab945d4e256d685d8 Mon Sep 17 00:00:00 2001 From: Elio Bischof Date: Tue, 11 Feb 2025 19:01:24 +0100 Subject: [PATCH 28/48] try symlink --- .github/workflows/docker.yml | 2 +- Dockerfile | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 41b8e7fdaf1..7e6e2b9d126 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -59,7 +59,7 @@ jobs: run: pnpm install - name: Build for Docker - run: pnpm build:docker + run: NEXT_PUBLIC_BASE_PATH=/ui/new-login pnpm build:docker - name: Build and Push Image id: build diff --git a/Dockerfile b/Dockerfile index c883c37878e..5982a224f2f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,14 +1,15 @@ -FROM node:20-slim +FROM node:20-alpine WORKDIR /app -# Don't run production as root RUN addgroup --system --gid 1001 nodejs RUN adduser --system --uid 1001 nextjs + +RUN mkdir /cfg +RUN ln -s .env /cfg/.env + USER nextjs -# Automatically leverage output traces to reduce image size -# https://nextjs.org/docs/advanced-features/output-file-tracing 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 From 533e8a2360b45e1a42bf801f7b7000849c80ca30 Mon Sep 17 00:00:00 2001 From: Elio Bischof Date: Tue, 11 Feb 2025 21:14:43 +0100 Subject: [PATCH 29/48] allow .env in different folder --- Dockerfile | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Dockerfile b/Dockerfile index 5982a224f2f..65f3326053e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,14 +5,14 @@ WORKDIR /app RUN addgroup --system --gid 1001 nodejs RUN adduser --system --uid 1001 nextjs -RUN mkdir /cfg -RUN ln -s .env /cfg/.env - -USER 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 node apps/login/server.js \ No newline at end of file + +CMD ["/bin/sh", "-c", " set -o allexport && . /.env-file/.env && set +o allexport && node apps/login/server.js"] From b91785b09e4d631969cff6dbfd89a3740d72e1b6 Mon Sep 17 00:00:00 2001 From: Max Peintner Date: Wed, 12 Feb 2025 13:35:04 +0100 Subject: [PATCH 30/48] remove region context --- apps/login/next.config.mjs | 2 +- apps/login/src/app/(login)/accounts/page.tsx | 17 +- .../app/(login)/authenticator/set/page.tsx | 22 +- .../(login)/idp/[provider]/failure/page.tsx | 10 +- .../(login)/idp/[provider]/success/page.tsx | 32 +-- apps/login/src/app/(login)/idp/page.tsx | 6 +- apps/login/src/app/(login)/invite/page.tsx | 10 +- .../src/app/(login)/invite/success/page.tsx | 8 +- apps/login/src/app/(login)/loginname/page.tsx | 11 +- apps/login/src/app/(login)/mfa/page.tsx | 12 +- apps/login/src/app/(login)/mfa/set/page.tsx | 14 +- .../src/app/(login)/otp/[method]/page.tsx | 10 +- .../src/app/(login)/otp/[method]/set/page.tsx | 14 +- apps/login/src/app/(login)/passkey/page.tsx | 8 +- .../src/app/(login)/passkey/set/page.tsx | 6 +- .../src/app/(login)/password/change/page.tsx | 10 +- apps/login/src/app/(login)/password/page.tsx | 9 +- .../src/app/(login)/password/set/page.tsx | 12 +- apps/login/src/app/(login)/register/page.tsx | 11 +- .../app/(login)/register/password/page.tsx | 11 +- apps/login/src/app/(login)/signedin/page.tsx | 14 +- apps/login/src/app/(login)/u2f/page.tsx | 8 +- apps/login/src/app/(login)/u2f/set/page.tsx | 6 +- apps/login/src/app/(login)/verify/page.tsx | 12 +- apps/login/src/app/login/route.ts | 40 ++- apps/login/src/lib/self.ts | 4 +- apps/login/src/lib/server/cookie.ts | 18 +- apps/login/src/lib/server/idp.ts | 10 +- apps/login/src/lib/server/invite.ts | 6 +- apps/login/src/lib/server/loginname.ts | 28 +- apps/login/src/lib/server/otp.ts | 4 +- apps/login/src/lib/server/passkeys.ts | 20 +- apps/login/src/lib/server/password.ts | 56 ++-- apps/login/src/lib/server/register.ts | 8 +- apps/login/src/lib/server/session.ts | 18 +- apps/login/src/lib/server/u2f.ts | 12 +- apps/login/src/lib/server/verify.ts | 43 ++- apps/login/src/lib/service.ts | 5 +- apps/login/src/lib/session.ts | 6 +- apps/login/src/lib/zitadel.ts | 267 ++++++++---------- apps/login/src/middleware.ts | 2 +- 41 files changed, 377 insertions(+), 445 deletions(-) diff --git a/apps/login/next.config.mjs b/apps/login/next.config.mjs index da22ee5e147..fd83c4672b6 100755 --- a/apps/login/next.config.mjs +++ b/apps/login/next.config.mjs @@ -54,7 +54,7 @@ if (process.env.ZITADEL_API_URL) { const nextConfig = { basePath: process.env.NEXT_PUBLIC_BASE_PATH, - output: 'standalone', + output: "standalone", reactStrictMode: true, // Recommended for the `pages` directory, default in `app`. experimental: { dynamicIO: true, 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 fb1486efb25..d186f1b92b9 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; } } @@ -222,7 +220,7 @@ export async function GET(request: NextRequest) { console.log("nexturl", request.nextUrl); 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"); @@ -234,7 +232,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) { @@ -249,7 +247,7 @@ export async function GET(request: NextRequest) { const isValid = await isSessionValid( serviceUrl, - serviceRegion, + selectedSession, ); @@ -286,7 +284,7 @@ export async function GET(request: NextRequest) { try { const { callbackUrl } = await createCallback({ serviceUrl, - serviceRegion, + req: create(CreateCallbackRequestSchema, { authRequestId, callbackKind: { @@ -314,7 +312,7 @@ export async function GET(request: NextRequest) { ) { const loginSettings = await getLoginSettings({ serviceUrl, - serviceRegion, + organization: selectedSession.factors?.user?.organizationId, }); @@ -357,7 +355,7 @@ export async function GET(request: NextRequest) { if (authRequestId) { const { authRequest } = await getAuthRequest({ serviceUrl, - serviceRegion, + authRequestId, }); @@ -388,7 +386,7 @@ export async function GET(request: NextRequest) { if (orgDomain) { const orgs = await getOrgsByDomain({ serviceUrl, - serviceRegion, + domain: orgDomain, }); if (orgs.result && orgs.result.length === 1) { @@ -405,7 +403,7 @@ export async function GET(request: NextRequest) { const identityProviders = await getActiveIdentityProviders({ serviceUrl, - serviceRegion, + orgId: organization ? organization : undefined, }).then((resp) => { return resp.identityProviders; @@ -431,7 +429,7 @@ export async function GET(request: NextRequest) { return startIdentityProviderFlow({ serviceUrl, - serviceRegion, + idpId, urls: { successUrl: @@ -545,7 +543,7 @@ export async function GET(request: NextRequest) { **/ const selectedSession = await findValidSession( serviceUrl, - serviceRegion, + sessions, authRequest, ); @@ -575,7 +573,7 @@ export async function GET(request: NextRequest) { const { callbackUrl } = await createCallback({ serviceUrl, - serviceRegion, + req: create(CreateCallbackRequestSchema, { authRequestId, callbackKind: { @@ -589,7 +587,7 @@ export async function GET(request: NextRequest) { // check for loginHint, userId hint and valid sessions let selectedSession = await findValidSession( serviceUrl, - serviceRegion, + sessions, authRequest, ); @@ -614,7 +612,7 @@ export async function GET(request: NextRequest) { try { const { callbackUrl } = await createCallback({ serviceUrl, - serviceRegion, + req: create(CreateCallbackRequestSchema, { authRequestId, callbackKind: { diff --git a/apps/login/src/lib/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 a3d505d953c..471cbe35573 100644 --- a/apps/login/src/lib/service.ts +++ b/apps/login/src/lib/service.ts @@ -67,7 +67,6 @@ export async function createServiceForHost( */ export function getServiceUrlFromHeaders(headers: ReadonlyHeaders): { serviceUrl: string; - serviceRegion: string; } { let instanceUrl; @@ -81,8 +80,7 @@ export function getServiceUrlFromHeaders(headers: ReadonlyHeaders): { } else if (process.env.ZITADEL_API_URL) { instanceUrl = process.env.ZITADEL_API_URL; } else { - const host = - headers.get("x-zitadel-forward-host") ?? headers.get("host"); + const host = headers.get("x-zitadel-forward-host") ?? headers.get("host"); if (host) { const [hostname, port] = host.split(":"); @@ -100,6 +98,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://", ""); From 6c56efeea7402d322719f737e924e7b52e1b8791 Mon Sep 17 00:00:00 2001 From: Max Peintner Date: Wed, 12 Feb 2025 13:51:43 +0100 Subject: [PATCH 31/48] build:standalone for docker --- apps/login/next.config.mjs | 2 +- apps/login/package.json | 1 + package.json | 2 +- packages/zitadel-client/turbo.json | 16 +++++++--------- turbo.json | 1 + 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/apps/login/next.config.mjs b/apps/login/next.config.mjs index fd83c4672b6..0c969b9977b 100755 --- a/apps/login/next.config.mjs +++ b/apps/login/next.config.mjs @@ -54,7 +54,7 @@ if (process.env.ZITADEL_API_URL) { const nextConfig = { basePath: process.env.NEXT_PUBLIC_BASE_PATH, - output: "standalone", + output: process.env.NEXT_OUTPUT_MODE || undefined, reactStrictMode: true, // Recommended for the `pages` directory, default in `app`. experimental: { dynamicIO: true, diff --git a/apps/login/package.json b/apps/login/package.json index 6b71bca77d7..5f5934ad9be 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/package.json b/package.json index 24e447658f0..5c48b04ce70 100644 --- a/package.json +++ b/package.json @@ -5,7 +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 && cd ..", + "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..c4664ae4851 100644 --- a/turbo.json +++ b/turbo.json @@ -25,6 +25,7 @@ "cache": true }, "build": {}, + "build:standalone": {}, "test": {}, "start": {}, "start:built": {}, From 0e52f989e9ea8577f2d383b6cd60c7c1d6a8aae7 Mon Sep 17 00:00:00 2001 From: Elio Bischof Date: Wed, 12 Feb 2025 18:14:01 +0100 Subject: [PATCH 32/48] fall back to host --- apps/login/src/app/login/route.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/login/src/app/login/route.ts b/apps/login/src/app/login/route.ts index fb1486efb25..a302dd76108 100644 --- a/apps/login/src/app/login/route.ts +++ b/apps/login/src/app/login/route.ts @@ -201,9 +201,8 @@ async function findValidSession( } function constructUrl(request: NextRequest, path: string) { - // TODO: remove localhost const forwardedHost = - request.headers.get("x-zitadel-forward-host") ?? "http://localhost:8080"; + request.headers.get("x-zitadel-forward-host") ?? request.headers.get("host"); const basePath = process.env.NEXT_PUBLIC_BASE_PATH || ""; return new URL( `${basePath}${path}`, From 3696978824a3257d502cfd4b274bad276953ea48 Mon Sep 17 00:00:00 2001 From: Max Peintner Date: Thu, 13 Feb 2025 10:31:21 +0100 Subject: [PATCH 33/48] lint --- apps/login/src/app/login/route.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/login/src/app/login/route.ts b/apps/login/src/app/login/route.ts index 8ce818b20ec..982ecde7ce7 100644 --- a/apps/login/src/app/login/route.ts +++ b/apps/login/src/app/login/route.ts @@ -200,7 +200,8 @@ async function findValidSession( function constructUrl(request: NextRequest, path: string) { const forwardedHost = - request.headers.get("x-zitadel-forward-host") ?? request.headers.get("host"); + request.headers.get("x-zitadel-forward-host") ?? + request.headers.get("host"); const basePath = process.env.NEXT_PUBLIC_BASE_PATH || ""; return new URL( `${basePath}${path}`, From 72f1b7cca4da2e42c0835ba3c07ed9ac1ae63bae Mon Sep 17 00:00:00 2001 From: Max Peintner Date: Thu, 13 Feb 2025 10:33:01 +0100 Subject: [PATCH 34/48] cleanup --- apps/login/src/lib/service.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/apps/login/src/lib/service.ts b/apps/login/src/lib/service.ts index 471cbe35573..2df01e5829b 100644 --- a/apps/login/src/lib/service.ts +++ b/apps/login/src/lib/service.ts @@ -80,7 +80,7 @@ export function getServiceUrlFromHeaders(headers: ReadonlyHeaders): { } else if (process.env.ZITADEL_API_URL) { instanceUrl = process.env.ZITADEL_API_URL; } else { - const host = headers.get("x-zitadel-forward-host") ?? headers.get("host"); + const host = headers.get("host"); if (host) { const [hostname, port] = host.split(":"); @@ -94,8 +94,6 @@ export function getServiceUrlFromHeaders(headers: ReadonlyHeaders): { throw new Error("Service URL could not be determined"); } - console.log("Service URL", instanceUrl); - return { serviceUrl: instanceUrl, }; From 20c170bbd5415a249b02e3ab2174be3203646407 Mon Sep 17 00:00:00 2001 From: Elio Bischof Date: Thu, 13 Feb 2025 21:47:56 +0100 Subject: [PATCH 35/48] enable static api url --- apps/login/next-env-vars.d.ts | 10 +++++++++- apps/login/src/lib/service.ts | 9 ++++++++- turbo.json | 9 ++------- 3 files changed, 19 insertions(+), 9 deletions(-) diff --git a/apps/login/next-env-vars.d.ts b/apps/login/next-env-vars.d.ts index 35fcb109197..6ee63855bdf 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/src/lib/service.ts b/apps/login/src/lib/service.ts index 2df01e5829b..6e4fe24ae95 100644 --- a/apps/login/src/lib/service.ts +++ b/apps/login/src/lib/service.ts @@ -49,8 +49,15 @@ 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); diff --git a/turbo.json b/turbo.json index c4664ae4851..61316b800e2 100644 --- a/turbo.json +++ b/turbo.json @@ -6,19 +6,14 @@ "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": { From beffae47af0ae7add1cf570539be91618e096c3e Mon Sep 17 00:00:00 2001 From: Elio Bischof Date: Fri, 14 Feb 2025 07:25:40 +0100 Subject: [PATCH 36/48] Revert "enable static api url" This reverts commit 20c170bbd5415a249b02e3ab2174be3203646407. --- apps/login/next-env-vars.d.ts | 10 +--------- apps/login/src/lib/service.ts | 9 +-------- turbo.json | 9 +++++++-- 3 files changed, 9 insertions(+), 19 deletions(-) diff --git a/apps/login/next-env-vars.d.ts b/apps/login/next-env-vars.d.ts index 6ee63855bdf..35fcb109197 100644 --- a/apps/login/next-env-vars.d.ts +++ b/apps/login/next-env-vars.d.ts @@ -10,18 +10,10 @@ declare namespace NodeJS { SYSTEM_USER_PRIVATE_KEY: string; // The fallback service user private key /** - * Self hosting: The Zitadel API url + * Self hosting: The instance 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/src/lib/service.ts b/apps/login/src/lib/service.ts index 6e4fe24ae95..2df01e5829b 100644 --- a/apps/login/src/lib/service.ts +++ b/apps/login/src/lib/service.ts @@ -49,15 +49,8 @@ export async function createServiceForHost( throw new Error("No token found"); } - const instanceHost = new URL(serviceUrl).host const transport = createServerTransport(token, { - 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 + baseUrl: serviceUrl, }); return createClientFor(service)(transport); diff --git a/turbo.json b/turbo.json index 61316b800e2..c4664ae4851 100644 --- a/turbo.json +++ b/turbo.json @@ -6,14 +6,19 @@ "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", - "ZITADEL_INSTANCE_HOST_HEADER" + "NEXT_PUBLIC_BASE_PATH" ], "tasks": { "generate": { From c2ad1712aef966b89659ccfa659eaebe4af20254 Mon Sep 17 00:00:00 2001 From: Elio Bischof Date: Fri, 14 Feb 2025 07:26:55 +0100 Subject: [PATCH 37/48] cleanup regional env vars --- turbo.json | 6 ------ 1 file changed, 6 deletions(-) diff --git a/turbo.json b/turbo.json index c4664ae4851..279e45867b1 100644 --- a/turbo.json +++ b/turbo.json @@ -6,12 +6,6 @@ "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", From 870736fe9e36def27d10136a3b8a56c429800803 Mon Sep 17 00:00:00 2001 From: Max Peintner Date: Fri, 14 Feb 2025 08:21:37 +0100 Subject: [PATCH 38/48] Update apps/login/src/lib/service.ts Co-authored-by: Elio Bischof --- apps/login/src/lib/service.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/login/src/lib/service.ts b/apps/login/src/lib/service.ts index 2df01e5829b..6fded4f9b61 100644 --- a/apps/login/src/lib/service.ts +++ b/apps/login/src/lib/service.ts @@ -57,7 +57,7 @@ export async function createServiceForHost( } /** - * Extracts the service url and region from the headers if used in a multitenant context (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 From c5884b2d8d6a4e15825a92746d9554153bca0152 Mon Sep 17 00:00:00 2001 From: Max Peintner Date: Fri, 14 Feb 2025 08:21:44 +0100 Subject: [PATCH 39/48] Update apps/login/src/lib/service.ts Co-authored-by: Elio Bischof --- apps/login/src/lib/service.ts | 6 ------ 1 file changed, 6 deletions(-) diff --git a/apps/login/src/lib/service.ts b/apps/login/src/lib/service.ts index 6fded4f9b61..25ce0bae146 100644 --- a/apps/login/src/lib/service.ts +++ b/apps/login/src/lib/service.ts @@ -40,12 +40,6 @@ export async function createServiceForHost( } if (!token) { - console.log( - `env vars: - ${process.env.AUDIENCE}, - ${process.env.SYSTEM_USER_ID}, - ${process.env.SYSTEM_USER_PRIVATE_KEY}`, - ); throw new Error("No token found"); } From 601b441a8e6e8c73d031134bd6acf1a0084c3ca5 Mon Sep 17 00:00:00 2001 From: Max Peintner Date: Fri, 14 Feb 2025 08:21:51 +0100 Subject: [PATCH 40/48] Update apps/login/src/lib/service.ts Co-authored-by: Elio Bischof --- apps/login/src/lib/service.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/login/src/lib/service.ts b/apps/login/src/lib/service.ts index 25ce0bae146..5ea9eec882a 100644 --- a/apps/login/src/lib/service.ts +++ b/apps/login/src/lib/service.ts @@ -20,7 +20,6 @@ type ServiceClass = export async function createServiceForHost( service: T, serviceUrl: string, - serviceRegion?: string, ) { let token; From 9050d9bf50a765925f5e00b9a5a3db1f03a61e67 Mon Sep 17 00:00:00 2001 From: Max Peintner Date: Fri, 14 Feb 2025 08:22:02 +0100 Subject: [PATCH 41/48] Update .github/workflows/docker.yml Co-authored-by: Elio Bischof --- .github/workflows/docker.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 7e6e2b9d126..79524b62f16 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -4,7 +4,6 @@ on: push: branches: - main - - dev jobs: build: From c2041abca1a8f10cac3e1bdf904345987ea20257 Mon Sep 17 00:00:00 2001 From: Max Peintner Date: Fri, 14 Feb 2025 08:22:09 +0100 Subject: [PATCH 42/48] Update apps/login/src/app/login/route.ts Co-authored-by: Elio Bischof --- apps/login/src/app/login/route.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/login/src/app/login/route.ts b/apps/login/src/app/login/route.ts index 982ecde7ce7..4db21f14301 100644 --- a/apps/login/src/app/login/route.ts +++ b/apps/login/src/app/login/route.ts @@ -216,8 +216,6 @@ export async function GET(request: NextRequest) { const authRequestId = searchParams.get("authRequest"); const sessionId = searchParams.get("sessionId"); - console.log("request.url", request.url); - console.log("nexturl", request.nextUrl); const _headers = await headers(); const { serviceUrl } = getServiceUrlFromHeaders(_headers); From 3088198613ec4b4dfce41d74dab0ec9be94b9ac1 Mon Sep 17 00:00:00 2001 From: Max Peintner Date: Fri, 14 Feb 2025 08:23:08 +0100 Subject: [PATCH 43/48] remove headers route --- apps/login/src/app/headers/route.ts | 13 ------------- 1 file changed, 13 deletions(-) delete mode 100644 apps/login/src/app/headers/route.ts diff --git a/apps/login/src/app/headers/route.ts b/apps/login/src/app/headers/route.ts deleted file mode 100644 index 13a67f87f43..00000000000 --- a/apps/login/src/app/headers/route.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { NextRequest, NextResponse } from "next/server"; -export const dynamic = "force-dynamic"; -export const revalidate = false; -export const fetchCache = "default-no-store"; -export async function GET(request: NextRequest) { - const headers = request.headers; - // Convert headers to a plain object - const headersObject: Record = {}; - headers.forEach((value, key) => { - headersObject[key] = value; - }); - return NextResponse.json(headersObject); -} From 37e98b61e848f20ab2bcead7bbc56ab6940dd97f Mon Sep 17 00:00:00 2001 From: Max Peintner Date: Fri, 14 Feb 2025 08:30:15 +0100 Subject: [PATCH 44/48] lint --- apps/login/src/app/login/route.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/login/src/app/login/route.ts b/apps/login/src/app/login/route.ts index 4db21f14301..9d95e28d70f 100644 --- a/apps/login/src/app/login/route.ts +++ b/apps/login/src/app/login/route.ts @@ -216,7 +216,6 @@ export async function GET(request: NextRequest) { const authRequestId = searchParams.get("authRequest"); const sessionId = searchParams.get("sessionId"); - const _headers = await headers(); const { serviceUrl } = getServiceUrlFromHeaders(_headers); From 4a791c5d24b076fa41226a5d8fd6ecf23e2520a9 Mon Sep 17 00:00:00 2001 From: Max Peintner Date: Fri, 14 Feb 2025 08:48:03 +0100 Subject: [PATCH 45/48] allow hostname *.zitadel.* as image source --- apps/login/next.config.mjs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/apps/login/next.config.mjs b/apps/login/next.config.mjs index 0c969b9977b..00fa1e19c4d 100755 --- a/apps/login/next.config.mjs +++ b/apps/login/next.config.mjs @@ -41,6 +41,12 @@ const imageRemotePatterns = [ port: "8080", pathname: "/**", }, + { + protocol: "https", + hostname: "*.zitadel.*", + port: "", + pathname: "/**", + }, ]; if (process.env.ZITADEL_API_URL) { From 59f7f0b9d72519065459267687540d8448698cfb Mon Sep 17 00:00:00 2001 From: Elio Bischof Date: Fri, 14 Feb 2025 11:43:51 +0100 Subject: [PATCH 46/48] Reapply "enable static api url" This reverts commit beffae47af0ae7add1cf570539be91618e096c3e. --- apps/login/next-env-vars.d.ts | 10 +++++++++- apps/login/src/lib/service.ts | 9 ++++++++- turbo.json | 3 ++- 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/apps/login/next-env-vars.d.ts b/apps/login/next-env-vars.d.ts index 35fcb109197..6ee63855bdf 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/src/lib/service.ts b/apps/login/src/lib/service.ts index 5ea9eec882a..070b2f4f918 100644 --- a/apps/login/src/lib/service.ts +++ b/apps/login/src/lib/service.ts @@ -42,8 +42,15 @@ 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); diff --git a/turbo.json b/turbo.json index 279e45867b1..61316b800e2 100644 --- a/turbo.json +++ b/turbo.json @@ -12,7 +12,8 @@ "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": { From 7d249bfcdc9315a5a17de73bb10d95292b50ff4a Mon Sep 17 00:00:00 2001 From: Max Peintner Date: Fri, 14 Feb 2025 11:47:51 +0100 Subject: [PATCH 47/48] lint --- apps/login/next-env-vars.d.ts | 2 +- apps/login/src/lib/service.ts | 25 ++++++++++++++++++------- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/apps/login/next-env-vars.d.ts b/apps/login/next-env-vars.d.ts index 6ee63855bdf..112eea393f7 100644 --- a/apps/login/next-env-vars.d.ts +++ b/apps/login/next-env-vars.d.ts @@ -20,7 +20,7 @@ declare namespace NodeJS { * The default is x-zitadel-instance-host. * Most users don't need to set this variable. */ - ZITADEL_INSTANCE_HOST_HEADER: string + ZITADEL_INSTANCE_HOST_HEADER: string; /** * Self hosting: The service user id diff --git a/apps/login/src/lib/service.ts b/apps/login/src/lib/service.ts index 070b2f4f918..48a31c1ac6b 100644 --- a/apps/login/src/lib/service.ts +++ b/apps/login/src/lib/service.ts @@ -42,15 +42,26 @@ export async function createServiceForHost( throw new Error("No token found"); } - const instanceHost = new URL(serviceUrl).host + const instanceHost = new URL(serviceUrl).host; const transport = createServerTransport(token, { 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 + 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); From 4969a665ad4a8e2bea009acc85a4a212ba685243 Mon Sep 17 00:00:00 2001 From: Elio Bischof Date: Fri, 14 Feb 2025 12:03:07 +0100 Subject: [PATCH 48/48] fix path --- .github/workflows/docker.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 79524b62f16..bad19343d35 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -58,7 +58,7 @@ jobs: run: pnpm install - name: Build for Docker - run: NEXT_PUBLIC_BASE_PATH=/ui/new-login pnpm build:docker + run: NEXT_PUBLIC_BASE_PATH=/new-login pnpm build:docker - name: Build and Push Image id: build