Commit Graph
792 Commits
Author SHA1 Message Date
5bdfd96be5 feat: extend DeleteProvider to include Zitadel IdP (#12396)
# Which Problems Are Solved

This PR extends `DeleteProvider` to include Zitadel provider enabling
the deletion of Zitadel IdP.

# How the Problems Are Solved

- Extend org/instance IDP remove write models to include
`ZitadelIDPAddedEvent` in event appends and queries.
- Extend command-side IDP reduction/type handling for Zitadel IDP add
events.
- Add management/admin integration tests for deleting Zitadel providers
- Add error translation key in all language locales for org-level “IDP
config not existing”.

# Additional Changes

N/A

# Additional Context.
Closes https://github.com/zitadel/zitadel/issues/12397

---------

Co-authored-by: Copilot Autofix powered by AI <[email protected]>
Co-authored-by: Livio Spring <[email protected]>
2026-07-13 09:22:31 +02:00
77169181a3 feat: get/list Zitadel IdP (#12394)
# Which Problems Are Solved

This PR extends the functionality of `GetProviderByID`, `ListProviders`
v1 endpoints and `GetIDPByID` v2 endpoint to also return Zitadel IdP
when queried.

# How the Problems Are Solved

- Add `PROVIDER_TYPE_ZITADEL` and a `ZitadelConfig` to
`zitadel.idp.v1.ProviderConfig` (v1 APIs).
- Add `IDP_TYPE_ZITADEL`, `ZitadelConfig`, `InstanceRolesInfo` in v2
`idp.proto`
- Extend internal/query IDP template querying to include a
`ZitadelIDPTemplate` (incl. issuer, client credentials, scopes, instance
roles info).
- Add/extend integration tests for updating + fetching providers by ID
and listing providers.

# Additional Changes
N/A

# Additional Context
Closes https://github.com/zitadel/zitadel/issues/12051

---------

Co-authored-by: Copilot Autofix powered by AI <[email protected]>
2026-07-10 09:17:49 +02:00
9d60e83d6f Merge commit from fork
* Use slices.Contains over custom function

* Correctly remove roles from granted roles

* fix(setup): repair user grants with stale roles (GHSA-v859-c572-qh5p)

Add setup step 73 that reconciles existing user grants whose roles were
left too broad by the buggy cascade removal in removeRoleFromUserGrant.
The corruption lives in the eventstore event payloads, so the step pushes
a corrective user.grant.cascade.changed event per affected grant (roles
intersected with the currently valid set) and re-triggers the user grant
projection. Runs in the second setup slice, after the projection tables
it reads have been created.

Co-Authored-By: Claude Opus 4.8 <[email protected]>

* fix(setup): scope GHSA-v859-c572-qh5p repair to grant-based user grants

Direct user grants can never be hit by this bug (only ChangeProjectGrant's
multi-role cascade to grant-based grants can trigger it), so drop the
direct-grant branch from the finder query to avoid stripping unrelated,
legitimate roles that merely mismatch for other reasons (e.g. stale
role_key drift). Also exclude removed instances from the migration scope,
and log the number of grants fixed per instance.

Co-authored-by: Cursor <[email protected]>

---------

Co-authored-by: Claude Opus 4.8 <[email protected]>
Co-authored-by: Livio Spring <[email protected]>
Co-authored-by: Cursor <[email protected]>
2026-07-09 13:28:09 +02:00
942607e0e9 feat: implement UpdateZitadelProvider in ManagementService (#12384)
# Which Problems Are Solved

This PR adds support for updating ZITADEL identity provider (IDP)
templates.

# How the Problems Are Solved

- Implements `UpdateZitadelProvider` in the Management gRPC server plus
converter
- Introduces an org-scoped `ZitadelIDPChanged` event and registers its
event mapper.
- Adds command-side support to update org Zitadel providers and appends
the new event to the org write model.
- Extends the IDP template projection reducer to accept org change
events.

# Additional Changes
N/A

# Additional Context
Closes https://github.com/zitadel/zitadel/issues/11922
Follow up for PRs:

- https://github.com/zitadel/zitadel/pull/12018
- https://github.com/zitadel/zitadel/pull/12020
- https://github.com/zitadel/zitadel/pull/12055
- https://github.com/zitadel/zitadel/pull/12056
- https://github.com/zitadel/zitadel/pull/12371
- https://github.com/zitadel/zitadel/pull/12378

---------

Co-authored-by: Copilot Autofix powered by AI <[email protected]>
Co-authored-by: Livio Spring <[email protected]>
2026-07-07 04:32:18 +00:00
653a968d91 feat: implement instance-level UpdateZitadelProvider (#12378)
# Which Problems Are Solved

This PR implements the instance-level `UpdateZitadelProvider` endpoint,
enabling updates to existing instance Zitadel IdP templates.

# How the Problems Are Solved

- Added `AdminService.UpdateZitadelProvider` handler, converter
- Added the command-layer implementation to update a ZitadelProvider and
push `instance.idp.zitadel.changed` event
- Added projection-layer implementation to persist Zitadel provider
updates into `projections.idp_templates6_zitadel`
- Added unit and integration tests


# Additional Changes
N/A

# Additional Context
Related to https://github.com/zitadel/zitadel/issues/11922
Follow-up for PRs:
- https://github.com/zitadel/zitadel/pull/12018
- https://github.com/zitadel/zitadel/pull/12020
- https://github.com/zitadel/zitadel/pull/12055
- https://github.com/zitadel/zitadel/pull/12056
- https://github.com/zitadel/zitadel/pull/12371

---------

Co-authored-by: Copilot Autofix powered by AI <[email protected]>
2026-07-06 10:18:35 +02:00
Livio SpringandGitHub 1e0b810dca feat: allow managing invite code in secret generators (#12109)
# Which Problems Are Solved

Zitadel exposes the secrets generator configuration through its admin
api. This allows instance admins to manage them on their own and they
can create overwrite the system / runtime defaults (incl. expiration).
This very much needed in multi-instance scenarios such as zitadel.cloud.
Currently the invite code configuration was not manageable through the
API, but only runtime config.

# How the Problems Are Solved

- added the `invite_code` type to the API allowing it to be set and
retrieved.
- added the type to console's management list
- added the type to be stored on instance setup
- change the `GetSecretGenerator` endpoint to fall back to the runtime
config if no config is stored on the instance itself
- ensure the `length` and at least one charset is enabled, return an
error otherwise
- expiry is not enforced, so 0 allows codes with no expiry (current
state)

# Additional Changes

None

# Additional Context

- closes https://github.com/zitadel/zitadel/issues/10474
2026-07-01 04:53:16 +00:00
8e82ec1cb9 Merge commit from fork
* Add DenyLists parsing

* Remove unneeded returned error

* Plug global denylist into Command

* app creation: apply denylist to backchannel logout URI

* Inject denylist to backchannel logout worker

* webhook config: validate against blocked URLs

* Add notificationsWebhook denylist target

* command: Add SMTP endpoint validation against blocklist

* command: Add SMS endpoint validation against blocklist

* Validate webhook endpoint against denylist on channel notification

* Remove unused tests

* handle deprecated denylists

* remove unintended denylist entry in deprecated list

* use single http client

* fix tests

* update comments

* fixes

* cleanup

* address comments

* fix merge

---------

Co-authored-by: Livio Spring <[email protected]>
2026-06-15 15:36:14 +02:00
Livio SpringandGitHub d184e976fc Merge commit from fork
* feat(jwt idp): manage and validate audience

* translations

* fix tests

* address comments

* update migration version

* fix merge
2026-06-15 15:27:47 +02:00
25e263394e chore: update passwap v0.12.1 and align hash validation defaults/errors (#12179)
# Which Problems Are Solved

- Upgrading to `zitadel/passwap` v0.12.1 introduced new encoded-hash
validation paths that still had review feedback open.
- Secret hasher defaults were internally inconsistent (`Hasher.Cost: 4`
vs `Limits.Bcrypt.MinCost: 10`), which could reject hashes created by
the configured hasher.
- New validation error IDs/messages and test coverage needed to be
aligned with project conventions and expected behavior branches.

# How the Problems Are Solved

- Kept the dependency upgrade to `zitadel/passwap` v0.12.1 and completed
the validation integration.
- Updated `ValidateEncodedHash` error handling in
`internal/crypto/passwap.go` to:
  - use unique random-style error IDs,
  - return `Errors.Hash.NotSupported` for no-verifier cases,
  - keep invalid-hash branches mapped to invalid argument errors.
- Expanded `TestHasher_ValidateEncodedHash` in
`internal/crypto/passwap_test.go` to cover and assert:
  - bounds error branch,
  - no-verifier branch,
  - generic invalid-hash branch,
  - expected ZITADEL error IDs/messages.
- Restored lost inline verifier-context comments for argon2 and md5plain
verifier entries.

# Additional Changes

- Added the missing explanatory `Limits` comment for `SecretHasher` in
`cmd/defaults.yaml`.
- Corrected `SecretHasher.Limits.Bcrypt.MinCost` from `10` to `4` to
match the configured default bcrypt cost and avoid configuration
footguns.

# Additional Context

- Follow-up for PR review feedback in
https://github.com/zitadel/zitadel/pull/12179#pullrequestreview-4313121965

---------

Co-authored-by: copilot-swe-agent[bot] <[email protected]>
Co-authored-by: Livio Spring <[email protected]>
2026-06-05 14:48:35 +02:00
f85a2373c5 chore(test): streamline integration tests for instance management (#12243)
- Removed redundant relational instance handling in integration tests
for adding and removing custom domains.
- Simplified test cases by consolidating instance creation and context
management.
- Enhanced clarity and maintainability of test logic by reducing
complexity in test structures.

# Which Problems Are Solved

`backed/v3` tests are flaky, but the code is not productive. Development
is paused for the moment. Disabling flaky tests helps us to maintain the
product easier.

# How the Problems Are Solved

- Removed redundant relational instance handling in integration tests
for adding and removing custom domains.
- Simplified test cases by consolidating instance creation and context
management.
- Enhanced clarity and maintainability of test logic by reducing
complexity in test structures.newly introduced terms).

# Additional Context

- related to https://github.com/zitadel/zitadel/pull/12241

---------

Co-authored-by: Livio Spring <[email protected]>
Co-authored-by: Copilot Autofix powered by AI <[email protected]>
2026-06-05 11:36:45 +00:00
Marco A.andGitHub 14acc60edd feat: ListSessions to relational (#11987)
# Which Problems Are Solved

This PR introduces the possibility of using the relational DB when
calling the ListSession gRPC endpoint.

# How the Problems Are Solved

  - Implement the Querier interface for ListSession:
- Create a `domain` model for the Session object to be able to map the
gRPC session into it.
- Match the permission filters on ES side to be sure the same sessions
are returned
- Implement converter methods to go from `gRPC` to `domain` models (both
ways)
- Fix the session sql relational migration: rework the trigger to update
the `expiration` field to perform the update only when the input
`lifetime` has a non-zero value.
  - Link the Querier implementation with the gRPC endpoint
- Run the same integration tests against the relational DB, making sure
the outcome is the same. ⚠️ Due to missing permission checks, some
divergence is expected. Hence, specific code to circumvent the
differences has been put in place

# Additional Context

- Closes #11039
2026-04-16 10:58:17 +02:00
Tim MöhlmannandGitHub 177589a0a8 fix(grpc): increase MaxSendMsgSize (#12066)
# Which Problems Are Solved

Users exporting larger orgsanizations were facing grpc message size
limits of 4 MiB, while trying to export 6.3 MiB of data. Other export
methods like S3 aren't implemented.

# How the Problems Are Solved

Set MaxSendMsgSize to 10 MiB (allow some overhead). This is not a
long-term solution and we should investigate better ways of export.

# Additional Changes

- none

# Additional Context

- Support ticket
2026-04-15 13:04:22 +00:00
Gayathri VijayanandGitHub e19bb7a173 feat: implement AddZitadelProvider in ManagementService (#12056)
# Which Problems Are Solved

This PR adds implementation to add a Zitadel IdP at the
organization-level.

# How the Problems Are Solved
- Added handling/converters for the `AddZitadelProvider` endpoint in
`ManagementService` in the server layer
- Registered a new `org.idp.zitadel.added` event for org-level Zitadel
providers
- Added `AddOrgZitadelProvider` command to validate the request and push
`org.idp.zitadel.added` event to the eventstore
- Added the `org.idp.zitadel.added` event to the projection reducer
- Added unit and integration tests

# Additional Changes
added more tests for the ZitadelProvider in AdminService

# Additional Context
- Closes https://github.com/zitadel/zitadel/issues/11823
- Follow-up for PRs https://github.com/zitadel/zitadel/pull/12018,
https://github.com/zitadel/zitadel/pull/12020,
https://github.com/zitadel/zitadel/pull/12055
2026-04-15 14:22:45 +02:00
7b9d2b7d17 feat: add administrator role permission table (#11817)
This update introduces a new table for managing administrator role
permissions, along with the necessary repository and projection logic to
handle adding and removing permissions. It also includes tests to ensure
the correct functionality of the permission management system.

closes https://github.com/zitadel/zitadel/issues/10219

---------

Co-authored-by: Marco Ardizzone <[email protected]>
2026-04-14 06:01:52 +00:00
bb3b52dda3 feat: command layer implementation for AddZitadelProvider (#12020)
# Which Problems Are Solved

This PR contains the command-layer implementation to add an instance IDP
of the type `ZitadelProvider`

# How the Problems Are Solved
- Implementing `AddZitadelProvider` in AdminService 
- Adding the command-layer to create a `ZitadelProvider` and push
`ZitadelIDPAddedEvent`

# Additional Changes
N/A

# Additional Context
- Related to https://github.com/zitadel/zitadel/issues/11823
- Follow-up for PR https://github.com/zitadel/zitadel/pull/12018

---------

Co-authored-by: Copilot <[email protected]>
2026-04-13 15:05:36 +00:00
01fe34a526 fix(oidc): use authenticated encryption for opaque tokens (#12017)
# Which Problems Are Solved

Opaque tokens now use authenticated encryption.

# How the Problems Are Solved

- Upgrade zitadel/oidc to v3.47
- Copy crypto implementation for refresh and session tokens (internal to
zitadel)
- Added config that allows validating old tokens for gradual roll-out

# Additional Changes

- Set NX cache for `integration-test-build` to `false`, working on a
seperate fix.

# Additional Context

- closes #11315

---------

Co-authored-by: copilot-swe-agent[bot] <[email protected]>
Co-authored-by: muhlemmer <[email protected]>
2026-04-13 10:59:50 +00:00
a2bf528ca0 feat(domain): introduce error slugs (#12030)
# Which Problems Are Solved

As part of https://github.com/zitadel/zitadel/issues/11917 we want to
introduce error slugs so (API) clients can rely on stable,
machine-readable errors and act accordingly.

# How the Problems Are Solved

- Added a `NewSlug` helper function in the domain package.
- Added `ErrorDetails` to the `ZitadelError`
- Added an `zitadel.error.v2.ErrorDetail` proto message
- Updated the connectRPC error interceptor to map new slug based errors
to the new `ErrorDetail`
- Defined some common slugs and error functions like internal errors
- Defined (session) specific slugs used in the `DeleteSession` and
`CheckUser` functions and replaced old implementations
- Updated integration tests to check specific errors if the relation
database feature is enabled
- Updated doc and guideline to reflect the latest changes and decisions
- Updated DeleteSession endpoint API to list possible slugs

# Additional Changes

None

# Additional Context

- closes #11957

---------

Co-authored-by: Wim Van Laer <[email protected]>
2026-04-13 09:47:04 +02:00
fbd43ced6e fix(grpc): return 401 for unauthenticated v1 gateway errors (#11786)
Fixes #11730

The v1 gRPC middleware can return native gRPC status errors such as
`codes.Unauthenticated` when the auth header is missing.

Those errors were being passed through the generic gRPC error converter,
which only handled ZITADEL errors and downgraded raw gRPC statuses to
`codes.Unknown`.

Through grpc-gateway that caused `/auth/v1/users/me` to return HTTP 500
instead of HTTP 401.

So this change preserves native gRPC status errors in
`ZITADELToGRPCError`, keeps `ExtractZITADELError` aligned with those
transport codes for activity reporting, and adds regression coverage for
the converter, middleware, and gateway HTTP behavior.

---------

Co-authored-by: Gayathri Vijayan <[email protected]>
2026-04-10 12:22:40 +00:00
Vitor Bari BucciantiandGitHub 035ac4b9a2 fix(api): Add dummy implementation of new LinksSettings APIs to satisfy SettingsServiceHandler interface (#12034)
# Which Problems Are Solved

#11975 introduces new APIs to `SettingsService`, however,
`settingsconnect.SettingsServiceHandler` wasn't updated to satisfy the
interface containing the new APIs.

# How the Problems Are Solved

By adding a dummy implementation of new RPC methods to the
SettingsService Server.

# Additional Changes

n/a 

# Additional Context

n/a
2026-04-10 13:57:32 +02:00
Mridang AgarwallaandGitHub ce31ee2272 fix: propagate non-NotFound errors from instance interceptor (#12019) 2026-04-10 08:22:56 +00:00
ec7a6d5526 fix: make recovery code active on add (#11734)
# Which Problems Are Solved

- Recovery codes added via `GenerateRecoveryCodes` were never listed as
active authentication methods by `ListAuthenticationMethodTypes`. The
`user_auth_method` projection reducer (`reduceInitAuthMethod`) set the
state to `MFAStateNotReady`, expecting a subsequent verification event
to transition it to `MFAStateReady`. Unlike TOTP, U2F, and Passwordless
— which all have distinct verification events — recovery codes have no
such event, so they were permanently stuck in `NotReady`.

# How the Problems Are Solved

- Introduced a dedicated `reduceAddRecoveryCodes` reducer for
`HumanRecoveryCodesAddedEvent` that sets `MFAStateReady` immediately,
since recovery codes are usable as soon as they are generated.
- Uses `NewUpsertStatement` (instead of `NewCreateStatement`) so that
regenerating recovery codes for the same user updates the existing row
rather than failing on a duplicate key conflict.
- Removed the `HumanRecoveryCodesAddedEvent` case from
`reduceInitAuthMethod`.

# Additional Changes

- Added `UserAuthMethodTypeRecoveryCode` mapping in `authMethodTypeToPb`
unit test.
- Added integration tests for `ListAuthenticationMethodTypes` covering
both the "recovery codes present" and "recovery codes removed" cases.

# Additional Context

* https://github.com/zitadel/zitadel/issues/11317

---------

Co-authored-by: Marco A. <[email protected]>
Co-authored-by: Cursor <[email protected]>
2026-03-27 09:47:16 +00:00
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 <[email protected]>
2026-03-19 08:35:53 +01: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 <[email protected]>
Co-authored-by: muhlemmer <[email protected]>
Co-authored-by: Copilot Autofix powered by AI <[email protected]>
Co-authored-by: Marco A. <[email protected]>
2026-03-18 14:07:33 +01: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 <[email protected]>
Co-authored-by: Max Peintner <[email protected]>
2026-03-17 12:54:27 +01:00
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. <[email protected]>
2026-03-16 14:30:17 +00:00
Wim Van LaerandGitHub 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
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 <[email protected]>
2026-03-12 16:01:58 +00:00
Livio SpringandGitHub 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
Livio SpringandGitHub ab51fd9563 Merge commit from fork 2026-03-11 08:12:46 +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 <[email protected]>
Co-authored-by: Gayathri Vijayan <[email protected]>
2026-03-10 10:09:51 +00:00
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 <[email protected]>
2026-03-09 10:47:32 +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 <[email protected]>
Co-authored-by: Copilot <[email protected]>
2026-03-06 14:57:52 +01:00
5934e07960 fix: recover from request panics (#11713)
# Which Problems Are Solved

Panics may cause a service discruption by unexpectedly closing an
request's connection. Or in the case of gRPC completely killing the
service.

Allthough panics are still individual bugs that need to be solved, this
PR makes sure a panic is gracefully handled and an understandable error
is returned to the client.

# How the Problems Are Solved

- Recover in the middleware interceptors for the 3 API protocols (HTTP,
gRPC, connect).
- HTTP middleware uses formatted responses for:
  - OIDC errors (JSON formatted response)
  - UI (error page rendering)
  - SCIM
- Upon recovery an alert level log is printed (ERROR+4 for stdlib log
handlers)

# Additional Context

- internal observation

---------

Co-authored-by: Livio Spring <[email protected]>
Co-authored-by: Livio Spring <[email protected]>
2026-03-03 11:55:17 +00:00
Marco A.andGitHub bebee4c795 chore: naming consistency - Organization ID (#11733)
# Which Problems Are Solved

Renaming of:

  - Resource Owner
  - OrgID
  - OrganizationID
  - Organization Id

# How the Problems Are Solved

Find & Replace, evalue entries, is resource owner referring to an
organization ? If so, do change

# Additional Context

- Closes #11305
2026-03-03 10:24:44 +00:00
4aacfa842f feat: set metadata at the user level in CreateUser request (#11719)
# Which Problems Are Solved

Currently, metadata can be set/updated only for human users, but it
should be available also for service accounts (machine users).

# How the Problems Are Solved

This is achieved by:
- adding a metadata field at the root level in `CreateUserRequest`,
which makes it available for both `human` and `machine` user types
- returning an error when both the root level and human-level `metadata`
fields are set in the `CreateUserRequest`
- setting `human` and `machine` metadata from the root `metadata` field
in the server layer
- pushing `user.metadata.set` event during machine user creation in the
command layer
- adding integration tests

# Additional Changes
N/A

# Additional Context
- Related to https://github.com/zitadel/zitadel/issues/11369

---------

Co-authored-by: Vitor Bari Buccianti <[email protected]>
Co-authored-by: Silvan <[email protected]>
2026-03-03 08:34:43 +00:00
e9e6ad4e17 fix(test): resolve nil-pointer panic in TestCommandSide_ChangeUserHuman (#11695)
# Which Problems Are Solved

1. `nx run @zitadel/api:test-unit` panics in
`TestCommandSide_ChangeUserHuman` due to two test cases (added in
0261536) missing the required `loginPaths` field. Since the field type
is `func(*testing.T) LoginPaths`, its zero value is `nil`, and calling
it causes a SIGSEGV.

2. Three targets in `apps/api/project.json` (`test-unit`, `build`,
`build-linux`) were silently non-cacheable because NX does not merge
`cache: true` from `targetDefaults` when a project-level target
overrides other properties like `dependsOn` or `inputs`.

3. `TestServer_AuthorizeOrDenyDeviceAuthorization` integration test is
flaky — it uses hardcoded `5*time.Second` timeouts for `EventuallyWithT`
polling, while the rest of the file uses
`WaitForAndTickWithMaxDuration(ctx, time.Minute)`. Under CI load, 5
seconds is insufficient and the empty ID cascades into a validation
error.

# How the Problems Are Solved

**Test panic fix:**
- Added missing `loginPaths: expectLoginPathsNoCall` to both broken test
cases ("change human email verified (self-management), not allowed" and
"change human phone verified (self-management), not allowed").

**NX cache fix:**
- Added explicit `"cache": true` to `test-unit`, `build`, and
`build-linux` targets in `apps/api/project.json`.
- Verified with `pnpm nx show project @zitadel/api --json` that all
three targets now resolve with `cache: true`.

**Integration test flakiness fix:**
- Replaced all 6 hardcoded `assert.EventuallyWithT(t, ...,
5*time.Second, 100*time.Millisecond)` calls in
`TestServer_AuthorizeOrDenyDeviceAuthorization` with
`require.EventuallyWithT(t, ..., retryDuration, tick)` using
`integration.WaitForAndTickWithMaxDuration(CTXLoginClient,
time.Minute)`.
- Changed from `assert` (non-fatal) to `require` (fatal) so timeout
failures stop the test immediately instead of cascading with empty IDs.

# Additional Context

- The broken unit test landed on main because CI skips `lint_test_build`
on pushes to main (`if: github.ref != 'refs/heads/main'`). A follow-up
issue was created: #11696.
- The integration test flakiness was missed by the previous fix in
#10752.

---------

Co-authored-by: Copilot <[email protected]>
Co-authored-by: Livio Spring <[email protected]>
2026-02-26 05:47:01 +00:00
Livio SpringandGitHub 0261536243 Merge commit from fork 2026-02-25 06:34:17 +01:00
Marco A.andGitHub b2532e9666 Merge commit from fork
* Inject DenyList from config to `StartCommands()`

* Implementation draft

* Move address checker to separate package

* Migrate usages of actions.AddressChecker to denylist.AddressChecker

* Rename denylist package files

* Pass []denylist.AddressChecker to StartCommand

* Add DenyList to defaults.yaml and add custom config parser

* net: add HostnameToIPList function

* denylist: Add IsHostBlocked()

* actions: use denylist.IsHostBlocked()

* command: Inject ip lookup function + extend add target validationt test

* command: Unexport ChangeTarget.IsValid()

* command: Add denyList check on ChangeTarget validation

* command: Export ActionsV2DenyList and IPLookupFunction params

* Lint fix

* Check denylist during action execution

* Fix integration tests

* Apply suggestions

* Add `mapstructure.StringToSliceHookFunc()` to decode `HTTPConfigDecodeHook`
2026-02-25 06:33:28 +01:00
Gayathri VijayanandGitHub 6ad1ef859b fix: set refresh token in the RetrieveIdentityIntentResponse (#11613)
# Which Problems Are Solved

This PR adds support for storing and retrieving refresh tokens from
external identity providers during the IDP intent flow.

# How the Problems Are Solved

* Updated `idp.proto` (v2 and v2beta): added an optional `refresh_token`
field to `IDPOAuthAccessInformation`, which, in turn, is used in
`RetrieveIdentityProviderIntentResponse`
* Added the `IDPRefreshToken` field to the IDP intent `SucceededEvent`
struct, and updated the corresponding constructor to set the refresh
token
* Added the `IDPRefreshToken` field to `IDPIntentWriteModel`, and
updated `reduceOAuthSucceededEvent` to populate refresh token from
events
* Updated `tokensForSucceededIDPIntent` function to extract and encrypt
the refresh token from IDP session, if set
* Updated `idpOAuthTokensToPb` function to decrypt refresh token before
returning to clients
* Updated unit and integration tests

# Additional Changes
Updated the link to the JWT IDP docs linked in the Console

# Additional Context
- Closes https://github.com/zitadel/zitadel/issues/11047
2026-02-19 06:06:30 +00:00
e41b70b1e3 feat(api): allow specifying access token type for user of type machine (#11599)
# Which Problems Are Solved

The user service v2 didn't allow the specify or change the access token
type for users of type machine and referred to using the management API,
which in return was already deprecated and linked to the user service.

# How the Problems Are Solved

Added a possibility to specify the access token type in the creation and
update request.

# Additional Changes

None

# Additional Context

- closes #10850
- requires backport to v4.x

---------

Co-authored-by: Copilot <[email protected]>
2026-02-19 05:05:19 +00:00
ca6bd9d6a2 fix: added login_hint to the idp intent (#11552)
# Which Problems Are Solved

In login V2, when the user started the login flow of an external IDP,
there was no login_hint passed to the external provider. This required
the user to enter their username again. Whilst they already entered it
in Zitadel. By adding the `login_hint` parameter, the username should
already be filled in on the external idp.

# How the Problems Are Solved

Pass the `login_hint` parameter to the external idp.

# Additional Changes

Also added the `login_hint` to the event-store for audit trailing.

# Additional Context


- Closes #11392

---------

Co-authored-by: Copilot <[email protected]>
2026-02-13 14:34:32 +00:00
Marco A.andGitHub 382aec2d61 chore: Service Account Naming Consistency (#11557)
# Which Problems Are Solved

Inconsistent naming of service account, found in the following
variations:

  - Machine User
  - machine user
  - Service User
  - Machine Account
  - Technical Account
  - User: Type Machine

# How the Problems Are Solved

Attentive search and replace.

Localizations have been translated using Copilot

# Additional Changes

Some unused methods have been removed from the Go code.

# Additional Context

- Closes #11285
2026-02-13 12:31:43 +01:00
b0609aa861 feat(api): return allowed_languages (#11553)
# Which Problems Are Solved

While Zitadel provides a possibility to restrict certain languages to be
used, the corresponding list could not be retrieved in the settings
service (v2). This blocked login v2 implementations from respecting the
list and they would always use all available languages.

# How the Problems Are Solved

- Retrieve the list when checking the instance and pass it into the
context.
- Return it as part of the existing `GetGeneralSettingsResponse`
- This allows us to remove an additional query in some other cases /
endpoints.

# Additional Changes

none

# Additional Context

- required for https://github.com/zitadel/zitadel/pull/11372
- backport to v4.x

---------

Co-authored-by: Copilot <[email protected]>
Co-authored-by: Marco A. <[email protected]>
2026-02-12 08:44:34 +00:00
Wim Van LaerandGitHub e98aa10892 fix: return auth none when no auth is configured for smtp + scopes in grpc response (#11554)
# Which Problems Are Solved

- When no auth was present on a smtp configuration, the `auth` field was
`nil` on the response while it should be `none`.
- Scopes were not properly retrieved from the database resulting in all
scopes being combined in one scope when retrieving the configuration.

# How the Problems Are Solved

- Set `auth` to `none` when no auth is configured
- Use `database.TextArray[string]` as type to get the scopes from the
database

# Additional Changes

# Additional Context
2026-02-11 11:48:41 +01:00
5a2181bcec chore: rename IAM to instance (#11351)
# Which Problems Are Solved

In many cases IAM was used where instance was meant. 

# How the Problems Are Solved

- Rename wrong usage of IAM to instance all over the code base.
- Add an agents.md which explains the terms used in Zitadel's
architecture.

# Additional Context

- closes #11280

---------

Co-authored-by: Copilot <[email protected]>
Co-authored-by: muhlemmer <[email protected]>
Co-authored-by: Copilot <[email protected]>
Co-authored-by: Marco A. <[email protected]>
2026-02-10 20:25:39 +01:00
1f0d54a978 chore(docs): User (Human) naming consistency (#11512)
# Which Problems Are Solved

Naming inconsistencies - User (Human)

# How the Problems Are Solved

Most of the occurrences have not been changed. `User (Human)` was mostly
changed when talking about code objects and where I felt it was
necessary to distinguish them from machine users.

When both human and machine user occurrences were found, the machine
user has been changed to service account (see
https://github.com/zitadel/zitadel/issues/11285)

# Additional Context

- Closes #11284

---------

Co-authored-by: Wim Van Laer <[email protected]>
2026-02-06 09:46:24 +00:00
Wim Van LaerGitHub[TheRobotCarlson](https://github.com/TheRobotCarlson)Warp [[email protected]](mailto:[email protected])Brian CarlsonWarp
944765f89c fix(api): honor request-provided IDs for OIDC apps (#11506)
Problem:
OIDC CreateApplication requests in both app/v2beta and application/v2
accept an ID field (id / application_id), but the OIDC creation path
dropped it, always generating a new app ID/client ID.

Changes:

Thread the request-provided ID into the OIDC domain request in both
handlers.
Update the OIDC command path to use the provided AppID when present
(fallback to generated ID when empty), mirroring API apps.
Add integration tests covering provided IDs for OIDC CreateApplication
on v2beta and v2.
Tests:

go test -count=1 -tags integration
./internal/api/grpc/app/v2beta/integration_test -run
TestCreateOIDCApplication_WithProvidedID
go test -count=1 -tags integration
./internal/api/grpc/application/v2/integration_test -run
TestCreateOIDCApplication_WithProvidedID

Co-Authored-By: [TheRobotCarlson](https://github.com/TheRobotCarlson)
Co-Authored-By: Warp [[email protected]](mailto:[email protected])

---------

Co-authored-by: Brian Carlson <[email protected]>
Co-authored-by: Warp <[email protected]>

---------

Shoutout: [TheRobotCarlson](https://github.com/TheRobotCarlson)
Shoutout: [ostempel](https://github.com/ostempel)
2026-02-05 16:05:02 +01:00
Livio SpringandGitHub ce30a5a98e feat(oidc): move back-channel logout from beta to GA (#11493)
# Which Problems Are Solved

This PR marks the OIDC Back-Channel Logout as general available (GA).

# How the Problems Are Solved

- API:
- deprecated the feature toggle (to prevent breaking changes) in v2beta
and v2 API
  - removed all related event logic and updated the projection iteration
  - removed the toggle usage for back-channel logout
  - removed related translations
- Management Console:
  - removed the feature toggle and its translations
- Docs:
  - removed all beta labels and feature toggle notes

# Additional Changes

none

# Additional Context

- closes #11277 
- requires backport to v4.x
2026-02-05 10:51:09 +00:00
4936bdf2c9 feat(rt): IDP Intents Relational Table (#11374)
# Which Problems Are Solved

In the context of moving our datastore to relational tables, Identity
Provider Intents have no definition of a relational table nor any DB API
that can be used to store the IDP intents as relational objects.

# How the Problems Are Solved

The PR follows the guidelines left in #11190

- A table `zitadel.identity_provider_intents` is created: it defines its
relational constraints (foreign keys) with the other tables, as well as
an ENUM to represent the state of the intent.
- An IDP Intent repository has been created, which offers CRUD
operations implemented as `Create`, `Get`, `Update` and `Delete` methods
for the IDP intent.
- The repository also defines all columns and conditions useful for
performing DB operations on the IDP intents.
- DB mocks have been added as well to ease testing on the `domain`
package.
- Reduction functions have been implemented for the existing IDP events
so to keep the relational table in sync with the event store.

# Additional Changes

To allow testing LDAP intent flow, the `Session.FetchUser()` method has
been extracted to a separate file. A corresponding mock has been created
as well in `fetch_user_mock.go`. The files are mutually excluded and
added at build time through go build tags: the mock is added when the
`integration` tag is specified, while the real implementation is added
when the same tag IS NOT added to the build tags.

# Additional Context

- Closes #11190

---------

Co-authored-by: Livio Spring <[email protected]>
Co-authored-by: Silvan <[email protected]>
2026-02-05 03:44:07 +00:00
11dbb1b277 feat(logging): add streams (#11435)
# Which Problems Are Solved

Streams allow differentiating logs produced by different components of
Zitadel.

# How the Problems Are Solved

The `backend/v3/instrumentation/logging` package now exposes convenience
function for setting and getting a logger from the context. As well as
high-level functions to emit log records at various levels. When
constructing a new logger a "stream" needs to be specified:

- **runtime**: General runtime logs, such as startup and shutdown
messages. Default for logs that do not belong to the other categories.
- **request**: Logs for incoming API and HTTP requests.
- **event_handler**: Logs for event handling in projections.
- **queue**: Logs for the job queue processing.
- **event_pusher**: Logs for event pushing to the database. Disabled by
default, contains sensitive information.

Each line from the returned logger contains a `stream` field as well as
a `version` field with the current Zitadel version.

## Runtime config

Streams can be enabled by passing an array of stream names in the
runtime config. Because some log streams may contain sensitive data
(especially events), it is now also possible to mask values by their
key.

# Additional Changes

- Wrap `slogctx` in the `logging` package. (Except API error converter
packages, because of import cycle)
- Add some docs to `logging` package so other devs understand how to add
logging to Zitadel
- Add `logging.OnError` and `logging.WithError` helper functions with
`Panic()` and `Fatal()` methods, to preserve current calls in the `cmd`
packages.
- Add instance context extractor.
- Only output request details in the request info log. Request ID
remains propagated through context.
- Moved middleware functionality into protocol specific packages. 
- Removed setting of URI to context in metric middleware. There were ony
setters and no getters. (Unused value)
- Reuse a single statusWriter in the middleware package for middlewares
that need to know the response status.

# Additional Context

- Closes #11333
- Closes #11331 
- Partly #11330

---------

Co-authored-by: Silvan <[email protected]>
2026-02-04 11:51:43 +01:00