475 Commits
Author SHA1 Message Date
034041f7ff feat(login): configurable text if external user can neither be create… (#12724)
### Which Problems Are Solved

- A user authenticates successfully with an external IdP, but no
matching ZITADEL user exists and the IdP allows neither user creation
nor linking. The hosted login then renders a hardcoded error message
(`Errors.User.ExternalIDP.NoOptionAllowed`): *"Neither creation of
linking is allowed on this provider. Please contact your
administrator."*
- Unlike every other message of the login flow, this message cannot be
customized. An administrator can neither point the user to the right
place (e.g. a specific support address or internal process) nor adjust
wording, tone or branding — and the default sentence contains a typo.

### How the Problems Are Solved

- Adds the login text `ExternalNotFound.NoOptionAvailable` (proto:
`ExternalUserNotFoundScreenText.no_option_available`), which can be set
per instance and per organization like all other login texts (Console:
Branding → Login Texts → External User Not Found).
- Renders that text instead of the hardcoded error when an external user
does not match an existing user and neither creation nor linking is
allowed on the IdP. If an actual error occurred on that page, it is
still rendered as before.
- Passes the provider name to the text, so a custom text can reference
it as `{{.ProviderName}}`.

### Additional Changes

- Adds the default text for the new key to all 22 login translation
files.
- Console: includes the new field when saving login texts. The editor
itself renders the fields returned by the API, so no changes to the form
were required.

### Additional Context

- Relates to #12723. This PR only makes the message configurable, it
does not change *when* the message is shown: the configuration reported
in that issue (IdP linking allowed, user creation disabled) still ends
up on the "external user not found" page with a link option instead of
this message.
- Login v2 (`apps/login`) is not affected. It already renders a
dedicated `/idp/{provider}/account-not-found` page whose texts come from
the hosted login translations.

---------

Co-authored-by: Stefan Schöb <stefan.schoeb@taskbase.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: Silvan <27845747+adlerhurst@users.noreply.github.com>
2026-10-13 09:48:26 +00:00
Livio SpringandClaude Opus 5.5 ad835efbc3 fix(api): restore query limits on v1 list endpoints (#12876)
> Stacked on zitadel/zitadel#12875 (reuses `SystemDefaults.QueryLimit`).
Retarget to `main` once that's merged.

## Which Problems Are Solved

The v1 list endpoints (admin, auth, management, system) apply no limit.
A request without `limit` returns all matching rows, and an explicit
`limit` is never capped. The same applies to the 6 change endpoints
(`ListOrgChanges`, `ListUserChanges`, `ListProjectChanges`,
`ListProjectGrantChanges`, `ListAppChanges`, `ListMyUserChanges`).
Without a limit, they return the full history of the object. The only
bound is the audit log retention, which restricts events by age (not by
count) and is disabled by default (`AuditLogRetention: 0s`).

This is a regression. The v1 endpoints previously applied
`Auth/Admin/Mgmt.SearchLimit` (1000) through `EnsureLimit`: a missing
limit defaulted to 1000, and a higher limit was rejected. The check
lived in the old eventsourcing repositories and was dropped when the
endpoints were migrated to the `query` package:
#2342, #2433, #2383, #2612, #2820, #2818, #2838, #3075, #3096.
The `ListQuery.limit` docs still describe the old behavior.

## How the Problems Are Solved

- New `SystemDefaults.V1QueryLimit`: uses `MaxQueryLimit` (1000 by
default) as both the default and the maximum, restoring the previous v1
behavior. Limits above it return `InvalidArgument` (`QUERY-4M0fs`).
- `object.ListQueryToModel` now takes the `SystemDefaults` and applies
it. All 43 v1 call sites were updated.
- The change endpoints apply the same check through
`change.ChangeQueryToModel` (their `ChangeQuery.limit` docs promise the
same default and maximum). Console always passes 30 / 20 there.
- `SystemDefaults` is passed to the admin and system servers. Management
and auth already had them.
- Removed the `Auth.SearchLimit` and `Admin.SearchLimit` configs:
  - `Admin.SearchLimit` was never read.
- `Auth.SearchLimit` only capped the refresh tokens of
`ListMyRefreshTokens` and `RevokeAllMyRefreshTokens` (which revokes the
listed tokens). Both now use `MaxQueryLimit` instead, with the same
default of 1000. This only concerns the legacy refresh tokens, which
haven't been issued since v2.53.
- Unknown config keys are ignored, so existing configs and env vars keep
working.
- Removed the unused `EnsureLimit` methods.
- The v1 list converters take the context first, followed by the system
defaults.
- Updated the `ListQuery.limit` and `ChangeQuery.limit` API docs and the
`MaxQueryLimit` comment in `defaults.yaml`, which now describes where it
applies (v1 lists and change histories, refresh tokens) and that the
events API (`ListEvents`) keeps its own cap of 1000.

## ⚠️ Behavior change

- Requests without `limit` return at most `MaxQueryLimit` (1000)
results.
- Requests with `limit` > 1000 fail with `InvalidArgument`.
- Self-hosters can restore the previous behavior with `MaxQueryLimit:
0`. This applies globally, including to v2.

Console: all v1 list calls pass page sizes ≤ 250, except two that load
all projects of an organization:
- the startup project preload (`listProjects(0, 0)` /
`listGrantedProjects(0, 0)`), used for the project counts, shortcuts and
breadcrumbs. zitadel/zitadel#12881 replaces it (counts from
`details.totalResult`, projects loaded by ID).
- the projects grid view (`project-grid.component.ts`), which has no
pagination. With the default of 1000, it only misses projects (and
pinned grid entries) for organizations with more than 1000 owned or
granted projects. The largest organizations on ZITADEL Cloud are well
below 1000 projects.

## Additional Changes

- Deprecated the unused `query` and `result` fields of
`ListProjectGrantMemberRolesRequest`. The endpoint has no list
semantics: it always returns all roles possible on the project grant
level, like the other member role endpoints, whose requests are empty.

## Additional Context

- Tests:
  - unit tests for `V1QueryLimit` and `ListQueryToModel`
- limit-exceeded integration tests for admin `ListOrgs`, management
`ListUsers`, `ListProjects` and `ListOrgChanges`, and system
`ListInstances`
- A technical advisory covering both PRs is planned.
- Needs a v4.x backport together with zitadel/zitadel#12875.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 08:01:54 +02:00
Livio SpringandClaude Opus 5.5 6f84d29350 fix(api): enforce query limits on v2 list endpoints (#12875)
## Which Problems Are Solved

Several v2 / v2beta list endpoints ignore the configured
`SystemDefaults.DefaultQueryLimit` (100) and `MaxQueryLimit` (1000):

- user v2 / v2beta `ListUsers`
- user v2 `ListIDPLinks`
- org v2 `ListOrganizations`
- session v2 / v2beta `ListSessions`

A request without `limit` returns **all** matching rows, and an explicit
`limit` is never capped. On large instances (especially `ListSessions`)
this causes expensive queries. It also contradicts the API docs of
`ListQuery.limit`, which already promise both the default and the
maximum.

## How the Problems Are Solved

- New `SystemDefaults.QueryLimit` method that applies the default and
rejects limits above the maximum (`InvalidArgument`, `QUERY-4M0fs`,
`Errors.Query.LimitExceeded`).
- `filter.PaginationPbToQuery` (v2 / v2beta) and
`object.ListQueryToQuery` (v2 / v2beta) share
`SystemDefaults.PaginationToQuery`. `ListQueryToQuery` now takes the
`SystemDefaults`, so every endpoint above behaves like the newer
endpoints.
- `SystemDefaults` is passed to the session v2 / v2beta and user v2beta
servers, and to the instance v2 / v2beta and app v2beta servers, which
never received them. Their list endpoints (e.g. `ListInstances`,
`ListCustomDomains`, `ListApplications`) were unbounded as well.
- `ListSessions` (v2 / v2beta) and `ListOrganizations` (v2 / v2beta) are
sorted by ID if no sorting column is given, like `ListUsers`, so pages
don't overlap or miss rows.
- Removed the unused (unbounded) `ListQueryToModel` helpers in
`object/v2beta` and `org/v2beta`.
- Corrected the `ListQuery.limit` API docs, the `DefaultQueryLimit` /
`MaxQueryLimit` comments in `defaults.yaml`, and the descriptions of
`ListUsers` (v2 / v2beta), `ListOrganizations` (v2), the v3alpha list
requests and the `API_DESIGN.md` template, which stated that all results
are returned by default.

## ⚠️ Behavior change

- Clients that leave out `limit` to get *all* results now receive at
most `DefaultQueryLimit` (100) and need to paginate.
- Requests with `limit` > `MaxQueryLimit` (1000) now fail with
`InvalidArgument` instead of succeeding.
- `ListSessions` and `ListOrganizations` without a sorting column are
now returned in descending ID order instead of an undefined order.

Operators can restore the previous behavior by setting
`DefaultQueryLimit: 0` and / or `MaxQueryLimit: 0`. Note that this
applies globally, including to the endpoints that already enforced the
limits.

Our own clients were checked:
- **Login**: `listUsers` sends `limit: 2`. `listSessions` (by IDs,
bounded by the session cookie size) and `listIDPLinks` send no limit and
stay well below 100.
- **Console**: tables use page sizes ≤ 100 and autocomplete uses 25. The
account switcher lists sessions per user agent without a limit;
zitadel/zitadel#12881 sorts them by creation date descending, so the
most recent ones are kept.

## Additional Changes

None.

## Additional Context

- Not covered: the relational (`backend/v3`) code paths behind
`EnableRelationalTables`.
- The v1 APIs (admin / auth / management / system) are handled in
zitadel/zitadel#12876, which is stacked on this PR.
- SCIM already enforces its own default and maximum of 100.
- A technical advisory is planned because of the behavior change.
- Needs a v4.x backport.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 08:01:54 +02:00
9067605b66 Merge commit from fork
* fix(crypto): use authenticated encryption for IDP intent tokens

IDP intent tokens were encrypted with AES-CFB which provides no
integrity protection, making them malleable. Switch to A256GCM via
the existing AuthAlgorithm interface (EncryptToken/DecryptToken),
the same approach already used for OIDC and session tokens.

The idpConfigEncryption key type is widened from EncryptionAlgorithm
to AuthEncryptionAlgorithm so that data-at-rest encryption (IDP
client secrets, LDAP bind passwords, SAML keys) continues to use
the CFB path unmodified.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(proto): raise IDP intent token max length to 500 for authenticated tokens

The switch to authenticated A256GCM (JWE compact serialization) makes IDP
intent tokens longer (~270 chars) than the previous AES-CFB base64 output.
Raise the max_len/max_length validation and OpenAPI constraints on every
idp_intent_token field from 200 to 500 so the new tokens are accepted:
user v2/v2beta (idp + user_service), session v2/v2beta, and resources
user v3alpha.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-04 06:13:37 +02:00
Livio SpringandClaude Fable 5 c9d747d407 fix(api): prevent cross-instance caching of well-known app link files (#12644)
# Which Problems Are Solved

The `/.well-known/apple-app-site-association` and
`/.well-known/assetlinks.json` responses are instance specific: the body
depends on the requested host. The responses did not declare this, so a
shared cache whose cache key does not include the host could store one
instance's file and serve it on another instance's domain. This could
result in a wrong or empty file being returned intermittently, breaking
native passkey verification.

Dropping the `public` directive (#12634) was not sufficient: depending
on its cache mode, a shared cache may store any response carrying a
`max-age`.

The docs page for native app links also still documented the old
`Cache-Control: public` header and only the single `get_login_creds`
relation (missing `handle_all_urls`, added in #12634).

# How the Problems Are Solved

- Send **`Vary: Host`** on both well-known responses, declaring that the
body depends on the host: a spec-compliant shared cache must store
per-host variants or skip caching. Clients addressing a single host (the
Apple and Google verifiers, browsers) are unaffected and keep honoring
the configured `max-age`.
- Correct the outdated caching reasoning in the code comments.
- Guard the header with unit and integration tests.
- Update the native app links docs page: both Digital Asset Links
relations and the current response headers.

# Additional Changes

None. `WellKnown.AppLinksCacheControlMaxAge` behavior is unchanged (`0`
still results in `no-store`).

# Additional Context

- Follow-up to #12634; relates to #12497.
- Verified with interleaved requests against two instances: responses
are no longer reused across domains, and each domain consistently serves
its own configuration.
- To be cherry-picked to `v4.x` from `main` once merged.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-26 10:57:28 +02:00
Livio SpringandCursor 318bfc36d7 feat: native app links for passkeys (#12580)
# Which Problems Are Solved

- Native iOS/Android passkeys need OS trust files on the ZITADEL domain;
without them, Associated Domains / App Links verification fails.
- Operators could not configure iOS Team ID + Bundle ID or Android
package name + SHA-256 fingerprints on OIDC apps.
- `/.well-known/apple-app-site-association` and
`/.well-known/assetlinks.json` were not served from application config.

# How the Problems Are Solved

- Add iOS/Android app-link fields on OIDC app create/update (Application
API v2 + Management), with validation.
- Persist and project those fields; query active app-link configs
instance-wide.
- Serve AASA (`webcredentials`) and Digital Asset Links
(`get_login_creds`) from well-known paths, with configurable
`Cache-Control` and fingerprint normalization at serve time.
- Console UI to edit the fields, with links to the well-known endpoints.
- Operator docs for configuration, endpoints, caching, and verification.

# Additional Changes

- Document on API fields that well-known responses may be HTTP-cached
and platform verifiers may delay propagation.
- Runtime config: `WellKnown.AppLinksCacheControlMaxAge` (default `5m`;
`0` → `no-store`).

# Additional Context

- Closes #12497
- Implemented and reviewed as stack:
  - #12531 API contract
  - #12532 storage wiring
  - #12536 well-known endpoints
  - #12537 console
  - #12547 docs

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-12 08:04:27 +02:00
Livio SpringandCursor a8861336f4 fix(api): accept SetSecuritySettings on /v2/settings/security (#12518)
# Which Problems Are Solved

`GetSecuritySettings` is served at `GET /v2/settings/security`, but
`SetSecuritySettings` was only bound to `PUT /v2/policies/security`.
That split made the natural copy-paste path (`PUT
/v2/settings/security`)
return `405`, including the enable curl in the Dynamic Client
Registration
guide.

# How the Problems Are Solved

Make `PUT /v2/settings/security` the primary HTTP binding for
`SetSecuritySettings`, and keep `PUT /v2/policies/security` as an
`additional_bindings` entry so existing callers keep working.

# Additional Changes

None.

# Additional Context

- Noticed during review of the Dynamic Client Registration PR (#12313):
the
guide's enable curl used `PUT /v2/settings/security` and hit `405`
against a
  live instance.
- Only `settings/v2` is changed; `v2beta` is left as-is (deprecated).
- Generated gateway/OpenAPI artifacts are gitignored and rebuilt from
the
  proto on generate.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-31 11:34:00 +02:00
jmarette f34cc45eac feat(oidc): add RFC 7591 dynamic client registration (#12313)
# Which Problems Are Solved

ZITADEL cannot currently be used as an OAuth 2.0 Authorization Server by
clients that need to register themselves at runtime:

- There is no [OAuth 2.0 Dynamic Client Registration (RFC
7591)](https://datatracker.ietf.org/doc/html/rfc7591) endpoint, and no
`registration_endpoint` is advertised in the discovery document.
- This blocks [Model Context Protocol
(MCP)](https://modelcontextprotocol.io) clients (Claude Desktop,
claude.ai, Cursor, the MCP SDKs), whose OAuth 2.1 authorization profile
expects an Authorization Server that supports dynamic client
registration. They self-register before any user context exists and only
then start the authorization code + PKCE flow.

# How the Problems Are Solved

## Control plane: instance security settings

No feature flag and no runtime config. A
`DynamicClientRegistrationSettings` message is nested under the instance
`SecuritySettings` in `settings/v2`, next to `embedded_iframe` and
`enable_impersonation`:

| `enabled` | `allow_unauthenticated` | Behaviour |
| --- | --- | --- |
| `false` (default) | — | `POST /oauth/v2/register` returns `404`,
`registration_endpoint` absent from discovery |
| `true` | `false` (default) | Token-gated registration, client homed in
the token's organization |
| `true` | `true` | Open registration for MCP hosts, client homed in the
instance default organization |

Both values are carried on `authz.Instance` and loaded with the
instance, exactly like `EnableImpersonation`, so the discovery document
and the endpoint read them per request without an extra query.
`allow_unauthenticated` implies `enabled` in both implementations, so a
single setting closes the endpoint.

Adding the two columns bumps the projection table to
`projections.security_policies3`, following what the impersonation
setting did for `security_policies2`.

## Authorization: a dedicated permission, not `project.app.write`

- New org-scoped permission **`project.app.register_dynamic`**, granted
by default to `ORG_OWNER`, `IAM_OWNER` and `IAM_ORG_MANAGER` — in both
`InternalAuthZ` and `SystemAuthZ`, mirroring where `project.app.write`
already lives.
- New built-in role **`ORG_DYNAMIC_CLIENT_REGISTRAR`** carrying only
that permission, so a service user can self-register clients without
gaining write access to the organization's existing applications.
- Open mode (`allow_unauthenticated = true`) requires no token and no
permission: that is the MCP self-register path.
- A valid token whose user lacks the permission is answered with **`403
insufficient_scope`** (RFC 6750 §3.1) rather than `401 invalid_token`,
so a caller can tell "your token is bad" from "your token may not do
this". `verifyAccessToken` also reports invalid tokens as permission
denied, so the authorization failure is marked explicitly to keep the
two apart.

The check runs once, at the endpoint, right after the token is verified
and before any state is created, so it also gates the auto-provisioning
of the organization's DCR project. The permission itself lives in the
command layer next to the others
(`Commands.CheckPermissionRegisterDynamicClient`). As the OIDC endpoints
are not behind the authorization interceptor, the caller identity is
derived from the verified token, the way token exchange does for the
impersonating actor.

## Registration itself

- **Registered clients are ordinary OIDC applications.** The endpoint
reuses the existing application-creation events
(`NewApplicationAddedEvent` and `NewOIDCConfigAddedEvent`), so the whole
token, authorization and introspection flow keeps working unchanged.
They are stored in a dedicated, auto-provisioned project named `ZITADEL
DCR` per organization (name lookup), so they do not pollute the
`IAMProject` or other projects.
- Input is validated with the existing `GetOIDCV1Compliance` rules;
`private_key_jwt` and `jwks`/`jwks_uri` are rejected with
`invalid_client_metadata`.
- **Endpoint wiring without forking the library.** `NewServer` calls
`op.RegisterServer` instead of `op.RegisterLegacyServer`, so the new
route can be added through the same `op.WithSetRouter` hook as the
authorize callback. `op.RegisterLegacyServer` appends a middleware after
the caller options, which chi forbids once a route has been registered;
`op.NewIssuerInterceptor` reproduces the issuer middleware it would
otherwise add. The `/oauth/v2` routing prefix is unchanged.

# Additional Changes

- **`application_type` inference for custom-scheme redirects** (last
commit, isolated). `application_type` is an OpenID Connect member; RFC
7591 does not define it, so clients that only implement RFC 7591 omit
it. Native MCP hosts doing so register custom-scheme redirect URIs,
which ZITADEL reserves for native applications, and the OIDC default of
`web` rejected them with `invalid_redirect_uri`. Inference is limited to
custom schemes and to an absent `application_type`, so every request
accepted today keeps its current application type and auth method — an
`http` loopback redirect still yields a web application. Happy to drop
this commit if you would rather keep it out of this PR.
- **Docs**: a Dynamic Client Registration integration guide, a
`registration_endpoint` section on the OpenID Connect endpoints page,
and the new role in the administrators table (plus its description in
the Console translations).

# Additional Context

- Part of #9810. This is **Phase 1 (DCR)**; #12315 adds RFC 7592 and
#12316 adds CIMD, both stacked on this branch and rebased once this
lands.
- Implements the control-plane and authorization model requested in the
review of this PR, itself a refinement of the direction in
https://github.com/zitadel/zitadel/issues/9810#issuecomment-4891176997.
- **Out of scope (deliberately)**: RFC 7592, CIMD, persisting free-form
metadata (`logo_uri`, `contacts`, and similar), and `private_key_jwt` /
`jwks_uri` (rejected cleanly). No new event types.
- Follow-ups explicitly left out, per the review: DCR client lifecycle
and richer audit, consent and custom scopes, JWT / `aud` (RFC 8707), and
RFC 8414 AS metadata (currently absent from both ZITADEL and
`zitadel/oidc`).
2026-07-30 14:43:47 +00:00
gayathri ffd9b39bdb feat: handle Zitadel provider IdP login via login v1 (#12469)
# 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
2026-07-28 15:20:46 +02:00
gayathriandLivio Spring 6eafca2872 feat: update GetActiveIdentityProviders to return Zitadel in the IdP list (#12422)
# 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 <9405495+livio-a@users.noreply.github.com>
2026-07-14 13:50:09 +02:00
Gayathri VijayanandCopilot Autofix powered by AI 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 <175728472+Copilot@users.noreply.github.com>
2026-07-10 09:17:49 +02:00
Gayathri VijayanandCopilot Autofix powered by AI 5dcce9abdb feat: add api definition to update Zitadel IdP (#12371)
# Which Problems Are Solved

Enabling updates on the Zitadel Identity Provider

# How the Problems Are Solved

This PR adds API definitions to update Zitadel provider at instance and
organization levels.

# 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

---------

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-07-03 12:52:26 +00:00
Livio Spring 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
Livio Spring 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
c0f7bfffdb docs(api): remove incorrect note on CreateInviteCode endpoint (#12073)
# Which Problems Are Solved

The CreateInviteCode endpoint wrongly stated that a new code can only be
issued if the old had expired or was invalidated due to too many
attempts, which is not true.

# How the Problems Are Solved

Removed the note from the proto / API documentation.

# Additional Changes

None

# Additional Context

- noticed by a customer
- requires backport to v4.x

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Matías Racedo <matiasracedo@gmail.com>
2026-04-16 17:04:47 -03:00
Gayathri VijayanandCopilot 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 <175728472+Copilot@users.noreply.github.com>
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] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: muhlemmer <5411563+muhlemmer@users.noreply.github.com>
2026-04-13 10:59:50 +00:00
Livio SpringandWim Van Laer 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 <wim+github@zitadel.com>
2026-04-13 09:47:04 +02:00
Wim Van LaerandCopilot e65cc3007d feat: added contracts for link-settings (#11975)
# Which Problems Are Solved

A new model is needed for links in settings.

# How the Problems Are Solved

Created the new contracts for `LinkSettings`

# Additional Changes


# Additional Context

Replace this example with links to related issues, discussions, discord
threads, or other sources with more context.
Use the Closing #issue syntax for issues that are resolved with this PR.
- Closes #11959
- Discussion #xxx
- Follow-up for PR #xxx
- https://discord.com/channels/xxx/xxx

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-04-10 09:24:49 +00:00
Gayathri VijayanandCopilot 61b40975f7 feat: API definition to add new Zitadel providers (#12018)
# Which Problems Are Solved

In the Zitadel API, provide an IdP template which allows connecting to
other Zitadel instances.

# How the Problems Are Solved

This PR adds API definitions to add Zitadel provider at instance and
organization levels.
- Add `AddZitadelProvider` to ManagementService and AdminService
- Add `InstanceRolesInfo` message to help determine instance admin role
assignments

# Additional Changes
N/A

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

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-04-10 07:40:05 +00: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
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
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
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
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
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
Marco A. 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 <vitor+github@zitadel.com>
Co-authored-by: Silvan <27845747+adlerhurst@users.noreply.github.com>
2026-03-03 08:34:43 +00:00
RamonandLivio Spring 369b468720 chore: consistent naming for object ids (#11604)
<!--
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
As part of the consistent naming effort, this PR focuses on Resource
ID's.

# How the Problems Are Solved
Renamed generic Resource ID to matching Object + ID such as

- Organization ID
- User ID
- Application ID
- Identity Provider ID
- Instance ID
- Project ID

# Additional Changes
None

# Additional Context
- Closes #11306

---------

Co-authored-by: Livio Spring <livio.a@gmail.com>
2026-02-19 06:21:01 +00:00
Gayathri Vijayan 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
Livio SpringandCopilot 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 <175728472+Copilot@users.noreply.github.com>
2026-02-19 05:05:19 +00:00
RamonandCopilot b23346f6ca chore: consistent naming for organization domain (#11356)
# Which Problems Are Solved

As part of the consistent naming effort, this PR focuses on
"Organization domain".

# How the Problems Are Solved

- All terms referring referring to Organization Domains where changed to
be Organization Domain

# Additional Changes

None

# Additional Context

- closes [#11283](https://github.com/zitadel/zitadel/issues/11283)

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-02-18 14:46:21 +00:00
Gayathri VijayanandCopilot 93a4ed8857 chore: rename authorization to role assignment (#11588)
# Which Problems Are Solved

As part of the naming consistency initiative, the terms Authorization,
User grants, internal authorization and other similar terms that are
used in the context of assigning project roles to users are replaced by
Role Assignments in the UI, API docs, and documentation.

# How the Problems Are Solved

By replacing the following terms with Role Assignments in API docs,
Console UI, and guides.

- Authorization
- internal authorization
- external authorization
- User Grant
- Roles and Authorizations

By adding a note in the API docs to make it clear that Authorization
within the context of Authorization Service API refers to role
assignments, not to OAuth authorization as it is still used in the APIs.

By updating some screenshots in documentation / guides to show "Role
Assignments" instead of "Authorizations" in the UI.

# Additional Changes

N/A

# Additional Context

- Closes https://github.com/zitadel/zitadel/issues/11289

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-02-17 13:14:57 +01:00
Florian Forster db9ebbbb41 chore(agents): add agents files (#11497) 2026-02-16 20:45:53 -08:00
Wim Van LaerandCopilot 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 <198982749+Copilot@users.noreply.github.com>
2026-02-13 14:34:32 +00:00
Marco A. 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
Wim Van Laer 9b064d8b74 docs: fixed some typos, formatting, grammar (#11540)
# Which Problems Are Solved

- Typos
- Punctuation
- Markdown table formatting
- ...

(A bunch of issues my editor gave)

# How the Problems Are Solved


# Additional Changes


# Additional Context
2026-02-13 07:45:17 +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 <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Marco A. <marco@zitadel.com>
2026-02-12 08:44:34 +00: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 <198982749+Copilot@users.noreply.github.com>
Co-authored-by: muhlemmer <5411563+muhlemmer@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Marco A. <marco@zitadel.com>
2026-02-10 20:25:39 +01:00
Marco A.andWim Van Laer 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 <wim+github@zitadel.com>
2026-02-06 09:46:24 +00:00
Livio Spring 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
Wim Van Laer 6f6f9d20f0 fix(api): make auth not required for testing smtp (#11514)
# Which Problems Are Solved

With the xoath introduction an `auth` oneof was added to the proto. This
was made because one of the authentication methods should always be
selected. This however, created a backwards compatibility issue.

# How the Problems Are Solved

Don't make `auth` required.

# Additional Changes


# Additional Context
2026-02-05 11:40:59 +01:00
b99271755b chore: renamed one time password to OTP (#11447)
# Which Problems Are Solved

naming consistency for TOTP/OTP

# How the Problems Are Solved


# Additional Changes


# Additional Context

- Closes #11299 
- Closes #11302 
- Closes #11304

---------

Co-authored-by: Marco A. <marco@zitadel.com>
Co-authored-by: Florian Forster <florian@zitadel.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-02-04 10:20:47 +01:00
Wim Van Laer 61d4060df3 chore: naming inconsistency application (#11431) 2026-02-04 07:20:07 +00:00
Livio SpringandMarco A. 09cf7cf0ae feat(oauth/oidc): move token exchange from beta to GA (#11475)
# Which Problems Are Solved

This PR marks the OAuth2 Token Exchange 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 interation
  - removed the toggle usage for token exchange
  - removed related translations
- Management Console:
  - removed the feature toggle and its translations
- Docs:
  - removed all beta labels and feature toggle notes

# Additional Changes

- removed unused `Errors.WebKey.FeatureDisabled` translations

# Additional Context

- closes #11114

---------

Co-authored-by: Marco A. <marco@zitadel.com>
2026-02-02 09:47:56 +00:00
Florian ForsterandFederico Coppede d8ea041c56 docs: introduce versioned docs and migrate to fuma (#11166)
## Todos for release

- [x] Configure Env in docs project on vercel
- [x] Configure Root Path in the docs project on vercel
- [ ] Remove old CSP https://github.com/zitadel/website/pull/1592

## What we did

This pull request migrates the project documentation from the old
`docs/` directory to the new `apps/docs/` directory, introduces a new
documentation system built with Next.js and Fumadocs, and updates all
relevant references, configuration files, and documentation to reflect
this change. It also adds new configuration and ignore files for the new
documentation app, updates CI and linting to exclude the new docs from
certain checks, and revises the contributing guidelines accordingly.

**Documentation System Migration and New Docs App**

* Migrated all documentation from `docs/` to `apps/docs/`, and updated
all references in `README.md`, `CONTRIBUTING.md`, and other files to
point to the new location.
[[1]](diffhunk://#diff-eca12c0a30e25b4b46522ebf89465a03ba72a03f540796c979137931d8f92055L585-L640)
[[2]](diffhunk://#diff-eca12c0a30e25b4b46522ebf89465a03ba72a03f540796c979137931d8f92055L660-R607)
[[3]](diffhunk://#diff-eca12c0a30e25b4b46522ebf89465a03ba72a03f540796c979137931d8f92055L740-R687)
[[4]](diffhunk://#diff-b335630551682c19a781afebcf4d07bf978fb1f8ac04c6bf87428ed5106870f5L2-R3)
[[5]](diffhunk://#diff-b335630551682c19a781afebcf4d07bf978fb1f8ac04c6bf87428ed5106870f5L30-R30)
* Added a new Next.js/Fumadocs-based documentation app under
`apps/docs/`, including core app files, layouts, routing, search API,
and a comprehensive `README.md` with development and contribution
instructions.
[[1]](diffhunk://#diff-5a1b07344a2c1b4d3f37b23ff1388b62cd9f57dea3c1cd23d8a0412b7602b132R1-R74)
[[2]](diffhunk://#diff-462b9ad1eabbb7d1c29bb9c36e4931eb180fd7190900e6d2babf8f4d66ad1c28R1-R39)
[[3]](diffhunk://#diff-e16ae25660ded787b10ac35dea96d5ecaacf895dae0afc8a9bd4382dc79a8c87R1-R7)
[apps/docs/app/[[...slug]]/layout.tsxR1-R81](diffhunk://#diff-59e08acde4e805b7aeccef1dcf98f1d71dfc550777e6b9402085cee0e9fa4e0aR1-R81),
[apps/docs/app/[[...slug]]/page.tsxR1-R79](diffhunk://#diff-e5df3f80d0fa01e12d63d81f29c57a9d14e846c78fd3beabb2ef768e38fd9580R1-R79),
[[4]](diffhunk://#diff-389b34918e040cacaa87cd7201ffa462cc2b0b716736f537e3d3c660ac69353bR1-R7)
[[5]](diffhunk://#diff-d3b03416d1c457b19f1c27b26f2db741412df841b875c26ccadc36e4522247f4R1-R29)
[[6]](diffhunk://#diff-c8fb8339570a5305809be7c618e14705fd86390dc278e6ce8ba224a7bc8b0c3cR1-R25)

**Configuration and Tooling Updates**

* Updated `.github/workflows/codeql.yml`, `.golangci.yaml`, and
`.github/dependabot.yml` to properly handle the new docs app: excluded
`apps/docs` from certain checks, added npm dependency updates for the
docs app, and excluded generated content.
[[1]](diffhunk://#diff-12783128521e452af0cfac94b99b8d250413c516ec71fe6d97dbea666ff7ba27L8-R14)
[[2]](diffhunk://#diff-9917ddc9f1c3304218f7269265b746d997c5c0615478177b5fceecd33ef47cb5R5-R6)
[[3]](diffhunk://#diff-9917ddc9f1c3304218f7269265b746d997c5c0615478177b5fceecd33ef47cb5R126-R129)
[[4]](diffhunk://#diff-dd4fbda47e51f1e35defb9275a9cd9c212ecde0b870cba89ddaaae65c5f3cd28R89-R106)
* Updated `.devcontainer/devcontainer.json` to use the latest Go 1.25.3
version for consistency.

**Licensing and Miscellaneous**

* Added `apps/docs/` to the list of licensed directories in
`LICENSING.md`.

These changes ensure the documentation is now maintained in a modern,
scalable system and all project tooling is updated to support the new
structure.

---------

Co-authored-by: Federico Coppede <fcoppede@gmail.com>
2026-01-29 08:38:36 -08:00
3fc0ef2506 feat: added xoauth for smtp (#11239)
# Which Problems Are Solved

- Some mail providers (e.g.: MS Exchange) have deprecated plain auth

# How the Problems Are Solved

Adds XOauth2 auth option to SMPT
- SMTP config now can contain XOAuth2 auth config
- Proto files are updated to have a oneof for configuration selection.
Old fields for configuring plain auth are still available not to create
a breaking change. These can be removed in the future.
- Columns are added to the database to persist the config

# Additional Changes

none

# Additional Context

Replace this example with links to related issues, discussions, discord
threads, or other sources with more context.
Use the Closing #issue syntax for issues that are resolved with this PR.
- Closes #8042

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Tim Möhlmann <tim+github@zitadel.com>
2026-01-27 15:11:56 +01:00
Marco A. 96bbd6a65c chore: management console naming inconsistency (#11390)
# Which Problems Are Solved

The following terms have all been renamed to management console:

- Customer Portal (when used to mean the console)
- Console
- Admin Console

# How the Problems Are Solved

- Search & Replace smartly
- Use Copilot for translation files

Changes done to: backend + frontend codebase, docs, translations and
protobufs (descriptions only)

# Additional Context

- Partially Closes #11279
2026-01-26 14:52:15 +00:00
Livio Spring 7d6a2950b4 feat(api): allow filtering apps by client id and entity id (#11385)
# Which Problems Are Solved

There's currently no way to retrieve a project based on the client_id of
an application. A developer would need to iterate through all projects
and their applications to make the correlation.

# How the Problems Are Solved

- Added a possibility to filter for `client_id` and `entity_id` on the
ListApplications endpoint.
- Added the `project_id` on the `Application` response (used on the
ListApplications endpoint).

# Additional Changes

None

# Additional Context

- closes #11340 
- requires backport to v4.x
2026-01-22 07:41:35 +00:00
Livio Spring 30d91cde58 fix(api): correctly handle organization_id on creation (#11396)
# Which Problems Are Solved

While moving the some requests from the v2beta organization service to
v2, the `org_id` property of the `AddOrganization` request was
deprecated in favor of `organization_id`. However, the internal logic
was adjusted, resulting in a ingored `organization_id`.

# How the Problems Are Solved

- properly favor `organization_id` over `org_id` and added a note to the
proto.

# Additional Changes

none

# Additional Context

- closes #11269
- requires backport to v4.x
2026-01-22 06:19:16 +00:00