# Which Problems Are Solved - Native apps (mobile/desktop) use custom protocol schemes (e.g. `myapp://callback`, `io.zitadel.app://auth`) as OAuth/OIDC redirect URIs. The previous redirect-safety check in the login UI only allowed `http:`/`https:` absolute URLs, so these custom-scheme callbacks were wrongly rejected and native app login flows were broken. - Even for valid external redirects, `router.push()` triggers an RSC prefetch `fetch()` that is blocked by the CSP `connect-src 'self'` directive for non-same-origin URLs, so navigation to external/custom-protocol targets failed. - SAML and OIDC callback URLs returned from the backend were not consistently validated before being used for redirects/POSTs across the various flow entry points. # How the Problems Are Solved - Reworked `isSafeRedirectUri` to use `@braintree/sanitize-url` instead of a strict `http/https`-only allowlist. Custom protocol schemes are now permitted, while dangerous schemes (`javascript:`, `data:`, plus an explicit block of `file:`, `blob:`, `about:`) are still rejected. - Added `isExternalUrl` helper to distinguish internal relative paths (`/...`) from external/custom-protocol targets. - In `handleServerActionResponse`, external/custom-protocol redirects now navigate via `window.location.href` (full navigation) instead of `router.push()`, avoiding the CSP-blocked RSC prefetch. Internal paths continue to use `router.push()`. - Added consistent redirect-URI validation for SAML and OIDC callbacks across all relevant entry points (`oidc.ts`, `saml.ts`, `server/flow-initiation.ts` including the `prompt=none` path, and the SAML `samlData` POST case), blocking unsafe URLs with a clear warning and error response. # Additional Changes - Added `@braintree/sanitize-url` (`^7.1.2`) dependency to `apps/login` (`package.json` / `pnpm-lock.yaml`). - Added unit tests for `isExternalUrl` covering relative paths, absolute HTTP/HTTPS URLs, custom protocol schemes, and protocol-relative URLs. - Annotated the intentional `window.location.href` navigation with a CodeQL suppression comment, documenting that the URL is validated by `isSafeRedirectUri` beforehand. - Minor formatting cleanup in `console` JWT provider component. # Additional Context - This restores behavior that previously worked for native apps but regressed when redirect validation was tightened to `http`/`https` only. --------- Co-authored-by: Max Peintner <[email protected]>
Zitadel Management Console
The Management Console is Zitadel's management UI.
It is built using Angular and part of the Zitadel monorepo.
To get started follow the contributing quick start.
Building
To build for production:
pnpm nx run @zitadel/console:build
This will:
- Generate proto files (via
prebuildscript) - Build the Angular app with production optimizations
Linting
To run linting and formatting checks:
pnpm nx @zitadel/console:lint
To auto-fix formatting issues:
pnpm nx @zitadel/console:lint-fix
Project Structure
src/app/proto/generated/- Generated proto files (Angular-specific format)buf.gen.yaml- Local proto generation configurationproject.json- Nx orchestration and caching for builds and testsprebuild.development.js- Development environment settings script
Dependency Chain
The Management Console app has the following build dependencies managed by Nx:
@zitadel/proto:generate- Generates the protobuf stubs@zitadel/client:build- Builds the TypeScript gRPC client library@zitadel/console:generate- Generates Management Console-specific protobuf stubs@zitadel/console:build- Creates a production build from Management Console
This ensures that the Management Console always has access to the latest client library and protobuf definitions.
Proto Generation Details
@zitadel/protogeneration: Modern ES modules with@bufbuild/protobuffor v2 APIs- Local
buf.gen.yamlgeneration: Traditional protobuf JavaScript classes for v1 APIs
The Management Console app calls Zitadel v1 and v2 APIs. As long as the Management Console still calls v1 APIs, it needs to import client stubs from separate sources:
Legacy v1 API (Traditional Protobuf)
- Uses local
buf.gen.yamlconfiguration - Generates traditional Google protobuf JavaScript classes extending
jspb.Message - Uses plugins:
protocolbuffers/js,grpc/web,grpc-ecosystem/openapiv2 - Output:
src/app/proto/generated/ - Used for: Most existing Management Console functionality
Modern v2 API (ES Modules)
- Uses
@zitadel/protopackage generation - Generates modern ES modules with
@bufbuild/protobuf - Uses plugin:
@bufbuild/eswith ES modules and JSON types - Output:
login/packages/zitadel-proto/ - Used for: New user v2 API and services
Dependency Management
The Management Console's project.json ensures proper execution order:
@zitadel/proto:generateruns first (modern ES modules)- Management Console's local generation runs second (traditional protobuf)
- Build/lint/start tasks depend on both generations being complete
This approach allows the Management Console app to use both v1 and v2 APIs while maintaining proper build dependencies.
Legacy Information
This project was originally generated with Angular CLI version 8.3.20 and has been updated over time.