Commit Graph
4539 Commits
Author SHA1 Message Date
Marco A.andCopilot f3ff0d59ec chore: Minor rework SECURITY.md (#11839)
# Which Problems Are Solved

Paragraph reorganization of `SECURITY.md` and some minor changes

# How the Problems Are Solved

  - Move out of scope section under `Scope`
  - Update `Supported Versions` with an up to date link
  - Extend `Out of Scope`

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-03-20 08:23:25 +00:00
Marco A. 8d1a099deb fix(domain): Fix session checks failing tests (#11881)
# Which Problems Are Solved

2 tests were failing on the new session checks:

  - Password check (events) fails due to a race condition
- IDP intent check (events) (also password test) fails due to a flaky
time comparison

# How the Problems Are Solved

- Race condition: remove setting the password hasher in the test. It's
already globally set in `domain_test.go`
- Time comparison: use `assert.WithinRange` instead of `assert.InDelta`
and use 2 second range to make sure you don't get resolution issues

# Additional Context

- Closes #11878
2026-03-20 06:57:36 +01:00
Fabienne Bühler a592fd7293 docs: update naming on authorizations requests to role assignments (#11850)
# Which Problems Are Solved

API Requests in the docs, still had old naming

# How the Problems Are Solved

Updated Authorization Reuqest naming in docs with role assignments
2026-03-19 09:45:21 +01:00
Livio SpringandStefan Benz ca4bba3992 feat: add delete session on relation tables (#11334)
# Which Problems Are Solved

As part of moving the session API to the relational database, this PR
adds the functionality to delete sessions through the session API v2 and
the OIDC end_session endpoint.

# How the Problems Are Solved

- added `SessionDeleteCommand` in domain package
- added possibility to pass the session token verifier to the domain
package
- use feature flag to switch API and OIDC usage from CQRS to relation
table
- added a `permissionCheck` condition to let permissions be checked
directly in the repository / sql
- part of it is still a placeholder until actual permission tables are
done
- added a `session_deleted` table to store (recently) deleted sessions
to handle necessary checks / cases like delete my own session, which
needs to be idempotent

# Additional Changes

Fixed `Matches` function of `existsCondition` (as missing an
implementation)

# Additional Context

- closes #11037

---------

Co-authored-by: Stefan Benz <46600784+stebenz@users.noreply.github.com>
2026-03-19 08:35:53 +01:00
Federico Coppede ae32508225 docs: postgresql 18 warning (#11871)
Added a callout to the Kubernetes deployment guide (`Deploy ZITADEL on
Kubernetes`) explicitly stating that PostgreSQL 18 is not currently
supported, ensuring users deploy with a compatible version (14-17).
2026-03-18 12:23:16 -07:00
Federico Coppede 80a20e9680 docs: added link to sidebar title for benchmarks (#11870)
This PR adds a link to the benchmarks title on the sidebar
2026-03-18 15:29:53 +00:00
997aa607c4 feat(telemetry): unify request details (#11509)
# Which Problems Are Solved

In the "new" structured logging, request details were added in different
middlewares, such as request, instance and user IDs. This meant the the
upstream request logging middleware did not have access to metadata that
got added later, resulting in incomplete logs. Furthermore it was not
possible to correlate an API error response to log output.

# How the Problems Are Solved

A mutable request details object is added to the context early on. When
the api authz function run, the instance and user IDs are added to this
object as they become available. Every logline emitted after this
(time-wise) will then all contain these details under the `request` log
group.

<details>

<summary>example output in JSON</summary>

```json
{
  "time": "2026-03-13T19:21:20.890428806Z",
  "level": "INFO",
  "source": {
    "function": "github.com/zitadel/zitadel/internal/api/grpc/server/connect_middleware.LogHandler.func1.1",
    "file": "/workspaces/zitadel/internal/api/grpc/server/connect_middleware/log_interceptor.go",
    "line": 34
  },
  "msg": "request served",
  "request": {
    "id": "d6q67c04vtjmi77cbbpg",
    "instance_host": "localhost:8080",
    "instance_id": "362349751439458307",
    "user_id": "362349751440048131"
  },
  "TraceID": "a9e0fee3522224f3583bbdcda737f4b4",
  "SpanID": "a563056eee36920a",
  "stream": "request",
  "version": "2026-03-13T19:20:59Z",
  "protocol": "connect",
  "service": "zitadel.user.v2.UserService",
  "http_method": "POST",
  "path": "/zitadel.user.v2.UserService/ListUsers",
  "code": "code_0",
  "duration": 12254350
}
```

</details>

Request IDs are now also returned with a response header or metadata.
Depending on the protocol:

- HTTP calls always return the request ID as header, regardless of
status
- gRPC calls always return the request ID as header, even if there was
an error
- connect RPC calls returns the request ID as header on success, trailer
in case of error. This is because header must be set on the response
object, which is nil in case of error. When there is an error, metadata
can be added which are then sent as trailers.

# Additional Changes

- Use the existing call duration middleware for both request ID and
logging for a consistent request start timestamp in all layers.
- Upgrade sloggcp for some fixes (notably TraceID)
- Modify the NoCache middleware so it uses `SetHeaders` instead of
`SendHeaders`. The latter prevented any other handler from setting
headers, including the new request ID middleware.

# Additional Context

Follow up on demo of:
  - https://github.com/zitadel/zitadel/pull/11159
  - https://github.com/zitadel/zitadel/pull/11435
  - backport to v4

---------

Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
Co-authored-by: muhlemmer <5411563+muhlemmer@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Marco A. <marco@zitadel.com>
2026-03-18 14:07:33 +01:00
SilvanandMarco Ardizzone f138082b64 feat: add administrator repository (#11803)
Introduces the `administrators` relational table and repository layer
for the v3 backend, unifying instance, organization, project, and
project-grant membership into a single scoped model.

Closes #10220

## Changes

- **Domain**: `Administrator` struct, `AdministratorScope` enum,
`AdministratorRepository` interface with typed CRUD, column, condition,
and change helpers. Generated enumer and GoMock.
- **Migration** (`016`): `zitadel.administrators` table with a generated
`id`, scope-alignment check constraint, cascading foreign keys, and a
child `administrator_roles` table.
- **Repository**: CTE-based role mutations (`AddRole`, `RemoveRole`,
`SetRoles`) for atomicity. Roles aggregated via `ARRAY_AGG`.
- **Projection**: Event reducers for
`member.added/changed/removed/cascade_removed` across all four admin
scopes.
- **Fixes**: `Rows.Close()` error wrapping; `TextArray` nil-safe scan +
full `pgtype` array interface; `authorization` and `projectGrant` scan
helpers fixed for `ARRAY_AGG` under `database/sql`; removed unused `ctx`
parameter from `callReduce`.

---------

Co-authored-by: Marco Ardizzone <marco@zitadel.com>
2026-03-18 10:24:09 +01:00
Silvan 6d90a120a6 feat: allow transactional table setup step to recreate the whole schema (#11833)
## Problem description

- Setup currently creates/updates relational tables, but there is no
built-in way to fully reset the relational schema during iterative
development.
- Re-running setup after schema/projection changes can leave stale
relational objects and projection state behind, which makes local/dev
validation harder.
- There is no explicit, configurable switch in setup steps for
destructive schema recreation behavior.

## How the Problems Are Solved

- Adds a new setup step configuration section for relational tables with
a `ShouldRecreateSchema` flag (default `false`).
- Wires the new config flag into the transactional tables setup step.
- Extends the transactional tables execution logic to optionally:
  - Drop the `zitadel` schema with `CASCADE`
- Clean related projection state entries for relational tables in
`projections.current_states`
  - Recreate tables through the existing setup flow afterward
- Wraps the destructive operations in a transaction and keeps
error/rollback handling plus logging for visibility.

## Additional Changes

- Adds an explicit warning in step configuration that schema recreation
is intended for development and not production use.
- Keeps behavior fully backward-compatible by default
(`ShouldRecreateSchema: false`), so existing setups are unchanged unless
the flag is enabled.

## Additional Context

- Follow-up for relational setup/dev workflow improvements.
- PR: #11833

## How to use it

### Env `export ZITADEL_RELATIONALTABLES_SHOULDRECREATESCHEMA=true`

### Config

Add the following to your custom setup steps config:

```yaml
RelationalTables:
  ShouldRecreateSchema: true
```
2026-03-18 03:53:57 +00:00
Max PeintnerandRamon a864434b4b feat(login): update to nextjs 16, improve caching, change default colors (#11629)
# Which Problems Are Solved

Updated the project to use the latest versions of Next.js and React, and
implemented a SWR caching strategy for key settings API calls to improve
performance. Adjusted configuration to ensure compatibility with Next.js
16.

# How the Problems Are Solved

- Updated next to 16.1.6, react & react-dom to 19.2.4, and next-intl to
4.8.3.
- Implemented `API_CACHE_ENABLED` and `API_CACHE_CONFIG` (replacing
deprecated unstable_cacheLife) for:
  - getBrandingSettings
  - getSecuritySettings
  - getPasswordComplexitySettings
  - getLoginSettings ...
- Updated default theme colors from blue to a more neutral black and
white

# Additional changes

- Updated login docker image to node 24

---------

Co-authored-by: Ramon <mail@conblem.me>
2026-03-17 16:01:50 +01:00
RamonandMax Peintner fca2589fc3 fix(login): http 2 memory leak's (#11830)
# Which Problems Are Solved
All http 2 based connect-es clients caused memory leaks in our testing
using the login v2 application as the host.

# How the Problems Are Solved
Switch to connect-rpc based http 1.1 transport for the login v2

# Additional Changes
Improved the otel interceptor implementation and tests.

# Additional Context
- connect-rpc is only enabled for v2 API's so we have to make sure to
not use any v1 apis in the login but this should be the case anyways.
- Discussion #10562

---------

Co-authored-by: Max Peintner <max@caos.ch>
2026-03-17 14:29:21 +00:00
c1be72765c chore(login): remove integration tests (#11608)
# Which Problems Are Solved

Removes the Cypress integration tests and associated configuration from
the apps/login project to streamline the build process.

# How the Problems Are Solved

- Removed cypress directory, integration directory, and
cypress.config.ts from apps/login.
- Updated project.json to remove test-integration targets and
dependencies.
- Updated package.json to remove the cypress dev dependency and clean
script reference.
- Updated tsconfig.json to remove the now-redundant integration
exclusion.
- Ensured acceptance tests are preserved and correctly excluded from
build inputs.

---------

Co-authored-by: Florian Forster <florian@zitadel.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: conblem <mail@conblem.me>
2026-03-17 14:16:39 +00:00
c3a6bdb0bb Merge commit from fork
* fix: add `Scopes` to `Request` interface so that scopes can be validated on all requests

* feat: assert org from scope exists when authorizing requests

* fix: check all scopes

* comments

* check org on callback creation

* fix tests

* clarifications

* fix scope marshaling

* fix: enfore organization for authrequest in initiation

* fix: filter sessions on the accounts page by organization scope

* add integration tests

---------

Co-authored-by: Livio Spring <livio@zitadel.com>
Co-authored-by: Max Peintner <peintnerm@gmail.com>
2026-03-17 12:54:27 +01:00
Marco A. aa4432dc99 feat(session): IDP Intent Check API with relation tables (#11820)
# Which Problems Are Solved

As part of #11035 , this PR implements the IDP intent check logic for
session validation

# How the Problems Are Solved

- Inject encryption algorithm for IDP intent tokens at DB initialization
  - Add the IDP intent repository as an invoke option
  - Rework crypto mocks using gomock
  - Implement IDP intent check logic
- minor - DB: expand IDP Intent deletion testing table with a test case
where IDP intent is not found

# Noteworthy

I did not implement `domain.Transactional` given the doubts that
@adlerhurst expressed in https://github.com/zitadel/zitadel/pull/11804 .
So, there is no transaction AT ALL in here because the `Execute()`
method contains one single DB call (Delete) and `Validate()` just does
Get calls.

# Additional Context

This is a cherry-picked PR + minor changes, coming from
https://github.com/zitadel/zitadel/pull/11164
- Relates to #11035
- Depends on https://github.com/zitadel/zitadel/pull/11804
2026-03-17 10:50:47 +00:00
Florian ForsterandCopilot 3fdac54878 docs: simplify helm chart guide (#11781)
## Summary

Rewrites the Kubernetes quickstart (Stage 1) to match the simplicity of
the Docker Compose quickstart. With the new bundled chart, users deploy
the full stack — PostgreSQL, Traefik, ZITADEL API, ZITADEL Login — with
two copy-paste blocks and no prerequisites beyond a Kubernetes cluster.

## Before / After

**Before:**
- Requires a pre-installed ingress controller
- 4 manual steps: install PostgreSQL separately, create secrets, wire DB
config, install ZITADEL
- Users need to understand Helm dependency management

**After:**
```bash
mkdir zitadel-helm && cd zitadel-helm &&
curl -fsSLO https://raw.githubusercontent.com/zitadel/zitadel-charts/main/examples/0-quickstart/quickstart-values.yaml
```
```bash
helm repo add zitadel https://charts.zitadel.com &&
helm repo add bitnami https://charts.bitnami.com/bitnami &&
helm repo add traefik https://traefik.github.io/charts &&
helm repo update &&
helm upgrade --install zitadel zitadel/zitadel --values quickstart-values.yaml --wait
```

Same UX as the Docker Compose quickstart. Mirrors the GitLab chart
pattern.

## Changes to `kubernetes/index.mdx`

### Stage 1 — Quickstart (full rewrite)
- Prerequisites reduced to: a Kubernetes cluster (1.30+), kubectl, Helm
- k3d moved to an optional callout tip (no longer required)
- Install section: `mkdir` → `curl` → `helm upgrade --install --wait`
(two copy-paste blocks, same pattern as compose)
- `helm upgrade --install` instead of `helm install` — idempotent, safe
to re-run
- "Swap out components" table: shows how to replace PostgreSQL, Traefik,
or add Redis
- Callouts: masterkey warning, stack architecture diagram

### Stage 2+ (unchanged)
Production cluster setup, TLS, cert-manager, etc. are untouched.

## Related
- Chart changes PR:
[zitadel/zitadel-charts#560](https://github.com/zitadel/zitadel-charts/pull/560)

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-17 10:36:23 +00:00
Tim MöhlmannandLivio Spring 921414fa16 fix(telemetry): count IDP template data (#11720)
# Which Problems Are Solved

The total number of configured IDPs seemed of.
We were counting only the IDP table for non-templated IDPs.

# How the Problems Are Solved

Add a count trigger migration for the IDP template table.
Entries will be counted under the existing
`ResourceCountIdentityProvider`

# Additional Changes

- none

# Additional Context

- Reported internally
- Implemented in #9979
- Related https://github.com/zitadel/zitadel/issues/9957

Co-authored-by: Livio Spring <livio.a@gmail.com>
2026-03-17 05:12:43 +00:00
Florian ForsterandCopilot Autofix powered by AI 279f592d80 docs: tweaking titles for better SEO appeal (#11852)
Just updating some title and descriptions for better SEO discovery

---------

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-03-16 20:03:11 -03:00
Federico CoppedeandCopilot Autofix powered by AI 34e6a792d2 docs: text customization on Login V2 (#11849)
This PR updates the "Hosted Login UI" documentation to clarify how text
customization works for the new Hosted Login V2.

**Changes:**

1. Adds a warning callout to the "Customization options" section.
2. Clarifies that Login V2 interface texts currently cannot be modified
via the ZITADEL Console UI.
3. Provides the required workaround, directing users to use the Settings
V2 API to patch translation keys using the en.json locale file as a
reference.

---------

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-03-16 17:12:10 +01:00
Livio SpringandMarco A. 500821ce0c fix: prevent possible nil pointer panics (#11728)
# Which Problems Are Solved

We found multiple cases where potentially a panic occurred or could
occur:
- when de/encrypting certain information
- returning apps without any configuration type (?)
- apple IdPs without a proper private key

# How the Problems Are Solved

- Added nil checks
- Check private key format for apple IdPs
- Added necessary helper function

# Additional Changes

Fixed i18n yaml where the IDP errors were indented under `org` instead
of directly under `errors`.

# Additional Context

- requires backport to v4.x

---------

Co-authored-by: Marco A. <marco@zitadel.com>
2026-03-16 14:30:17 +00:00
Marcel LinkandRamon 7c0e1750f3 feat(login): Support private key file with env (#10575)
# Which Problems Are Solved

Instead of encoding the private key as base64 and setting it in the env
as SYSTEM_USER_PRIVATE_KEY it is sometimes easier to write it to disk
and use a file path. This is for example also possible when setting up
system users in zitadel core.

# How the Problems Are Solved

Added SYSTEM_USER_PRIVATE_KEY_FILE which is preferred over
SYSTEM_USER_PRIVATE_KEY and expects a file path to a private key in PEM
format (like SYSTEM_USER_PRIVATE_KEY but not base64 encoded). To prevent
loading the private key too often it is cached.

---------

Co-authored-by: Ramon <mail@conblem.me>
2026-03-16 14:55:58 +01:00
Wim Van Laer 965e3fa621 fix: check whether org exists before creating user (#11647)
# Which Problems Are Solved

It was possible to create a user with an imaginary org.

# How the Problems Are Solved

Check whether org exists before creating the user.

# Additional Changes


# Additional Context

- Closes #11532
2026-03-16 13:12:21 +01:00
Fabienne Bühler 9a4530bf77 docs: Add note for updated terminology (#11802)
# Which Problems Are Solved

For existing customers it could be hard to understand the new aligned
terms we have defined, if they are already used to the "old term"

# How the Problems Are Solved

Adding notes at the top of docs pages to state clearliy new and old
terms.
2026-03-16 09:10:48 +00:00
Mridang Agarwalla cadf75e4fe fix: use configured service name for OTEL resources (#11818)
# Which Problems Are Solved

The OTEL service.name resource attribute is hardcoded to "ZITADEL" in
setupOTelSDK, so the Instrumentation.ServiceName config and the
OTEL_SERVICE_NAME environment variable are both ignored. This makes it
impossible to distinguish between multiple Zitadel instances or
co-located services in tracing dashboards and alerting rules.

# How the Problems Are Solved

The hardcoded string is replaced with cfg.ServiceName so the configured
value flows through. An explicit check for the OTEL_SERVICE_NAME
environment variable is added at the top of resourceWithService, giving
it the highest priority per the OpenTelemetry specification.

# Additional Changes

None.

# Additional Context

Closes #11455
Backport to v4
2026-03-13 16:18:51 +00:00
Marco A. 3c3201e5a0 feat(session): Password Check API with relation tables (#11804)
# Which Problems Are Solved

As part of #11035 , this PR implements the password check logic for
session validation

# How the Problems Are Solved

- Add system config to default configuration of `domain` package for
easy initialization. Intialize the system settings when Zitadel starts
up
- Add password hasher verify logic to the default configuration of
`domain` package. Initialize it when Zitadel starts up.
  - Add settings repositories with their mocks
  - Implement the logic for doing a password check

# Additional Context

This is a cherry-picked PR + minor changes, coming from
https://github.com/zitadel/zitadel/pull/11164
- Relates to #11035
- Depends on https://github.com/zitadel/zitadel/pull/11777
2026-03-13 11:40:48 +01:00
Gayathri VijayanandCopilot d08779e279 feat: supporting metadata updates in actions v2 via RetrieveIdentityProviderIntent API (#11810)
# Which Problems Are Solved

Adds support for returning CreateUser/UpdateUser action payloads from
RetrieveIdentityProviderIntent so Actions v2 can update user metadata
(and other fields) using the v2 user APIs, ensuring parity with user
creation using Actions v2.

# How the Problems Are Solved

By:
- deprecating `AddHumanUser` and `UpdateHumanUser` fields in
`RetrieveIdentityProviderIntentResponse`
- adding a oneof field called `UserAction` with `CreateUser` and
`UpdateUser` fields to support user creation/update
- setting `UserAction` in the `RetrieveIdentityProviderIntentResponse`
for user creation/update

# Additional Changes
N/A

# Additional Context
- Related to https://github.com/zitadel/zitadel/issues/11369
- Follow-up for PRs https://github.com/zitadel/zitadel/pull/11719,
https://github.com/zitadel/zitadel/pull/11747
- Actions V2 example docs will be updated in a follow-up PR

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-03-12 16:01:58 +00:00
Florian Forster 238d98bb30 fix: update OpenAPI generation to use workspace root and improve temp… (#11822)
# Which Problems Are Solved

- `@zitadel/docs:generate-proto-docs` could block while `npx` waited for
confirmation to install `@bufbuild/buf`.
- When the docs generation ran through `nx run-many --target generate`,
that interactive prompt was hidden, so the task appeared stuck without
visible output.

# How the Problems Are Solved

- Resolve Buf from the workspace root with `pnpm exec buf generate` so
the repo-pinned CLI is used non-interactively.
- Run the Buf command from the workspace context instead of the
temporary execution directory.
- Keep the existing generation arguments, template handling, and
excluded path handling intact.

# Additional Changes

- Remove the temporary directory setup that was only needed for the
previous `npx`-based invocation.
- Keep the existing `protoc-gen-connect-openapi` installation and PATH
wiring unchanged.

# Additional Context

- Follow-up for the docs generation issue discussed in Discord where
`@zitadel/docs:generate-proto-docs` prompted for `@bufbuild/buf`
installation and appeared blocked under `nx run-many --target generate`.
- Validated with `pnpm nx run @zitadel/docs:generate-proto-docs
--outputStyle=stream`.
- Validated with `pnpm nx run @zitadel/docs:generate
--outputStyle=stream`.
2026-03-12 14:47:33 +00:00
Vitor Bari Buccianti e664d8d04e chore(deps): upgrade fumadocs (#11787)
# Which Problems Are Solved

Request builder in the API docs does not render oneOf variants:
https://github.com/fuma-nama/fumadocs/issues/3063


[Before](https://zitadel.com/docs/reference/api/user/zitadel.user.v2.UserService.CreateUser):

<img width="1211" height="965" alt="Screenshot 2026-03-09 at 10 01 54"
src="https://github.com/user-attachments/assets/562d2e8f-99e0-438a-96fb-8b3c57d94c85"
/>

# How the Problems Are Solved

Fixed upstream:
https://github.com/fuma-nama/fumadocs/commit/440a7efaec4453692a287fe4f75b824c395adfb9


[After](https://docs-coodtipmk-zitadel.vercel.app/docs/reference/api/user/zitadel.user.v2.UserService.CreateUser):

<img width="1155" height="1003" alt="Screenshot 2026-03-09 at 10 02 40"
src="https://github.com/user-attachments/assets/f503330e-17f8-43ef-8f79-2d8a488794cf"
/>


# Additional Changes

n/a

# Additional Context

Relates to #11784
2026-03-12 15:12:05 +01:00
cbf05dbe16 fix(ui/auth): display correct Apple sign-in callback URL (#11439)
# Which Problems Are Solved

- Apple Sign-In uses a Form Post method to return the authorization
response, which ZITADEL handles at a specific endpoint ending in /form
for the login v1.
- The Console previously displayed the standard callback URL (without
`/form`), causing confusion and configuration errors..


# How the Problems Are Solved

- **Console**: Updated ProviderNextService to accept a suffix string . 
- **Console**: Updated ProviderAppleComponent to append the suffix to
the urls.


# Additional Changes
- Updated `docs/docs/guides/integrate/identity-providers/apple.mdx` to
explicitly state that the callback URL end with `/form`
- Updated `docs/docs/guides/integrate/login-ui/external-login.mdx` to
clarify the `/form` suffix requirement for Apple Sign-In in the hosted
login documentation.
# Additional Context
- fixes #11438

---------

Co-authored-by: Ramon <mail@conblem.me>
Co-authored-by: Florian Forster <florian@zitadel.com>
2026-03-12 10:24:48 +00:00
Mridang Agarwalla 7cdee1703f chore: standardised the eslint config structure accross the project (#11814) 2026-03-12 11:02:52 +01:00
Livio Spring 621fd9bdec test: fix matrix for relation table tests (#11757)
# Which Problems Are Solved

In #11239 , the helper function for matrix tests (without the relational
tables enabled) was changed, but the feature was never enabled in the
matrix. Some integration tests currently can't even succeed because of
missing implementations.

# How the Problems Are Solved

This PR correctly enables the feature where intended and returns the
state into the matrix.
This allows returning early for some tests which cannot succeed yet.
Corresponding todos have been re-added as well.

# Additional Changes

None

# Additional Context

 - relates to #11239
 - requires backport to v4.x
2026-03-12 06:24:40 +00:00
Mridang Agarwalla db8f475a02 feat(login): add readiness probe endpoint (#11828)
# Which Problems Are Solved

The login v2 container has no way to verify upstream Zitadel API
connectivity before accepting traffic. The existing `/healthy` endpoint
always returns 200 regardless of whether the backend is reachable. This
means Kubernetes routes user traffic to pods that cannot actually serve
login requests, causing silent failures where the root layout swallows
gRPC errors and renders pages with default settings.

# How the Problems Are Solved

A new `/ui/v2/login/ready` endpoint creates a gRPC client using the same
auth and transport path as real requests, calls
`SettingsService.getGeneralSettings()`, and returns `200 OK` on success
or `503 Service unavailable` on failure. This verifies both network
connectivity and authentication credentials to the upstream Zitadel API.

Kubernetes supports readiness probes natively, so this endpoint can be
configured as a readiness probe to gate traffic until the login
container can connect to Zitadel. Docker Compose does not have a
readiness probe concept, so the compose healthcheck and
`healthcheck.mjs` default remain unchanged and continue using
`/healthy`.

The Docker HEALTHCHECK in the Dockerfile has been updated to use
`/ready` so that the image-level health status reflects actual upstream
connectivity. This will also allow us to simplify the Helm chart by
dropping the `wait4x` init containers that currently poll the Zitadel
API before starting the login pod, since the readiness probe makes them
redundant.

# Additional Changes

The `/ready` endpoint has been added to the OTEL HTTP instrumentation
ignore list to avoid noisy probe traces. Unit tests, a wiring spec
integration test, and an OTEL span filtering test have been added for
the new endpoint. The `# TODO: Check healthy, not ready` comment has
been removed from the Dockerfile. The `/healthy` endpoint is kept as-is
for liveness probes.

# Additional Context

The Helm chart changes to use `/ready` for readiness and startup probes
and to remove the `wait-for-zitadel` init container will be done in a
follow-up PR in the `zitadel-charts` repository.
2026-03-12 15:52:58 +11:00
4586708c06 chore: add terminology Markdown catalog for Copilot review (#11764)
## Problem

ZITADEL has inconsistent naming across docs, UI, and API
([#5888](https://github.com/zitadel/zitadel/issues/5888)). We want
contributors and Copilot code-review agents to flag discouraged terms
and suggest canonical replacements automatically.

## Solution

Add a **Markdown terminology catalog** that Copilot agents read
natively.

### What's added

- **`TERMINOLOGY.md`** (repo root) — full ~35-term canonical table from
issue #5888 with:
- Action legend: `keep` / `replace` / `remove` / `internal` / `proposed`
  - Scope legend: `UI` / `Docs` / `API` / `Everywhere`
  - "Search for (discouraged)" and "Replace with / enforce" columns
  - Governance section (how to add new terms, ownership)
- **`.github/instructions/terminology.instructions.md`** — Copilot
`applyTo`-scoped instruction that activates on every PR touching
docs/i18n/proto files and tells the agent:
  - Which files map to which scope
- Not to flag identifiers/field names in proto files (only
comments/descriptions)
  - To request catalog updates when new terms are introduced

### What's updated

- `.github/copilot-instructions.md` — points to `TERMINOLOGY.md`
- `apps/docs/AGENTS.md` — updated reference, removed dead
`check-terminology` Nx target entry
- `.github/pull_request_template.md` — checklist item updated
- `.github/workflows/ready_for_review.yml` — checklist item updated

### Why Markdown over JSON

| | Markdown | JSON |
|---|---|---|
| Copilot reads natively | yes | no (needs parsing context) |
| Mirrors AGENTS.md table style | yes | no |
| Human-readable without tooling | yes | no |
| Mirrors the #5888 issue format | yes | no |
| Requires schema / parser | no | yes |

### Why root over `.github/`

`.github/` is for GitHub-specific automation files. `TERMINOLOGY.md` is
a project-wide convention document — it belongs alongside
`CONTRIBUTING.md`, `CODE_OF_CONDUCT.md`, and `AGENTS.md` at the repo
root.

## How it works in practice

When a PR touches `apps/docs/content/**`, `console/src/assets/i18n/**`,
`apps/login/locales/**`, or `proto/**/*.proto`, Copilot code review
automatically loads `.github/instructions/terminology.instructions.md`
and cross-references `TERMINOLOGY.md` to flag discouraged terms.

Human reviewers see the terminology checklist in the auto-comment on PR
open.

## Checklist
- [x] `TERMINOLOGY.md` at repo root with all ~35 terms from #5888
- [x] Plain text action/scope values (no emojis)
- [x] Copilot instruction file scoped to correct file patterns
- [x] All stale `terminology-rules.json` references removed
- [x] No linter/CI step added (guidelines-only approach)

Relates to: #5888

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Fabienne Bühler <fabienne@zitadel.com>
2026-03-11 16:20:27 +00:00
Fabienne BühlerandMridang Agarwalla 574e23e834 fix: Separate Example Applications and SDKs/Integrations more clearly (#11569)
# Which Problems Are Solved

The distinction between Example Applications and SDKs has not been
clear. In the SDKs section a lot of Example applications where listed.
Also In the SDKs it was not really clear what the SDKs actually are.
Also some examples and skds are outdated and not well maintained
anymore.

# How the Problems Are Solved

- Moved all example app guides to the Example Applications Section
- Restructured SDKs Nav --> SDKs & Integrations: Frontend & Mobile,
Backend & API, Management API Clients
- Removed unnecessary / outdated guides
- Remove ids in framework.json for frameworks which shouldn't be
rendered in console

## Todos:
- Update SDKs Introduction page
- Add links to common oidc libs for most used frameworks

---------

Co-authored-by: Mridang Agarwalla <mridang@zitadel.com>
2026-03-11 14:57:15 +01:00
Livio Spring d5f35fbd54 fix(console): switch to webkeys v2 (from v2beta) (#11807)
# Which Problems Are Solved

The Management Console was still using the deprecate v2beta endpoints of
the webkey service even though the v2 service was move to GA a while
ago.

# How the Problems Are Solved

Switch to the v2 endpoints.

# Additional Changes

None

# Additional Context

- relates to #10773
2026-03-11 08:20:21 +00:00
Tim Möhlmann 64ee480f84 Merge commit from fork
When an expired invite code was used for webauthn (passkeys), the change date got updated by the failed event. This change date was used to test for expiry, meaning failed events would reset the expiry timeout.

This fix adds a Code Creation Date to the writemodel which gets set by the first event. This can be the added or requested event.

Other changes:

- Expiry renamed to CodeExpiry so it's consistent with similar write models using secret codes.
- humanVerifyPasswordlessInitCode takes an algorithm instead of the complete generator, so the method can be unit tested easier
- Added tests that reproduced the original issue
2026-03-11 08:25:21 +01:00
Livio Spring 4a8a5e2fef Merge commit from fork 2026-03-11 08:21:42 +01:00
Livio Spring ab51fd9563 Merge commit from fork 2026-03-11 08:12:46 +01:00
SilvanandMarco Ardizzone de1cab9976 refactor: merge relational table projections into one handler (#11740)
## Problem description

During tests we found concurrency issues in the relational table
projections. Tests got flaky if a table (e.g. organization domains) had
too many foreign keys to tables which were projected by another handler.

## Resolution

The projections of the relational tables got merged into one handler to
enforce sequential reduction of events.

## Additional info

- closes https://github.com/zitadel/zitadel/issues/11703
- closes https://github.com/zitadel/zitadel/issues/10810

---------

Co-authored-by: Marco Ardizzone <marco@zitadel.com>
2026-03-10 17:01:46 +00:00
RamonandCopilot 689b90d9d9 fix(console): organization column display in grants #10822 (#11742)
# Which Problems Are Solved

- The organization name in the user grants table was not consistently
displayed. The `grantedOrgName` property was sometimes missing,
resulting in an empty or incorrect value in the 'org' column.

# How the Problems Are Solved

- Implements a conditional check for the 'org' column in the user grants
table. The cell now displays `grantedOrgName` if available, otherwise it
falls back to `orgName`.

# Additional Changes

- Imports and adds `TypeSafeCellDefModule` to the user grants module,
providing the `cnslCellDef` directive for more flexible and type-safe
cell definitions.

# Additional Context

- Fixes #10822

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-03-10 13:47:13 +00:00
Ramon 057fb8dff2 fix(login): prettier setup (#11798)
# Which Problems Are Solved
Invalid formatting in the login codebase due to invalid prettier
configuration

# How the Problems Are Solved
Fxed .prettierignore wildcards for login source files

# Additional Changes
Removed .prettierrc file because there is already a prettier.config.mjs
file

# Additional Context
2026-03-10 13:30:20 +00:00
RamonandMax Peintner 33c635fbc3 fix(console): role assignment manipulation #10517 (#11756)
# Which Problems Are Solved

The management console deletes all roles if user grant is not
manipulated before saving in the dialog.


# How the Problems Are Solved

Correctly prefill the selected role assignments so when no change was
done we keep the current state.

# Additional Changes

- Prevents displaying misleading error messages to users when a role
assignment operation results in no actual changes.

# Additional Context

- Closes #10517

Co-authored-by: Max Peintner <max@caos.ch>
2026-03-10 12:59:44 +00:00
Max Peintner defa7b5d0e fix(login): update LDAP flow (#11788)
Closes #11096 

# Which Problems Are Solved

This pull request resolves a 404 error that occurred at the end of the
LDAP login flow.

Previously, when a user submitted their LDAP credentials in the
apps/login application, the form initiated the session creation process
but incorrectly redirected the user to /idp/ldap/success, a route that
does not exist. In addition, the redirect failed to preserve necessary
IDP context parameters (such as requestId, organization, and linking
fingerprint info) that are required to fully complete the authentication
intent.

# How the Problems Are Solved

- Fixed redirect path: Updated `createNewSessionForLDAP` to redirect to
`/idp/ldap/process` instead of success, aligning it with the standard
IDP intent processing pipeline which dynamically resolves
`[provider]/process`.
- Preserved context parameters: Extracted `requestId`, `organization`,
`postErrorRedirectUrl`, `linkToSessionId`, and `linkFingerprint` from
the URL parameters on the LDAP page and passed them through
LDAPUsernamePasswordForm down to the server action so the ongoing auth
request is successfully tied to the user's intent.
2026-03-10 13:26:42 +01:00
62cb5bbb83 feat: delete metadata on SetOrganizationMetadata api (#11790)
# Which Problems Are Solved

Currently, to delete an Organization metadata key, callers must use a
separate
[DeleteMetadata](https://zitadel.com/docs/reference/api/org/zitadel.org.v2.OrganizationService.DeleteOrganizationMetadata)
API. This increases the complexity on client-side for operations where
metadata need to be synchronized.

# How the Problems Are Solved

Introduce deletion behavior to
[SetOrganizationMetadata](https://zitadel.com/docs/reference/api/org/zitadel.org.v2.OrganizationService.SetOrganizationMetadata):

When a metadata entry is passed with an empty value ("" / empty bytes):

- If the key exists → delete the key
- If the key does not exist → no-op (idempotent, no error)

# Additional Changes

n/a

# Additional Context

Relates to #11776

---------

Co-authored-by: Gayathri Vijayan <66356931+grvijayan@users.noreply.github.com>
Co-authored-by: Gayathri Vijayan <gayathri+github@zitadel.com>
2026-03-10 10:09:51 +00:00
Marco A.andSilvan 8b90ddb0b5 feat(session): User Check API with relation tables (#11777)
# Which Problems Are Solved

As part of #11035 , this PR implements the user check logic for session
validation

# How the Problems Are Solved

- Add user and session repositories as invoke options, as well as their
mocks to prepare the ground for testing
- Implement the logic for the UserCheck command, following what has been
done on eventstore side
- Add a session permission chek interface to be used during the
`Validate()` part of the Commander

# Additional Context

This is a cherry-picked PR + minor changes, coming from
https://github.com/zitadel/zitadel/pull/11164
- Relates to #11035

---------

Co-authored-by: Silvan <27845747+adlerhurst@users.noreply.github.com>
2026-03-10 09:10:31 +00:00
Ramon 86ec54b22f fix(console): manager removal #11543 (#11627)
# Which Problems Are Solved
Organization managers could not be removed in the add manager modal

# How the Problems Are Solved
Correctly emit a change event in the SearchUserAutocompleteComponent to
update dependent components.

# Additional Changes

# Additional Context
- Closes #11543
2026-03-10 09:13:22 +01:00
Gayathri VijayanandLivio Spring 3f258953ce test: add tests for recovery codes event reducers (#11773)
# Which Problems Are Solved

Add integration tests for recovery codes event reducers in the RT model.

# How the Problems Are Solved

Added integration tests for recovery codes event reducers

# Additional Changes

N/A

# Additional Context
- Closes https://github.com/zitadel/zitadel/issues/11707
- Todo: add tests for other reducers in the `users_relational`
projection.

---------

Co-authored-by: Livio Spring <livio.a@gmail.com>
2026-03-09 10:40:02 +00:00
Gayathri VijayanandCopilot 282b2486d9 feat: set metadata field in UpdateUser endpoint (#11747)
# Which Problems Are Solved

To be able to update metadata via the `UpdateUser` endpoint.

# How the Problems Are Solved
This is achieved by:
* adding the `Metadata` field to `UpdateUserRequest`
* update the server layer to convert/set metadata fields to domain layer
metadata
* update the command layer to handle metadata updates

# Additional Changes

N/A

# Additional Context
- Related to https://github.com/zitadel/zitadel/issues/11369,
https://github.com/zitadel/zitadel/issues/11759
- Follow-up for PR https://github.com/zitadel/zitadel/pull/11719

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-03-09 10:47:32 +01:00
Max Peintner 5b12690757 fix(login): seperate OpenTelemetry initialization for different runtimes (#11785) 2026-03-09 09:24:19 +05:30
Marco A. 2793abf1e3 chore(domain): Assert errors using ErrorIS for instance and organization tests (#11789)
# Which Problems Are Solved

This is a small refactoring for tests in `backend/v3/domain` package to
use `assert.ErrorIs` instead of `assert.Equal` for error assertion.

# How the Problems Are Solved

  - Add custom `Is()` function to `MultipleObjectsUpdatedError` error
- Substitute `assert.Equal` with `assert.ErrorIs` in instance and
organization tests

# Additional Context

This was part of #11035
2026-03-06 19:20:54 +01:00
247e278505 feat: delete metadata on SetUserMetadata api (#11776)
# Which Problems Are Solved

Currently, to delete metadata a key, callers must use a separate
[DeleteMetadata](https://zitadel.com/docs/reference/api/user/zitadel.user.v2.UserService.DeleteUserMetadata)
API. This increases the complexity on client-side for operations where
metadata need to be synchronized.

# How the Problems Are Solved

Introduce the behavior to
[SetUserMetadata](https://zitadel.com/docs/reference/api/user/zitadel.user.v2.UserService.SetUserMetadata):

When a metadata entry is passed with an empty value ("" / empty bytes):

- If the key exists → delete the key
- If the key does not exist → no-op (idempotent, no error)

# Additional Changes

- Updated [User Metadata
page](https://zitadel.com/docs/guides/manage/customize/user-metadata#manage-user-metadata-through-the-management-api)

# Additional Context

Similar behavior will be applied to
[UpdateUser](https://zitadel.com/docs/reference/api/user/zitadel.user.v2.UserService.UpdateUser)
and
[SetOrganizationMetadata](https://zitadel.com/docs/reference/api/org/zitadel.org.v2.OrganizationService.SetOrganizationMetadata)

Breaking change? 
Currently, sending an empty value returns an error — no client should be
intentionally relying on that error as part of a working workflow. The
change goes from "rejected input" to "accepted input with defined
semantics."

In other words, it relaxes a restriction rather than tightening one.
Existing valid calls continue to work exactly as before. The only
scenario where it could be "breaking" is if someone explicitly depends
on the error response for empty values (e.g., using it as a validation
check), which would be unusual.

---------

Co-authored-by: Gayathri Vijayan <gayathri+github@zitadel.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-03-06 14:57:52 +01:00