# Which Problems Are Solved
This PR introduces several HTML attributes to the username/ID input
field to **prevent unwanted automatic capitalization and correction** on
mobile devices (iOS and Android).
Specifically, this addresses the common issue where a mobile keyboard
defaults to an uppercase letter for the first character, even when the
input (like a username or email) should be lowercase.
# How the Problems Are Solved
The following attributes have been added to the `<input>` field:
| Attribute | Value | Purpose |
| :--- | :--- | :--- |
| `autoCapitalize` | `none` | **Crucial fix:** Prevents the virtual
keyboard from capitalizing the first letter. |
| `autoCorrect` | `off` | Prevents the operating system from
auto-correcting input (e.g., changing "teh" to "the"). |
| `spellCheck` | `false` | Disables the red squiggly lines for
spell-checking. |
# Additional Changes
None.
Previously:
~Introduces a default `Content-Type` request header in the `.env` file
to increase compatibility for developing `zitadel-login` and call a
non-local Zitadel API. The `Host` header is also added as a
commented-out reference so developers will be reminded to set this one
too. This is needed for supporting calls to a Zitadel deployed behind an
AWS ALB, for example.~
https://github.com/zitadel/zitadel-charts/pull/460
# Additional Context
This attribute was already present:
| Attribute | Value | Purpose |
| :--- | :--- | :--- |
| `autoComplete` | `username` | Provides a semantic hint to password
managers to correctly suggest and fill stored usernames. |
## Rationale and References (MDN Web Docs)
| Attribute | Why we use it | Reference Link |
| :--- | :--- | :--- |
| **`autoCapitalize="none"`** | Overrides default OS sentence
capitalization behavior. | [MDN:
autocapitalize](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Global_attributes/autocapitalize)
|
| **`autoCorrect="off"`** | Essential for case-sensitive or specific
identifiers where correction must be disabled (primarily iOS). | [MDN:
autocorrect](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Global_attributes/autocorrect)
|
| **`spellCheck="false"`** | Usernames are not dictionary words, so
spell-checking is distracting/irrelevant. | [MDN:
spellcheck](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Global_attributes/spellcheck)
|
| **`autoComplete="username"`** | Modern standard for indicating a login
field, supporting password managers. | [MDN:
autocomplete](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Attributes/autocomplete)
|
## Browser Safety Concern
This change is **safe**. These attributes act as "hints" to the browser
and OS. If a particular older browser does not support one of the
attributes, it will simply ignore it and revert to its default behavior,
introducing **no errors** or breaking changes. The combination used is
considered best practice for secure and predictable input fields.
- Discussion #11124
---------
Co-authored-by: Copilot <[email protected]>
Co-authored-by: Ramon <[email protected]>
# Which Problems Are Solved
Panics may cause a service discruption by unexpectedly closing an
request's connection. Or in the case of gRPC completely killing the
service.
Allthough panics are still individual bugs that need to be solved, this
PR makes sure a panic is gracefully handled and an understandable error
is returned to the client.
# How the Problems Are Solved
- Recover in the middleware interceptors for the 3 API protocols (HTTP,
gRPC, connect).
- HTTP middleware uses formatted responses for:
- OIDC errors (JSON formatted response)
- UI (error page rendering)
- SCIM
- Upon recovery an alert level log is printed (ERROR+4 for stdlib log
handlers)
# Additional Context
- internal observation
---------
Co-authored-by: Livio Spring <[email protected]>
Co-authored-by: Livio Spring <[email protected]>
# 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
Introduce a new SQL migration that creates the `login_names` table and
associated triggers/functions for managing login names based on domain
policies and user updates. Manual tests confirm the functionality works
as intended.
# Which Problems Are Solved
Currently, metadata can be set/updated only for human users, but it
should be available also for service accounts (machine users).
# How the Problems Are Solved
This is achieved by:
- adding a metadata field at the root level in `CreateUserRequest`,
which makes it available for both `human` and `machine` user types
- returning an error when both the root level and human-level `metadata`
fields are set in the `CreateUserRequest`
- setting `human` and `machine` metadata from the root `metadata` field
in the server layer
- pushing `user.metadata.set` event during machine user creation in the
command layer
- adding integration tests
# Additional Changes
N/A
# Additional Context
- Related to https://github.com/zitadel/zitadel/issues/11369
---------
Co-authored-by: Vitor Bari Buccianti <[email protected]>
Co-authored-by: Silvan <[email protected]>
Users deploying ZITADEL against a managed PostgreSQL service (RDS, Cloud
SQL, Azure Database, etc.) often do not have superuser access and cannot
provide `Admin.*` credentials. The documented workaround — provisioning
the user and database manually and then running `start-from-setup` —
silently skips schema bootstrapping, causing `relation
"eventstore.events" does not exist` errors with no clear recovery path.
The root cause is that `zitadel init` conflates two steps that require
different privileges without exposing them separately:
- **Provisioning step** (`CREATE ROLE`, `CREATE DATABASE`, `GRANT`) —
requires superuser.
- **Schema bootstrapping step** (create
`eventstore`/`projections`/`system` schemas and base tables) — requires
only DB owner.
Users who handle the provisioning step externally have no supported way
to run schema bootstrapping alone.
## Changes
- **`cmd/initialise/verify_schema.go`** (renamed from
`verify_zitadel.go`): Rename `newZitadel()` → `newSchema()` (internal);
rename the `init zitadel` sub-command to `zitadel init schema`
(backwards-compatible alias kept) with a clear description that it
bootstraps the ZITADEL database schema without admin/superuser
privileges. Fix stale error log message to reference `init schema`.
- **`cmd/initialise/verify_schema_test.go`** (renamed from
`verify_zitadel_test.go`): Test file renamed to match source file.
- **`cmd/initialise/init.go`**: Update call site to `newSchema()`. Add
guidance in the `init` command's Long description about using `zitadel
init schema` for users without admin credentials.
- **`cmd/initialise/verify_database.go`**: Add a `pg_database` catalog
pre-check before attempting `CREATE DATABASE`, so `zitadel init` with
`ADMIN=service_user` no longer fails with `permission denied to create
database` when the database was already provisioned externally.
- **`cmd/initialise/verify_database_test.go`**: Add test cases covering
the new catalog-check skip path, the existing error-skip path, and the
error-propagation path when the `pg_database` query itself fails.
- **`apps/docs/content/self-hosting/manage/database/index.mdx`**: Inline
the `_postgres.mdx` partial (now only PostgreSQL is supported), add a
top-level callout, and add a **Managed PostgreSQL / No Admin Access**
section with explicit 3-step instructions and security guidance (strong
passwords, SSL, TLS). Additional improvements: add inline `# Use
'require' or 'verify-full' for production` comments on `Mode: disable`
lines in the YAML example; add clarifying comment to the redundant
`GRANT` in the SQL snippet; replace admonition syntax with proper
Fumadocs `<Callout>` components; add full database connection env vars
to the `start-from-setup` example.
- **`apps/docs/content/self-hosting/manage/updating_scaling.mdx`**:
Rewrite the init phase description to clearly distinguish the
provisioning and schema bootstrapping steps, and document `zitadel init
schema` as the path for manual provisioning. Replace admonition syntax
with proper Fumadocs `<Callout>` components.
- **`apps/docs/content/self-hosting/manage/database/_postgres.mdx`**:
Deleted (content merged into `index.mdx`).
## Problem
This relates to https://github.com/zitadel/zitadel/discussions/9363
I think we can improve our UX in cases where a user wants to use an
external DB and/or does not want to share too broad permissions with
zitadel
## Related problems
* https://github.com/zitadel/zitadel/issues/10432
* https://github.com/zitadel/zitadel/discussions/8583
* https://github.com/zitadel/zitadel/issues/7903
* https://github.com/zitadel/zitadel/issues/9718
* https://github.com/zitadel/zitadel/issues/8012
* https://github.com/zitadel/zitadel/issues/8558
## Related PRs
https://github.com/zitadel/zitadel/pull/11021
This update introduces a trigger that enforces username uniqueness based
on organization-specific settings. It ensures that usernames are unique
when the organization setting for scoped usernames is enabled.
Additionally, tests have been added to verify the functionality across
different organizational settings.
The users table got introduced by #10967
---------
Co-authored-by: Marco A. <[email protected]>
# Which Problems Are Solved
This PR provides an example for testing DB reduction to relational
tables without exploiting integration tests.
# How the Problems Are Solved
- Set up a disposable embedded Postgres DB used to store the results of
the calls to the reducers and verify such results
- Add utility method to return transactions from the existing DB pool.
These transactions can be used by the single test cases to insert and
read data from DB
- Add a test to verify that the handler contains the expected reducers
(checking also that they are on the right aggregate type)
- Add tests to verify the single reduce functions. A parent test creates
the required objects to satisfy the foreign key constraints.
# Additional Changes
- Typo fixed in `postgres.DecodeConfig()`
- Discard unneeded `projectionName` parameter for `Executor` function
# Additional Context
- Closes#11430
# Which Problems Are Solved
The group write model used the `event.ID` field instead of
`event.Aggregate().ID` as aggregate id.
# How the Problems Are Solved
replaced `event.ID` with `event.Aggregate().ID`
# Which Problems Are Solved
Not all frameworks were listed in the Management Console when creating
an application.
# How the Problems Are Solved
Aligned the list from the docs and console.
# Additional Changes
None
# Additional Context
requires backport to v4.x
This PR forces the user to enter a reason/explanation before submitting
a negative feedback. Negative feedback without an explanation is not
actionable.
# Which Problems Are Solved
This PR fixes a couple of minor issues in the docs:
- Duplicated sentences
- Obsolete names
- Wrong header hierarchy
# How the Problems Are Solved
Solved by rewriting/fixing the mdx files.
# Additional Changes
none
# Additional Context
none
# Which Problems Are Solved
#11351 renamed IAM to instance. This included also translation keys in
the backend. As most translation files already contained an `Instance`
in the error section, renaming `IAM` to `Instance` on the same level,
results in a duplicate key.
# How the Problems Are Solved
This PR merges the section to remove the duplictes.
# Additional Changes
None
# Additional Context
- relates to #11351
- backport to v4.x
---------
Co-authored-by: Tim Möhlmann <[email protected]>
Co-authored-by: Copilot <[email protected]>
# Which Problems Are Solved
#11390 renamed "Console" to "Management Console". This included a rename
of the feature key to enable the management console to use the V2 API
for user creation. Due to the rename generated events would also be
changed, resp. existing events would be ignored, which leads to
inconsistency in the data model.
# How the Problems Are Solved
Renamed the key back to `KeyConsoleUseV2UserApi`.
And added a comment to prevent future issues.
# Additional Changes
None
# Additional Context
- relates to #11390
- backport to v4
# Which Problems Are Solved
Adds a repository implementation to add/remove recovery codes to the
users relational table.
# How the Problems Are Solved
This is achieved by:
* adding the following columns to the users table: `recovery_codes`,
`recovery_code_last_successful_check`, `recovery_code_failed_attempts`
* adding the `RecoveryCodes` field to the `HumanUser` domain with fields
to set recovery `codes`, `lastSuccessfullyCheckedAt` timestamp, and
`failedAttempts`
* setting `recoveryCodes` in the `Get` user query statement to return a
json object with details related to the recovery codes
* adding the repository-layer implementation to add/remove recovery
codes and set fields related to recovery code checks.
* adding projection reducers to handle the following events:
`HumanRecoveryCodesAddedEvent`, `HumanRecoveryCodesRemovedEvent`,
`HumanRecoveryCodeCheckSucceededEvent`, and
`HumanRecoveryCodeCheckFailedEvent`
* adding unit tests
# Additional Changes
* fix the error message when the recovery is empty in
`internal/command/user_human_recovery_codes.go`
* add a new error message for empty recovery code during checks in
`en.yaml`
# Additional Context
- Closes https://github.com/zitadel/zitadel/issues/11212
- Follow-up: integration tests for the reducers will be added in a
different PR after this
[PR](https://github.com/zitadel/zitadel/pull/11478) is merged
# Which Problems Are Solved
1. `nx run @zitadel/api:test-unit` panics in
`TestCommandSide_ChangeUserHuman` due to two test cases (added in
0261536) missing the required `loginPaths` field. Since the field type
is `func(*testing.T) LoginPaths`, its zero value is `nil`, and calling
it causes a SIGSEGV.
2. Three targets in `apps/api/project.json` (`test-unit`, `build`,
`build-linux`) were silently non-cacheable because NX does not merge
`cache: true` from `targetDefaults` when a project-level target
overrides other properties like `dependsOn` or `inputs`.
3. `TestServer_AuthorizeOrDenyDeviceAuthorization` integration test is
flaky — it uses hardcoded `5*time.Second` timeouts for `EventuallyWithT`
polling, while the rest of the file uses
`WaitForAndTickWithMaxDuration(ctx, time.Minute)`. Under CI load, 5
seconds is insufficient and the empty ID cascades into a validation
error.
# How the Problems Are Solved
**Test panic fix:**
- Added missing `loginPaths: expectLoginPathsNoCall` to both broken test
cases ("change human email verified (self-management), not allowed" and
"change human phone verified (self-management), not allowed").
**NX cache fix:**
- Added explicit `"cache": true` to `test-unit`, `build`, and
`build-linux` targets in `apps/api/project.json`.
- Verified with `pnpm nx show project @zitadel/api --json` that all
three targets now resolve with `cache: true`.
**Integration test flakiness fix:**
- Replaced all 6 hardcoded `assert.EventuallyWithT(t, ...,
5*time.Second, 100*time.Millisecond)` calls in
`TestServer_AuthorizeOrDenyDeviceAuthorization` with
`require.EventuallyWithT(t, ..., retryDuration, tick)` using
`integration.WaitForAndTickWithMaxDuration(CTXLoginClient,
time.Minute)`.
- Changed from `assert` (non-fatal) to `require` (fatal) so timeout
failures stop the test immediately instead of cascading with empty IDs.
# Additional Context
- The broken unit test landed on main because CI skips `lint_test_build`
on pushes to main (`if: github.ref != 'refs/heads/main'`). A follow-up
issue was created: #11696.
- The integration test flakiness was missed by the previous fix in
#10752.
---------
Co-authored-by: Copilot <[email protected]>
Co-authored-by: Livio Spring <[email protected]>
# Which Problems Are Solved
- Currently, if a user has only secondary authentication methods (like
TOTP) configured but no primary authentication method (Password,
Passkey, or IDP), the login flow fails to handle them correctly,
resulting in an unhelpful "user not found" error when they attempt to
log in.
- These users are not correctly prompted to set up a primary
authentication factor, leaving them in a state where they cannot
successfully authenticate.
# How the Problems Are Solved
- Updated `sendLoginname` to evaluate if a user has an active primary
authentication method (`AuthenticationMethodType.PASSWORD`, `PASSKEY`,
or `IDP`. If they lack a primary method, the flow now correctly
redirects them into the verification/invite process rather than falling
through the method checks and returning a generic error.
- Updated `sendVerification` to replace the empty `authMethodTypes`
array check with a specific check for primary authentication methods.
Now, after completing email/invite verification, users who do not have a
primary authentication method are explicitly redirected to
`/authenticator/set` to set one up.
# Which Problems Are Solved
The login container can only serve HTTP. In deployments where a reverse
proxy is not used, operators need the login container to terminate TLS
itself.
Closes#11473
# How the Problems Are Solved
The container now supports optional HTTPS via three environment
variables that match the pattern already used by the backend server:
`ZITADEL_TLS_ENABLED`, `ZITADEL_TLS_CERTPATH`, and
`ZITADEL_TLS_KEYPATH`. When `ZITADEL_TLS_ENABLED` is not set or set to
`false`, behavior is identical to before. When set to `true`, the server
reads the provided certificate and key files and serves HTTPS using the
lower-level `getRequestHandlers` API from Next.js.
The Docker healthcheck was updated to probe the correct scheme
automatically based on the same environment variable.
# Additional Changes
Added a dockerized integration test that verifies both HTTP and HTTPS
modes using testcontainers.
# Additional Context
The TLS path uses `getRequestHandlers` from
`next/dist/server/lib/start-server` instead of `startServer` because the
latter rejects self-signed certificates in production mode. This is the
same internal API that `startServer` itself calls.
---------
Co-authored-by: Copilot <[email protected]>
Replaces the single-file `docker-compose.yaml` quickstart with a
production-aware, Traefik-based compose pack in `deploy/compose/`. The
pack covers the full arc from a 2-minute localhost quickstart to a
hardened homelab or semi-production deployment.
### What's in the pack
**Stack**: Traefik (proxy) → ZITADEL API (Go `:8080`) + ZITADEL Login
(Next.js `:3000`) → PostgreSQL
All HTTP/gRPC routing is handled by Traefik via Docker labels — no
manual proxy config needed. The Login V2 UI is enabled by default. Login
URLs are derived automatically from `ZITADEL_DOMAIN`,
`ZITADEL_EXTERNALPORT`, and `ZITADEL_PUBLIC_SCHEME` — no separate URL
variables needed.
**Compose files**
| File | Purpose |
|------|---------|
| `docker-compose.yml` | Base stack — works standalone. Uses explicit
`name: zitadel` network for reliable Traefik service discovery. |
| `docker-compose.mode-letsencrypt.yml` | TLS overlay: ACME HTTP
challenge |
| `docker-compose.mode-external-tls.yml` | TLS overlay: upstream LB/CDN
terminates TLS. Uses `forwardedHeaders.trustedIPs` (configurable via
`TRAEFIK_TRUSTED_IPS`) instead of `insecure=true`. |
| `docker-compose.mode-local-tls.yml` | TLS overlay: self-signed certs
for LAN |
| `docker-compose.prodlike.yml` | Splits init / setup / start for
controlled upgrades |
| `docker-compose.test.yml` | CI overlay: swaps images to locally-built
`:local` tags |
**Optional profiles**: `cache` (Redis), `observability` (OpenTelemetry
Collector)
### Build infra
- New `@zitadel/api:pack` and `@zitadel/login:pack` Nx targets build
local Docker images (`zitadel/zitadel:local`,
`zitadel/zitadel-login:local`) for use in CI and local testing
- `apps/api/Dockerfile` now accepts a `BINARY` build arg so local and
release builds share the same image
### Testing
- New `@zitadel/compose` Nx project with targets: `test-config`
(validates all overlay combinations using `--quiet`), `test-run` (starts
full stack with local images), `test-e2e` (Playwright wiring + protocol
matrix tests through Traefik), `test-full` (end-to-end: build → start →
test → teardown), `stop`
- **`@zitadel/compose` is explicitly excluded from `nx affected` in CI
for now** — the full stack smoke test requires a Docker daemon and
significant resources. The intent is to add a dedicated
`compose_smoke_test` CI job in a follow-up. The targets can be run
locally with `pnpm nx run @zitadel/compose:test-full`.
### Documentation
- **`compose.mdx`**: Complete rewrite with a staged structure (Stage 1
Quickstart → Stage 2 Homelab → Stage 3 Beyond Compose). Documents TLS
modes, profiles, secrets hardening, ExternalDomain/Port/Secure
invariant, upgrades, and the path to Kubernetes
- **New `requirements.mdx`**: Lists supported PostgreSQL versions
(14–18), Redis (standalone), Docker Compose v2.x, and reverse proxy h2c
requirements
- **`reverse_proxy.mdx`**: Added intro covering h2c requirements, TLS
modes table, and Login UI routing split
- **`troubleshooting.mdx`**: New sections for container restarts on
upgrade, FIRSTINSTANCE env vars not taking effect, and diagnosing
unhealthy containers
- **`caddy/index.mdx`**: Known issue and workaround for the `TE:
trailers` header hang
- Removed the old
`apps/docs/content/self-hosting/deploy/docker-compose.yaml` embedded in
the docs
### Breaking change
The old `apps/docs/content/self-hosting/deploy/docker-compose.yaml` file
is deleted. The getting-started docs page
(`/self-hosting/deploy/compose`) now points to the new pack via a `curl
| tar` download command.
---
### Checklist
- [x] `deploy/compose/` smoke test passes end-to-end locally (`pnpm nx
run @zitadel/compose:test-full`)
- [x] Docs build passes (`pnpm nx run @zitadel/docs:build`)
- [ ] Follow-up issue created to add `compose_smoke_test` CI job
---------
Co-authored-by: Mridang Agarwalla <[email protected]>
# Which Problems Are Solved
If the `cache.objects`-table does not exist setup failes with the
following error:
`ERROR: relation "cache.objects" does not exist at character 44`
# How the Problems Are Solved
Changed statement to prevent immediately throw an error if the table is
missing.
# Additional Context
- reported in
https://discord.com/channels/927474939156643850/1473769282880934089
- backport to v4
Closes#11199
# Which Problems Are Solved
This PR refactors the login app to load allowed languages and the
default language directly from the Zitadel API equivalents
(`getGeneralSettings`), rather than relying on a hardcoded list. This
ensures that the available languages in the UI and the locale selection
logic match the instance's configuration.
# How the Problems Are Solved
- Fetches allowed languages server-side and passes them to the
LanguageSwitcher
- The NEXT_LOCALE cookie and Accept-Language headers are now strictly
validated against the API-provided allowed languages.
- Fallback: If a cookie requests an unsupported language, the system now
falls back to the API's defaultLanguage (instead of valid but
unconfigured defaults).
# Additional Changes
Helper: Added `getLanguage(code)` to map API language codes to display
names (utilizing Intl.DisplayNames if the code isn't in our static
mapping).
---------
Co-authored-by: Livio Spring <[email protected]>
# Which Problems Are Solved
This PR introduces robust redirect configuration options and enhances
security for Server Actions in multi-domain setups.
# How the Problems Are Solved
- Redirect Fallback Logic: Implemented a unified `resolveRedirectUri`
utility that prioritizes redirect targets as follows:
- Environment override (`DEFAULT_REDIRECT_URI`)
- Organization settings (`defaultRedirectUri`).
- Relative fallback (`/signedin?...`).
- Host Reflection: `DEFAULT_REDIRECT_URI` supports absolute URLs or
relative paths via host reflection.
- Server Action Security: Configured `serverActions.allowedOrigins` to
be dynamically manageable via the `SERVER_ACTION_ALLOWED_ORIGINS`
environment variable (comma-separated list). It defaults to an empty
list for maximum security.
- UI Integration: Updated the /signedin page to use the unified redirect
logic, ensuring consistent behavior for the "Continue" button.
- Documentation: Added type definitions and detailed descriptions for
new environment variables in
`next-env-vars.d.ts`
---------
Co-authored-by: Copilot <[email protected]>
# Which Problems Are Solved
We do have a production checklist for self-hosters which lacks some
important things for our cloud customers.
# How the Problems Are Solved
Adding a production checklist specifically for cloud users
---------
Co-authored-by: Copilot <[email protected]>
Co-authored-by: Florian Forster <[email protected]>
## Summary
This PR introduces the relational user repository for backend v3,
including schema, repository APIs, reducers/projections, and tests for
both human and machine users.
## What changed
* Added user-focused relational migrations (users, verifications,
metadata, PATs, machine keys, passkeys, identity provider links) and
related FK wiring.
* Implemented/expanded repository domain contracts and storage
implementations for human and machine user flows.
* Added support for machine secret handling and aligned access token
type modeling.
* Extended user domain models (verifications, password/email/phone/TOTP
state, passkeys, metadata, invite handling, identity provider links).
* Updated projection/reduction coverage and integration tests for key
user lifecycle events.
* Regenerated and updated mocks/enums plus supporting database
change/column utilities.
## Notes for reviewers
* This PR is large because it establishes the foundational relational
user storage layer and related test scaffolding. Sorry for that.
## Closes
Closes#10218Closes#10224Closes#10225Closes#10209Closes#10802
---------
Co-authored-by: Iraq Jaber <[email protected]>
Co-authored-by: Copilot <[email protected]>
Co-authored-by: Marco A. <[email protected]>
Co-authored-by: Tim Möhlmann <[email protected]>
# Which Problems Are Solved
When running Zitadel behind a reverse proxy and especially when the API
and the login UI don't run on the same domain, Zitadel needs to be
configured to trust the corresponding domains and use them in public
responses, like email links and more.
This can be done by adding a trusted domain. However it's currently only
possible through the API and not in the instance setup process.
# How the Problems Are Solved
Added a possibility to configure multiple trusted domains in the first
instance setup process.
# Additional Changes
None
# Additional Context
- closes#11153
# Which Problems Are Solved
In the refactoring of the logic for the creating and resending of invite
codes (#9962), a bug was introduced where the creating of a new code was
not possible if the request was to return it. It worked when being sent
via mail.
# How the Problems Are Solved
Fixed the check for an existing code.
# Additional Changes
none
# Additional Context
- closes https://github.com/zitadel/zitadel/issues/10718
- requires backport to v4.x
- relates to #9962
Co-authored-by: Marco A. <[email protected]>
<!--
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
- On self-hosted ZITADEL, the CSP `img-src` directive was baked in at
build time from `ZITADEL_API_URL`, blocking branding logos when the
runtime domain differs from the build environment
- CSP construction was duplicated across three files with no single
source of truth
# How the Problems Are Solved
- Introduced a centralized `buildCSP()` function in `src/lib/csp.ts`
that constructs the full CSP string from runtime inputs (`serviceUrl`
for img-src, `iframeOrigins` for frame-ancestors)
- Middleware and flow-initiation now call `buildCSP()` instead of
concatenating strings against a static `DEFAULT_CSP`
- `constants/csp.js` is simplified to a static fallback used only by
`next.config.mjs`
# Additional Changes
- Removed no-op `securitySettings.embeddedIframe.allowedOrigins;`
statements in flow-initiation
- Removed duplicate `X-Frame-Options: SAMEORIGIN` header from
`next.config.mjs` (conflicted with `X-Frame-Options: deny`)
- Added `X-Frame-Options: deny` explicitly on proxy route responses in
middleware (previously relied on next.config.mjs static header surviving
the rewrite)
# Additional Context
- Closes#11088
- Closes#11602
# Which Problems Are Solved
Some graphics used in the docs are using the wrong naming for specific
terms
# How the Problems Are Solved
Replaced graphics with updated terms:
- Role Assignment instead of User Grant, Authorization
- Project Grant instead of Organization Grant
Co-authored-by: Livio Spring <[email protected]>
# Which Problems Are Solved
Update outdated screenshots in the docs.
# How the Problems Are Solved
By replacing the outdated ones with current screenshots
# Additional Changes
Replace the usage of "authorization" with "role assignments" in docs
where it was previously missed.
# Additional Context
- Follow-up for PR https://github.com/zitadel/zitadel/pull/11588
- there are some more docs to be updated, which will be done in a
following PR
---------
Co-authored-by: Copilot <[email protected]>
# Which Problems Are Solved
After a user is deactivated, their sessions are still valid. When the
user is redirected to login page, they're stuck in a loop on a blank
page on the `users/me` endpoint as the user's session is still valid.
# How the Problems Are Solved
By terminating a deactivated user's session. This is done by:
- Adding a new reducer in session projection to delete sessions for
`UserDeactivatedEvent`, `UserLockedEvent` and `UserRemovedEvent` events
- Adding a new reducer in the relation session projection to delete
sessions based on `UserDeactivatedEvent`, `UserLockedEvent` events
# Additional Changes
N/A
# Additional Context
- Closes https://github.com/zitadel/zitadel/issues/10307
- todo: add integration test cases for relational session reducers based
on user deactivated, locked, deleted events
# Which Problems Are Solved
- Docs code blocks that display imported files (YAML configs, Go
examples) render as unstyled plain text with no syntax highlighting,
unlike fenced code blocks which go through `rehypeCode`/Shiki
# How the Problems Are Solved
- Deleted `components/docusaurus/code-block.tsx` entirely — no custom
wrapper is needed anymore
- Replaced all usages with `DynamicCodeBlock` from
`fumadocs-ui/components/dynamic-codeblock` directly in MDX files; it
handles SSR pre-rendering through the same Shiki pipeline as all other
code blocks
- Raw file content (YAML, Go) is imported as strings via webpack's
existing `asset/source` rule already configured in `next.config.mjs` —
no new infrastructure required
- In `_proxy_guide_tls_mode.mdx`, the `Commands` JSX component was
refactored from concatenated JSX array children to a single template
literal string, which is what `DynamicCodeBlock` (and any string-based
highlighter) requires
- All changes applied to both non-versioned docs and versioned snapshots
(v4.10, v4.11)
# Additional Changes
None.
# Additional Context
- Affected MDX files: YAML config files under
`self-hosting/manage/configure/`, reverse-proxy guides,
`self-hosting/deploy/compose.mdx`, and the actions
`testing-request-signature.mdx` guide
<!-- START COPILOT ORIGINAL PROMPT -->
<details>
<summary>Original prompt</summary>
>
> ----
>
> *This section details on the original issue you should resolve*
>
> <issue_title>code block style is weird</issue_title>
> <issue_description>### Preflight Checklist
>
> - [x] I could not find a solution in the existing issues, docs, nor
discussions
> - [x] I have joined the [ZITADEL chat](https://zitadel.com/chat)
>
> ### Describe the docs your are missing or that are wrong
>
> This hurts my eyes:
>
> <img width="867" height="525" alt="Image"
src="https://github.com/user-attachments/assets/b7b66d92-56e1-4e0a-8dba-3cab448930fe"
/>
>
> ### Additional Context
>
> _No response_</issue_description>
>
> <agent_instructions>the user reported a weirdly styled code block in
the docs page where we used to display yaml files. Investigate the docs
and fix the styling</agent_instructions>
>
> ## Comments on the Issue (you are @copilot in this section)
>
> <comments>
> <comment_new><author>@fforootd</author><body>
> haha, ok that is certainly weird, let me look at
that.</body></comment_new>
> </comments>
>
</details>
<!-- START COPILOT CODING AGENT SUFFIX -->
- Fixeszitadel/zitadel#11645
<!-- START COPILOT CODING AGENT TIPS -->
---------
Co-authored-by: copilot-swe-agent[bot] <[email protected]>
Co-authored-by: fforootd <[email protected]>
Co-authored-by: Florian Forster <[email protected]>
<!--
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
The first input field on login screens is not automatically focused,
requiring users to manually click before typing. This creates
unnecessary friction during the login flow, particularly for
keyboard-oriented users and accessibility scenarios.
# How the Problems Are Solved
- Added the `autoFocus` prop to the first `TextInput` in all 12 login
form components.
- For forms with conditionally rendered first inputs
(`set-password-form` and `register-form-idp-incomplete`), `autoFocus` is
set dynamically so the correct field receives focus depending on which
input is visible.
# Additional Changes
None
# Additional Context
- Closes#11565
Co-authored-by: Max Peintner <[email protected]>
<!--
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 <[email protected]>
# 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
Since I and the agents sometimes get confused about which scopes and
types to use in our commits and PRs, I've created an explicit list that
we can verify against our existing `semantic.yml` file.
Co-authored-by: Marco A. <[email protected]>
Co-authored-by: Livio Spring <[email protected]>
# Which Problems Are Solved
The user service v2 didn't allow the specify or change the access token
type for users of type machine and referred to using the management API,
which in return was already deprecated and linked to the user service.
# How the Problems Are Solved
Added a possibility to specify the access token type in the creation and
update request.
# Additional Changes
None
# Additional Context
- closes#10850
- requires backport to v4.x
---------
Co-authored-by: Copilot <[email protected]>
# Which Problems Are Solved
The readme file is using the wrong path for the zitadel logo and
oidc-cert file.
<img width="1252" height="415" alt="Screenshot 2026-02-18 at 15 15 07"
src="https://github.com/user-attachments/assets/dc0dbe79-58fe-4695-ac01-6130b0e8441e"
/>
PR #11166 changed the README path from `./docs/static/logos/` to
`./apps/docs/static/logos/`. However, that same commit actually moved
the file to `apps/docs/public/img/logos/` — the README update used the
wrong destination path.
# How the Problems Are Solved
- Replace image path with the correct one.
# Additional Changes
n/a
# Additional Context
n/a
# 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 <[email protected]>