# Which Problems Are Solved
This PR adds support for using a ZITADEL IdP provider in the login v1 UI
flow and conditionally grants a support-user instance membership based
on a ZITADEL-specific project-roles token claim.
# How the Problems Are Solved
- Introduced ZITADEL IdP handling in the login v1 handler, including
extracting the `urn:zitadel:iam:org:project:roles` claim and granting
`IAM_OWNER_VIEWER` instance membership when configured orgs match.
- Added a new `AddInstanceMemberFromLogin` to assign an instance
membership during the login v1 ZITADEL-IdP flow without permission
checks (as the authorization is established based on the project roles
in the token claim)
- Added unit tests
# Additional Changes
N/A
# Additional Context
- Closes https://github.com/zitadel/zitadel/issues/12446
<!-- CURSOR_AGENT_PR_BODY_BEGIN -->
## Summary
`ListUsers` with `LoginNameQuery` + equals/equals-ignore-case was very
slow on large orgs (e.g. ~330k users) because the generated SQL filtered
the `projections.login_names3` **view** on the computed
`login_name_lower` expression and correlated that subquery on
`users14.id`. Postgres nested-looped every user and never used
`login_names3_users_search (instance_id, user_name_lower)`.
This change rewrites the **query planner** for that hot path: when an
equals/equals-ignore-case login-name filter is present (and not under
`OR`/`NOT`), the user list query **INNER JOINs** an indexed matches
subquery instead of filtering via the view expression. The matches SQL
mirrors `user_by_login_name.sql` (`user_name_lower` / domain paths +
`preferred` / `is_primary`).
Non-equals methods and OR combinations keep the previous view-based
filter so semantics stay unchanged.
Also adds a k6 use case that mirrors login v2 discovery
(`loginNameQuery` EQUALS_IGNORE_CASE + `organizationIdQuery`, `limit:
2`):
```bash
cd benchmark
make users_by_login_name USER_AMOUNT=100000 VUS=10 DURATION=60s
```
## Approach
1. `NewLoginNameSearchQuery` for equals / equals-ignore-case returns a
marker `loginNameEqualsFilter` (other methods unchanged).
2. `prepareUsersQuery` extracts that marker when safe, then:
- builds the usual `sq.SelectBuilder` **without** the login-name view
predicate
- adds `JoinClause` to `user_login_name_matches(.sql)` /
`_case_sensitive.sql` as `login_name_matches`
- keeps metadata JOIN/`DISTINCT` only when metadata filters are present
(same as before)
3. Embedded SQL files under `internal/query/` for the matches subquery.
Local smoke against ~330k synthetic users: baseline ~1392ms → rewritten
path ~0.4ms for a single equals-ignore-case lookup.
## Test plan
- [x] `go test ./internal/query/ -run
'TestLoginName|TestUsers|TestUserByLoginName'` (after generate-stubs)
- [x] Existing `user_test` expected SQL updated (no always-on metadata
join; login-name equals uses JOIN)
- [ ] Run k6 before/after on a large `USER_AMOUNT` (e.g. 50k–100k+) and
compare `list_users_duration` p50/p95/p99
- [x] Manual login v2 username discovery against a large org
- [x] Confirm OR / NOT / CONTAINS login-name queries still return
expected results
<!-- CURSOR_AGENT_PR_BODY_END -->
<div><a
href="https://cursor.com/agents/bc-252883bd-48d9-492e-b619-5ccfa93cf9c3"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://cursor.com/assets/images/open-in-web-dark.png"><source
media="(prefers-color-scheme: light)"
srcset="https://cursor.com/assets/images/open-in-web-light.png"><img
alt="Open in Web" width="114" height="28"
src="https://cursor.com/assets/images/open-in-web-dark.png"></picture></a> <a
href="https://cursor.com/background-agent?bcId=bc-252883bd-48d9-492e-b619-5ccfa93cf9c3"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://cursor.com/assets/images/open-in-cursor-dark.png"><source
media="(prefers-color-scheme: light)"
srcset="https://cursor.com/assets/images/open-in-cursor-light.png"><img
alt="Open in Cursor" width="131" height="28"
src="https://cursor.com/assets/images/open-in-cursor-dark.png"></picture></a> </div>
---------
Co-authored-by: Cursor Agent <[email protected]>
Co-authored-by: Silvan <[email protected]>
# Which Problems Are Solved
`GenerateRandomString` used for generating codes incl. OTP was
incorrectly ignoring the last rune of the possible set.
# How the Problems Are Solved
Refactored the function to get the full randomness.
# Additional Changes
None
# Additional Context
Thanks @AyushParkara for pointing this out.
# Which Problems Are Solved
This PR extends `StartIdentityProviderIntent` and
`RetrieveIdentityProviderIntent` for the new Zitadel provider.
# How the Problems Are Solved
- Added `domain.IDPTypeZitadel` cases to both the instance and org
switches in `NewAllIDPWriteModel` to return Zitadel provider when
`GetProvider` is called
- Added Zitadel provider to RetrieveIdentityProviderIntent's provider
type-switch
- Added new `zitadel.go` provider, an OIDC wrapper with forced PKCE
- Added unit/integration tests
# Additional Changes
# Additional Context
- Closes https://github.com/zitadel/zitadel/issues/12050
---------
Co-authored-by: Copilot Autofix powered by AI <[email protected]>
# Which Problems Are Solved
In Zitadel's append-only event-sourced architecture, the
`eventstore.events2` table grows indefinitely. PostgreSQL's default
autovacuum uses a percentage-based scale factor, so as the table grows,
the number of changed rows required to trigger a `VACUUM` or `ANALYZE`
drifts towards infinity. Without regular vacuums, the table's Visibility
Map becomes stale, disabling fast Index-Only Scans and forcing expensive
heap reads. Without regular analyzes, query planner statistics become
stale, leading to suboptimal execution plans.
This causes eventstore operations to progressively degrade as `events2`
grows, even without CPU, memory, or I/O saturation. A manual `VACUUM
ANALYZE` immediately restores performance, confirming the root cause.
- If `Eventstore.Autovacuum` is left at its default, `events2` keeps
using PostgreSQL's default, percentage-based autovacuum/autoanalyze
scale factors, which become impractically infrequent on large tables.
- There was previously no supported way to apply static, table-level
autovacuum tuning to `events2` through Zitadel's own configuration/setup
process.
# How the Problems Are Solved
- Added an `Eventstore.Autovacuum` runtime configuration block to
`cmd/defaults.yaml` (disabled by default):
```yaml
Eventstore:
Autovacuum:
Enabled: false # ZITADEL_EVENTSTORE_AUTOVACUUM_ENABLED
VacuumThreshold: 50000 # ZITADEL_EVENTSTORE_AUTOVACUUM_VACUUMTHRESHOLD
AnalyzeThreshold: 50000 # ZITADEL_EVENTSTORE_AUTOVACUUM_ANALYZETHRESHOLD
```
- Added a repeatable `zitadel setup` migration step
(`cmd/setup/eventstore_autovacuum.go`) that:
- When `Enabled: true`, disables the percentage-based
`autovacuum_vacuum_scale_factor`, `autovacuum_analyze_scale_factor`, and
`autovacuum_vacuum_insert_scale_factor` on `eventstore.events2`, and
applies static thresholds (`autovacuum_vacuum_insert_threshold`,
`autovacuum_vacuum_threshold`, `autovacuum_analyze_threshold`) from the
config instead.
- When `Enabled: false`, resets those storage parameters on
`eventstore.events2` back to the cluster defaults.
- Implements `Repeatable.Check()` so the step only re-runs when the
configuration actually changed since the last `zitadel setup` run.
- Added documentation in the new "Performance tuning" page.
# Additional Changes
- Move the projection documentation into performance tuning page
- Expand and update the projection documentation to the latest state in
zitadel. (contained some stale information)
# Additional Context
Several other issues describe read-performance symptoms consistent with
this same root cause (stale `events2` visibility map / planner
statistics at scale, without resource saturation). Since this PR
addresses the shared root cause:
- Closes#12448
- Closes#10754
- Closes#10260
- Closes#8585
- Closes#9239
---
_Generated by [Claude
Code](https://claude.ai/code/session_01HoKvEY7niCVgLCz7CajBwW)_
---------
Co-authored-by: Claude <[email protected]>
Co-authored-by: Copilot Autofix powered by AI <[email protected]>
Co-authored-by: Silvan <[email protected]>
# Which Problems Are Solved
Fixes i18n consistency and adds HU translations for login v2
# How the Problems Are Solved
- Updated i18n files and added hu.json
- Moved all translations to v2-default.json
---------
Co-authored-by: Dobos Zoltán <[email protected]>
Co-authored-by: Liam Neville <[email protected]>
# Which Problems Are Solved
This PR extends the Settings Login API (v2 and v2beta) to include
ZITADEL IdP in the list of IdPs returned by `GetActiveIdentityProviders`
# How the Problems Are Solved
- Added `IDENTITY_PROVIDER_TYPE_ZITADEL` to Settings
IdentityProviderType enums (v2 and v2beta) and updated domain display
name handling.
- Updated Settings gRPC converters (v2 and v2beta) to map
`domain.IDPTypeZitadel` to the new proto enum value
- Added unit/integration tests
# Additional Changes
Correctly map `domain.IDPTypeApple` to
`IdentityProviderType_IDENTITY_PROVIDER_TYPE_APPLE` in v2beta instead of
unspecified.
# Additional Context
- Closes https://github.com/zitadel/zitadel/issues/12401
---------
Co-authored-by: Livio Spring <[email protected]>
# 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]>
# 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]>
## Which Problems Are Solved
The v4.15.3 token exchange hardening (`#12319`, `#12322`) introduced two
regressions:
1. **Logic bug**: scope validation used intersection (`!inSubject ||
!inActor`) instead of union, so any explicit `scope` on a `user_id`
subject always failed — even `openid` when present on the actor token.
2. **Design gap**: even with union logic, scope-less subjects
(`user_id`, `id_token`) cannot satisfy a rule that requires all
requested scopes to exist on input tokens. This breaks documented
impersonation flows (e.g. service account actor + `user_id` subject
requesting `email`).
## How the Problems Are Solved
- **Standard exchange** (no actor, or subject carries scopes): keep
union validation — requested scopes must be ⊆ subject ∪ actor. For plain
exchange this is effectively a subset of the subject token.
- **Scope-less subject impersonation** (`user_id`, `id_token` on actor
path): split validation:
- **Subject-data scopes** (`openid`, `profile`, `email`, …): client
allowlist only
- **Authorization scopes** (`offline_access`, `:aud`, `projects:roles`,
`role:*`): still ⊆ subject ∪ actor
- Restore subject → actor fallback when `scope` is omitted.
GHSA protections remain: cross-client token binding and
authorization-scope escalation are still rejected.
Closes#12319Closes#12322
## Additional Changes
- Unit tests for scope validators (`token_exchange_test.go`)
- Integration tests covering `user_id`/`id_token` paths, union-path
rejection, and client-credentials actor → `user_id` exchange
## Additional Context
- Relates to https://github.com/zitadel/zitadel/releases/tag/v4.15.3
- Security fix: GHSA-vrh8-c9cm-wh8v
---------
Co-authored-by: Cursor <[email protected]>
Co-authored-by: Copilot Autofix powered by AI <[email protected]>
* 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]>
# 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
# Which Problems Are Solved
Login v2 uses the `users.v2.ListUsers`-endpoint to get a user by login
name. This query had an inefficient `WHERE`-clause.
# How the Problems Are Solved
Update the view and use a specific clause for this query.
# Additional information
Added in https://github.com/zitadel/zitadel/pull/10475
---------
Co-authored-by: Marco A. <[email protected]>
Co-authored-by: Livio Spring <[email protected]>
* fix: added client and scope validation for token exchange
Verify that the token exchange is not cross client
Only yield scopes which were already on the initial token
* comments
* added test
# Which Problems Are Solved
The updated default denylist added an entry for IPv4-mapped IPv6
addresses to prevent IPv6 encapsulation bypasses.
This is not necessary since the IP already gets resolved into v4 and now
blocks them all.
# How the Problems Are Solved
Removed the entry.
# Additional Changes
None
# Additional Context
None
# Which Problems Are Solved
Enable FIPS 140-3 compliant build.
# How the Problems Are Solved
- Add runtime config validation, if the FIPS flag is enabled fail the
application when a non-compliant hasher is used, or throw a warning when
a legacy verifier is used
- Add a build matrix for FIPS certified build:
- Go binary is built with `GOFIPS140=certified`
- Login container uses a separate base:
[ubi9](https://catalog.redhat.com/en/software/containers/ubi9/ubi/615bcf606feffc5384e8452e)
from redhat which provides a FIPS certified OpenSSL (used by NodeJS TLS
stack)
- Non-FIPS images where already pushed to both Github Container Registry
and Google Artifact Repository (GAR). Fips images are only pushed to the
GAR.
- Tag versions are suffixed `-fips`. So on release the following images
will be additionally available:
```
europe-docker.pkg.dev/zitadel-common/zitadel-repo/zitadel-login:vX.Y.Z-fips
europe-docker.pkg.dev/zitadel-common/zitadel-repo/zitadel:vX.Y.Z-fips-debug
europe-docker.pkg.dev/zitadel-common/zitadel-repo/zitadel:vX.Y.Z-fips
```
# Other changes
- Bumb Go toolchain. At least v1.25.10 is required for a
GOFIPS140=certified setting.
# Additional Context
- Closes https://github.com/zitadel/zitadel/issues/4335
- Build [test
run](https://github.com/zitadel/zitadel/actions/runs/27253916052)
pushing FIPS and non-FIPS images
# Which Problems Are Solved
- The eventstore did not support intentionally overwriting the resource
owner when creating events for aggregates that may be reused across
owners.
- Resource owner handling was implicit and could not be controlled per
command/event type.
- We needed a safe way to distinguish between:
- keeping the existing aggregate owner, and
- explicitly setting a new owner for specific create-like events.
# How the Problems Are Solved
- Introduced a new eventstore command type with an explicit
enforce_owner flag.
- Updated eventstore.commands_to_events and eventstore.push so owner
assignment is now explicit:
- if enforce_owner is true, the command owner is written
- if enforce_owner is false, the existing aggregate owner is retained
when present
- Added EnforceResourceOwnerCommand and wiring so command types can opt
in to enforced owner behavior.
- Wired the new behavior through the v3 eventstore push path, including
compatibility fallback for older command type mapping.
- Added migration/setup changes to register and use the new command type
and SQL functions.
- Added and updated tests for owner overwrite and aggregate ID reuse
scenarios.
# Additional Changes
- Added small migration/setup robustness improvements related to
eventstore setup ordering and helper reuse.
- Added focused test coverage for enforced owner behavior and
sequencing.
- Events that currently allow owner changes (implement
EnforceResourceOwner) are:
- AddedEvent (action)
- GroupAddedEvent
- StartedEvent (idp intent)
- ProjectAddedEvent
- HumanAddedEvent
- HumanRegisteredEvent
- MachineAddedEvent
- CreatedEvent (schema user)
# Additional Context
- Follow-up for eventstore owner-handling correctness in create flows
and aggregate ID reuse cases.
- No additional issue link was attached for this change.
---------
Co-authored-by: abhishek kumar gupta <[email protected]>
# Which Problems Are Solved
- IDP intent authorization redirects used by Login v2 ignored the
configured `UsePKCE` setting for Generic OAuth providers
- This caused providers such as X/Twitter OAuth2 to receive
authorization requests without `code_challenge` and
`code_challenge_method`
- OIDC provider construction had the same gap, even though PKCE is
already part of the provider configuration model
- Existing IDP intent redirect tests expected non-PKCE OAuth URLs and
failed once PKCE was applied correctly
# How the Problems Are Solved
- Updated `OAuthIDPWriteModel.ToProvider` in
internal/command/idp_model.go to pass `rp.WithPKCE(nil)` when `UsePKCE`
is enabled
- Updated `OIDCIDPWriteModel.ToProvider` to apply the same PKCE
relying-party option for OIDC providers
# Additional Changes
- Added focused provider-construction tests covering:
- OAuth provider redirects include code_challenge
- OIDC provider redirects include code_challenge
- both providers use code_challenge_method=S256
- both persist the generated codeVerifier for token exchange
- Updated `TestCommands_AuthFromProvider` in
internal/command/idp_intent_test.go so OAuth redirect assertions verify
PKCE structurally instead of hard-coding the generated challenge value
# Additional Context
- Reproduced with X/Twitter OAuth2 where the generated authorization URL
was missing PKCE parameters despite `usePkce: true`
- Verified both the focused PKCE tests and the full unit test suite run
successfully with the fix
- Closes#12036
- Closes/supersedes #12054:
- Tests are included
- No slice re-allocation on `opts` append
# Result
### Before
`authUrl` in `StartIdentityProviderIntent` response is missing
`code_challenge` and `code_challenge_method` for Generic OAuth IDP with
PKCE enabled:
```json
{
"details": {
"sequence": "1",
"changeDate": "2026-06-07T18:48:16.921317Z",
"resourceOwner": "376298239768395779"
},
"authUrl": "https://x.com/i/oauth2/authorize?client_id=<REDACTED>&prompt=select_account&redirect_uri=http%3A%2F%2Flocalhost%3A8080%2Fidps%2Fcallback&response_type=code&scope=tweet.read+users.email+users.read+offline.access&state=376417136207200259"
}
```
### After
`code_challenge` and `code_challenge_method` are correctly included into
`authUrl`:
```json
{
"details": {
"sequence": "1",
"changeDate": "2026-06-07T18:49:39.488941Z",
"resourceOwner": "376298239768395779"
},
"authUrl": "https://x.com/i/oauth2/authorize?client_id=<REDACTED>&code_challenge=8G4vN8QNgSsbvGSHKwYPEc2qUYU2BK5L0fsr992duTA&code_challenge_method=S256&prompt=select_account&redirect_uri=http%3A%2F%2Flocalhost%3A8080%2Fidps%2Fcallback&response_type=code&scope=tweet.read+users.email+users.read+offline.access&state=376417274736672771"
}
```
# 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]>
- 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]>
# 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
# 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
# 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
# Which Problems Are Solved
Persisting instance-level Zitadel provider in the projections.
# How the Problems Are Solved
- Defining a new projection table `projections.idp_templates6_zitadel`
and columns for the Zitadel provider
- Adding a reducer `reduceZitadelIDPAdded` to process instance-level
`ZitadelIDPAddedEvent`
- Unit tests
# Additional Changes
N/A
# Additional Context
- Related to 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
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]>
# 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]>
# 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]>
# 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]>
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]>
# 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
# Which Problems Are Solved
Currently ZITADEL only allows the use of RSA public keys for machine
user authentication (jwt-bearer grant), including for system API users.
Attempting to use ECDSA (e.g. P-256) or ED25519 keys results in
`Errors.Internal` because `BytesToPublicKey` performs an
`ifc.(*rsa.PublicKey)` type assertion that returns `(nil, nil)` for
non-RSA keys, which then causes a nil key panic in go-jose during JWT
verification.
This is the same fix as #8433 (by @livio-a), rebased onto current
`main`.
# How the Problems Are Solved
- `BytesToPublicKey` now returns `crypto.PublicKey` (the standard
library interface) instead of `*rsa.PublicKey`
- A type switch validates the parsed key is one of `*rsa.PublicKey`,
`*ecdsa.PublicKey`, or `ed25519.PublicKey`
- A new `ErrNoPublicKey` sentinel error is returned for unsupported key
types instead of silently returning nil
- Callers in `system_token.go` and `query/key.go` are updated to use the
generic `crypto.PublicKey` interface
# Additional Changes
None
# Additional Context
Duplicate of #8433 which has been open since August 2024. We hit this
bug while implementing OIDC bootstrap for an SGX enclave that generates
ECDSA P-256 keys at runtime -- the `AddKey` API accepts the ECDSA SPKI
PEM fine, but the subsequent `jwt-bearer` token exchange fails with
`Errors.Internal` due to the nil key.
---------
Co-authored-by: Copilot <[email protected]>
Co-authored-by: Wim Van Laer <[email protected]>
# Which Problems Are Solved
`@zitadel/api:generate-go` failed due to duplicate generated files.
https://github.com/zitadel/zitadel/pull/11820 removed the old generated
file and added a generate command to the `internal/crypto/crypto.go`
file. However, there was already a `internal/crypto/generate.go` with a
different output file name (the old file).
# How the Problems Are Solved
Removed the `internal/crypto/generate.go` file and moved the second
generate into `internal/crypto/code.go`.
# Additional Changes
Noticed that mockgen is an old version and updated it. Also then checked
all other tools and updated them.
# Additional Context
- relates to #11820
- noted internally
# Which Problems Are Solved
A test was failing because of timezone flakiness
# How the Problems Are Solved
The actual problem was an `updatedAt` field was not filled in because of
the `createdAt` was missing on an event. This caused a zero value to be
filled in into the `updatedAt` field. Postgres then stored this value
with seconds in it's timezone info, which go could not store.
By adding filling in the `createdAt` field, this does not occur.
# Which Problems Are Solved
Add Passkey challenge needed for Create/Set session in the RT model.
# How the Problems Are Solved
Introduce `PasskeyChallengeCommand` (validate/execute/events) for
session creation checks
Add a generic `BeginWebAuthNLogin` helper that returns session data +
assertion JSON bytes.
Add unit tests
# Additional Changes
N/A
# Additional Context
- Related to https://github.com/zitadel/zitadel/issues/11035
---------
Co-authored-by: Copilot <[email protected]>
Co-authored-by: Marco A. <[email protected]>
# Which Problems Are Solved
Incorrectly mapped errors on the `/oauth/v2/token` endpoint lead to a
large number of HTTP status 500 errors.
# How the Problems Are Solved
By mapping invalid jwt assertion errors to OIDC `invalid_client` errors,
which returns a HTTP status 400.
# Additional Changes
N/A
# Additional Context
- Closes https://github.com/zitadel/zitadel/issues/11924
- Follow-up:
- Fix the [error
handling](https://github.com/zitadel/oidc/blob/main/pkg/oidc/verifier.go#L195)
in the oidc package
---------
Co-authored-by: Copilot <[email protected]>
# Which Problems Are Solved
In https://github.com/zitadel/zitadel/pull/11858#discussion_r2993742914
we discussed on how to translate the ES passkey state to a relational
one. That is used to filter out passkeys during convertion to webauthn
credentials.
It was decided to consider passkeys in ready state those that have a
verified at `time.Time` set.
The change required fixing the reducer for the eventstore event.
# How the Problems Are Solved
- Set `VerifiedAt` once `HumanWebAuthNVerifiedEvent` is received
- Also set the verification to `nil`
# Additional Context
- Discussion #11858
- Follow-up for PR #11858
<!--
Please inform yourself about the contribution guidelines on submitting a
PR here:
https://github.com/zitadel/zitadel/blob/main/CONTRIBUTING.md#submit-a-pull-request-pr.
Take note of how PR/commit titles should be written and replace the
template texts in the sections below. Don't remove any of the sections.
It is important that the commit history clearly shows what is changed
and why.
Important: By submitting a contribution you agree to the terms from our
Licensing Policy as described here:
https://github.com/zitadel/zitadel/blob/main/LICENSING.md#community-contributions.
-->
# Which Problems Are Solved
- Creating an organization via `SetUpOrg` failed when a custom domain
was provided in the same request.
- The org-domain setup path checked org existence only against persisted
state, so it could not see the newly created organization before the
batch was pushed.
# How the Problems Are Solved
- Added a preparation-aware org existence check that resolves the org
through the validation filter instead of the direct persisted-state
lookup.
- Reused the transaction-aware preparation filter so later validations
can see earlier in-flight commands from the same `PrepareCommands`
batch.
fixes#11677
---------
Co-authored-by: abhishek kumar gupta <[email protected]>
Co-authored-by: Wim Van Laer <[email protected]>
# Which Problems Are Solved
https://github.com/zitadel/zitadel/pull/11390 renamed "Console" to
"Management Console". While
https://github.com/zitadel/zitadel/pull/11706 already reverted an
unintended rename of the feature key to enable the management console to
use the V2 API for user creation. It was now also discovered that the
rename of the feature itself also broke existing (default)
configurations.
# How the Problems Are Solved
Added a `mapstructure` tag on the instance feature to handle existing
configs.
# Additional Changes
Removed unused `TokenExchange` from the default configuration.
# Additional Context
- relates to #11390
- relates to #11706
- requires backport to v4.x
---------
Co-authored-by: Copilot <[email protected]>
Co-authored-by: Marco A. <[email protected]>