* fix: add `Scopes` to `Request` interface so that scopes can be validated on all requests
* feat: assert org from scope exists when authorizing requests
* fix: check all scopes
* comments
* check org on callback creation
* fix tests
* clarifications
* fix scope marshaling
* fix: enfore organization for authrequest in initiation
* fix: filter sessions on the accounts page by organization scope
* add integration tests
---------
Co-authored-by: Livio Spring <[email protected]>
Co-authored-by: Max Peintner <[email protected]>
# Which Problems Are Solved
As part of #11035 , this PR implements the IDP intent check logic for
session validation
# How the Problems Are Solved
- Inject encryption algorithm for IDP intent tokens at DB initialization
- Add the IDP intent repository as an invoke option
- Rework crypto mocks using gomock
- Implement IDP intent check logic
- minor - DB: expand IDP Intent deletion testing table with a test case
where IDP intent is not found
# Noteworthy
I did not implement `domain.Transactional` given the doubts that
@adlerhurst expressed in https://github.com/zitadel/zitadel/pull/11804 .
So, there is no transaction AT ALL in here because the `Execute()`
method contains one single DB call (Delete) and `Validate()` just does
Get calls.
# Additional Context
This is a cherry-picked PR + minor changes, coming from
https://github.com/zitadel/zitadel/pull/11164
- Relates to #11035
- Depends on https://github.com/zitadel/zitadel/pull/11804
# Which Problems Are Solved
The total number of configured IDPs seemed of.
We were counting only the IDP table for non-templated IDPs.
# How the Problems Are Solved
Add a count trigger migration for the IDP template table.
Entries will be counted under the existing
`ResourceCountIdentityProvider`
# Additional Changes
- none
# Additional Context
- Reported internally
- Implemented in #9979
- Related https://github.com/zitadel/zitadel/issues/9957
Co-authored-by: Livio Spring <[email protected]>
This PR updates the "Hosted Login UI" documentation to clarify how text
customization works for the new Hosted Login V2.
**Changes:**
1. Adds a warning callout to the "Customization options" section.
2. Clarifies that Login V2 interface texts currently cannot be modified
via the ZITADEL Console UI.
3. Provides the required workaround, directing users to use the Settings
V2 API to patch translation keys using the en.json locale file as a
reference.
---------
Co-authored-by: Copilot Autofix powered by AI <[email protected]>
# Which Problems Are Solved
We found multiple cases where potentially a panic occurred or could
occur:
- when de/encrypting certain information
- returning apps without any configuration type (?)
- apple IdPs without a proper private key
# How the Problems Are Solved
- Added nil checks
- Check private key format for apple IdPs
- Added necessary helper function
# Additional Changes
Fixed i18n yaml where the IDP errors were indented under `org` instead
of directly under `errors`.
# Additional Context
- requires backport to v4.x
---------
Co-authored-by: Marco A. <[email protected]>
# Which Problems Are Solved
Instead of encoding the private key as base64 and setting it in the env
as SYSTEM_USER_PRIVATE_KEY it is sometimes easier to write it to disk
and use a file path. This is for example also possible when setting up
system users in zitadel core.
# How the Problems Are Solved
Added SYSTEM_USER_PRIVATE_KEY_FILE which is preferred over
SYSTEM_USER_PRIVATE_KEY and expects a file path to a private key in PEM
format (like SYSTEM_USER_PRIVATE_KEY but not base64 encoded). To prevent
loading the private key too often it is cached.
---------
Co-authored-by: Ramon <[email protected]>
# Which Problems Are Solved
It was possible to create a user with an imaginary org.
# How the Problems Are Solved
Check whether org exists before creating the user.
# Additional Changes
# Additional Context
- Closes#11532
# 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.
# Which Problems Are Solved
The OTEL service.name resource attribute is hardcoded to "ZITADEL" in
setupOTelSDK, so the Instrumentation.ServiceName config and the
OTEL_SERVICE_NAME environment variable are both ignored. This makes it
impossible to distinguish between multiple Zitadel instances or
co-located services in tracing dashboards and alerting rules.
# How the Problems Are Solved
The hardcoded string is replaced with cfg.ServiceName so the configured
value flows through. An explicit check for the OTEL_SERVICE_NAME
environment variable is added at the top of resourceWithService, giving
it the highest priority per the OpenTelemetry specification.
# Additional Changes
None.
# Additional Context
Closes#11455
Backport to v4
# Which Problems Are Solved
As part of #11035 , this PR implements the password check logic for
session validation
# How the Problems Are Solved
- Add system config to default configuration of `domain` package for
easy initialization. Intialize the system settings when Zitadel starts
up
- Add password hasher verify logic to the default configuration of
`domain` package. Initialize it when Zitadel starts up.
- Add settings repositories with their mocks
- Implement the logic for doing a password check
# Additional Context
This is a cherry-picked PR + minor changes, coming from
https://github.com/zitadel/zitadel/pull/11164
- Relates to #11035
- Depends on https://github.com/zitadel/zitadel/pull/11777
# Which Problems Are Solved
Adds support for returning CreateUser/UpdateUser action payloads from
RetrieveIdentityProviderIntent so Actions v2 can update user metadata
(and other fields) using the v2 user APIs, ensuring parity with user
creation using Actions v2.
# How the Problems Are Solved
By:
- deprecating `AddHumanUser` and `UpdateHumanUser` fields in
`RetrieveIdentityProviderIntentResponse`
- adding a oneof field called `UserAction` with `CreateUser` and
`UpdateUser` fields to support user creation/update
- setting `UserAction` in the `RetrieveIdentityProviderIntentResponse`
for user creation/update
# Additional Changes
N/A
# Additional Context
- Related to https://github.com/zitadel/zitadel/issues/11369
- Follow-up for PRs https://github.com/zitadel/zitadel/pull/11719,
https://github.com/zitadel/zitadel/pull/11747
- Actions V2 example docs will be updated in a follow-up PR
---------
Co-authored-by: Copilot <[email protected]>
# Which Problems Are Solved
- `@zitadel/docs:generate-proto-docs` could block while `npx` waited for
confirmation to install `@bufbuild/buf`.
- When the docs generation ran through `nx run-many --target generate`,
that interactive prompt was hidden, so the task appeared stuck without
visible output.
# How the Problems Are Solved
- Resolve Buf from the workspace root with `pnpm exec buf generate` so
the repo-pinned CLI is used non-interactively.
- Run the Buf command from the workspace context instead of the
temporary execution directory.
- Keep the existing generation arguments, template handling, and
excluded path handling intact.
# Additional Changes
- Remove the temporary directory setup that was only needed for the
previous `npx`-based invocation.
- Keep the existing `protoc-gen-connect-openapi` installation and PATH
wiring unchanged.
# Additional Context
- Follow-up for the docs generation issue discussed in Discord where
`@zitadel/docs:generate-proto-docs` prompted for `@bufbuild/buf`
installation and appeared blocked under `nx run-many --target generate`.
- Validated with `pnpm nx run @zitadel/docs:generate-proto-docs
--outputStyle=stream`.
- Validated with `pnpm nx run @zitadel/docs:generate
--outputStyle=stream`.
# Which Problems Are Solved
- Apple Sign-In uses a Form Post method to return the authorization
response, which ZITADEL handles at a specific endpoint ending in /form
for the login v1.
- The Console previously displayed the standard callback URL (without
`/form`), causing confusion and configuration errors..
# How the Problems Are Solved
- **Console**: Updated ProviderNextService to accept a suffix string .
- **Console**: Updated ProviderAppleComponent to append the suffix to
the urls.
# Additional Changes
- Updated `docs/docs/guides/integrate/identity-providers/apple.mdx` to
explicitly state that the callback URL end with `/form`
- Updated `docs/docs/guides/integrate/login-ui/external-login.mdx` to
clarify the `/form` suffix requirement for Apple Sign-In in the hosted
login documentation.
# Additional Context
- fixes#11438
---------
Co-authored-by: Ramon <[email protected]>
Co-authored-by: Florian Forster <[email protected]>
# Which Problems Are Solved
In #11239 , the helper function for matrix tests (without the relational
tables enabled) was changed, but the feature was never enabled in the
matrix. Some integration tests currently can't even succeed because of
missing implementations.
# How the Problems Are Solved
This PR correctly enables the feature where intended and returns the
state into the matrix.
This allows returning early for some tests which cannot succeed yet.
Corresponding todos have been re-added as well.
# Additional Changes
None
# Additional Context
- relates to #11239
- requires backport to v4.x
# Which Problems Are Solved
The login v2 container has no way to verify upstream Zitadel API
connectivity before accepting traffic. The existing `/healthy` endpoint
always returns 200 regardless of whether the backend is reachable. This
means Kubernetes routes user traffic to pods that cannot actually serve
login requests, causing silent failures where the root layout swallows
gRPC errors and renders pages with default settings.
# How the Problems Are Solved
A new `/ui/v2/login/ready` endpoint creates a gRPC client using the same
auth and transport path as real requests, calls
`SettingsService.getGeneralSettings()`, and returns `200 OK` on success
or `503 Service unavailable` on failure. This verifies both network
connectivity and authentication credentials to the upstream Zitadel API.
Kubernetes supports readiness probes natively, so this endpoint can be
configured as a readiness probe to gate traffic until the login
container can connect to Zitadel. Docker Compose does not have a
readiness probe concept, so the compose healthcheck and
`healthcheck.mjs` default remain unchanged and continue using
`/healthy`.
The Docker HEALTHCHECK in the Dockerfile has been updated to use
`/ready` so that the image-level health status reflects actual upstream
connectivity. This will also allow us to simplify the Helm chart by
dropping the `wait4x` init containers that currently poll the Zitadel
API before starting the login pod, since the readiness probe makes them
redundant.
# Additional Changes
The `/ready` endpoint has been added to the OTEL HTTP instrumentation
ignore list to avoid noisy probe traces. Unit tests, a wiring spec
integration test, and an OTEL span filtering test have been added for
the new endpoint. The `# TODO: Check healthy, not ready` comment has
been removed from the Dockerfile. The `/healthy` endpoint is kept as-is
for liveness probes.
# Additional Context
The Helm chart changes to use `/ready` for readiness and startup probes
and to remove the `wait-for-zitadel` init container will be done in a
follow-up PR in the `zitadel-charts` repository.
## Problem
ZITADEL has inconsistent naming across docs, UI, and API
([#5888](https://github.com/zitadel/zitadel/issues/5888)). We want
contributors and Copilot code-review agents to flag discouraged terms
and suggest canonical replacements automatically.
## Solution
Add a **Markdown terminology catalog** that Copilot agents read
natively.
### What's added
- **`TERMINOLOGY.md`** (repo root) — full ~35-term canonical table from
issue #5888 with:
- Action legend: `keep` / `replace` / `remove` / `internal` / `proposed`
- Scope legend: `UI` / `Docs` / `API` / `Everywhere`
- "Search for (discouraged)" and "Replace with / enforce" columns
- Governance section (how to add new terms, ownership)
- **`.github/instructions/terminology.instructions.md`** — Copilot
`applyTo`-scoped instruction that activates on every PR touching
docs/i18n/proto files and tells the agent:
- Which files map to which scope
- Not to flag identifiers/field names in proto files (only
comments/descriptions)
- To request catalog updates when new terms are introduced
### What's updated
- `.github/copilot-instructions.md` — points to `TERMINOLOGY.md`
- `apps/docs/AGENTS.md` — updated reference, removed dead
`check-terminology` Nx target entry
- `.github/pull_request_template.md` — checklist item updated
- `.github/workflows/ready_for_review.yml` — checklist item updated
### Why Markdown over JSON
| | Markdown | JSON |
|---|---|---|
| Copilot reads natively | yes | no (needs parsing context) |
| Mirrors AGENTS.md table style | yes | no |
| Human-readable without tooling | yes | no |
| Mirrors the #5888 issue format | yes | no |
| Requires schema / parser | no | yes |
### Why root over `.github/`
`.github/` is for GitHub-specific automation files. `TERMINOLOGY.md` is
a project-wide convention document — it belongs alongside
`CONTRIBUTING.md`, `CODE_OF_CONDUCT.md`, and `AGENTS.md` at the repo
root.
## How it works in practice
When a PR touches `apps/docs/content/**`, `console/src/assets/i18n/**`,
`apps/login/locales/**`, or `proto/**/*.proto`, Copilot code review
automatically loads `.github/instructions/terminology.instructions.md`
and cross-references `TERMINOLOGY.md` to flag discouraged terms.
Human reviewers see the terminology checklist in the auto-comment on PR
open.
## Checklist
- [x] `TERMINOLOGY.md` at repo root with all ~35 terms from #5888
- [x] Plain text action/scope values (no emojis)
- [x] Copilot instruction file scoped to correct file patterns
- [x] All stale `terminology-rules.json` references removed
- [x] No linter/CI step added (guidelines-only approach)
Relates to: #5888
---------
Co-authored-by: Copilot <[email protected]>
Co-authored-by: Fabienne Bühler <[email protected]>
# Which Problems Are Solved
The distinction between Example Applications and SDKs has not been
clear. In the SDKs section a lot of Example applications where listed.
Also In the SDKs it was not really clear what the SDKs actually are.
Also some examples and skds are outdated and not well maintained
anymore.
# How the Problems Are Solved
- Moved all example app guides to the Example Applications Section
- Restructured SDKs Nav --> SDKs & Integrations: Frontend & Mobile,
Backend & API, Management API Clients
- Removed unnecessary / outdated guides
- Remove ids in framework.json for frameworks which shouldn't be
rendered in console
## Todos:
- Update SDKs Introduction page
- Add links to common oidc libs for most used frameworks
---------
Co-authored-by: Mridang Agarwalla <[email protected]>
# Which Problems Are Solved
The Management Console was still using the deprecate v2beta endpoints of
the webkey service even though the v2 service was move to GA a while
ago.
# How the Problems Are Solved
Switch to the v2 endpoints.
# Additional Changes
None
# Additional Context
- relates to #10773
When an expired invite code was used for webauthn (passkeys), the change date got updated by the failed event. This change date was used to test for expiry, meaning failed events would reset the expiry timeout.
This fix adds a Code Creation Date to the writemodel which gets set by the first event. This can be the added or requested event.
Other changes:
- Expiry renamed to CodeExpiry so it's consistent with similar write models using secret codes.
- humanVerifyPasswordlessInitCode takes an algorithm instead of the complete generator, so the method can be unit tested easier
- Added tests that reproduced the original issue
## Problem description
During tests we found concurrency issues in the relational table
projections. Tests got flaky if a table (e.g. organization domains) had
too many foreign keys to tables which were projected by another handler.
## Resolution
The projections of the relational tables got merged into one handler to
enforce sequential reduction of events.
## Additional info
- closes https://github.com/zitadel/zitadel/issues/11703
- closes https://github.com/zitadel/zitadel/issues/10810
---------
Co-authored-by: Marco Ardizzone <[email protected]>
# Which Problems Are Solved
- The organization name in the user grants table was not consistently
displayed. The `grantedOrgName` property was sometimes missing,
resulting in an empty or incorrect value in the 'org' column.
# How the Problems Are Solved
- Implements a conditional check for the 'org' column in the user grants
table. The cell now displays `grantedOrgName` if available, otherwise it
falls back to `orgName`.
# Additional Changes
- Imports and adds `TypeSafeCellDefModule` to the user grants module,
providing the `cnslCellDef` directive for more flexible and type-safe
cell definitions.
# Additional Context
- Fixes#10822
---------
Co-authored-by: Copilot <[email protected]>
# Which Problems Are Solved
Invalid formatting in the login codebase due to invalid prettier
configuration
# How the Problems Are Solved
Fxed .prettierignore wildcards for login source files
# Additional Changes
Removed .prettierrc file because there is already a prettier.config.mjs
file
# Additional Context
# Which Problems Are Solved
The management console deletes all roles if user grant is not
manipulated before saving in the dialog.
# How the Problems Are Solved
Correctly prefill the selected role assignments so when no change was
done we keep the current state.
# Additional Changes
- Prevents displaying misleading error messages to users when a role
assignment operation results in no actual changes.
# Additional Context
- Closes#10517
Co-authored-by: Max Peintner <[email protected]>
Closes#11096
# Which Problems Are Solved
This pull request resolves a 404 error that occurred at the end of the
LDAP login flow.
Previously, when a user submitted their LDAP credentials in the
apps/login application, the form initiated the session creation process
but incorrectly redirected the user to /idp/ldap/success, a route that
does not exist. In addition, the redirect failed to preserve necessary
IDP context parameters (such as requestId, organization, and linking
fingerprint info) that are required to fully complete the authentication
intent.
# How the Problems Are Solved
- Fixed redirect path: Updated `createNewSessionForLDAP` to redirect to
`/idp/ldap/process` instead of success, aligning it with the standard
IDP intent processing pipeline which dynamically resolves
`[provider]/process`.
- Preserved context parameters: Extracted `requestId`, `organization`,
`postErrorRedirectUrl`, `linkToSessionId`, and `linkFingerprint` from
the URL parameters on the LDAP page and passed them through
LDAPUsernamePasswordForm down to the server action so the ongoing auth
request is successfully tied to the user's intent.
# Which Problems Are Solved
As part of #11035 , this PR implements the user check logic for session
validation
# How the Problems Are Solved
- Add user and session repositories as invoke options, as well as their
mocks to prepare the ground for testing
- Implement the logic for the UserCheck command, following what has been
done on eventstore side
- Add a session permission chek interface to be used during the
`Validate()` part of the Commander
# Additional Context
This is a cherry-picked PR + minor changes, coming from
https://github.com/zitadel/zitadel/pull/11164
- Relates to #11035
---------
Co-authored-by: Silvan <[email protected]>
# Which Problems Are Solved
Organization managers could not be removed in the add manager modal
# How the Problems Are Solved
Correctly emit a change event in the SearchUserAutocompleteComponent to
update dependent components.
# Additional Changes
# Additional Context
- Closes#11543
# Which Problems Are Solved
Add integration tests for recovery codes event reducers in the RT model.
# How the Problems Are Solved
Added integration tests for recovery codes event reducers
# Additional Changes
N/A
# Additional Context
- Closes https://github.com/zitadel/zitadel/issues/11707
- Todo: add tests for other reducers in the `users_relational`
projection.
---------
Co-authored-by: Livio Spring <[email protected]>
# Which Problems Are Solved
This is a small refactoring for tests in `backend/v3/domain` package to
use `assert.ErrorIs` instead of `assert.Equal` for error assertion.
# How the Problems Are Solved
- Add custom `Is()` function to `MultipleObjectsUpdatedError` error
- Substitute `assert.Equal` with `assert.ErrorIs` in instance and
organization tests
# Additional Context
This was part of #11035
## Problem description
When calling `repository.UserRepository().Get(...)` the following error
got returned caused by scanning.
`Scan error: scanning: doing scan: scanFn: scany: scan row into struct
fields: sql: Scan error on column index 7, name "metadata": unsupported
Scan, storing driver.Value type []uint8 into type *[]*domain.Metadata`
## How the problem got solved
The issue was that json arrays were not properly unmarshalled during
scanning the rows into structs.
## Additional changes
The issue could also happen on login names, therefore it got fixed for
this field too. Other fields are not affected because we use
`json.RawMessage` for the specific user types.
## Additional information
Introduced in https://github.com/zitadel/zitadel/pull/10967
- Transitioned from using `handler.Statements` to a repository pattern
for managing organization data in migrations.
- Introduced a new method to set the updated timestamp for
organizations.
- Updated the projection logic to utilize the repository for creating,
updating, and deleting organization records.
Closes#11138
# Which Problems Are Solved
Previously, the application strictly checked the allowRegister
setting—which typically applies to local account creation—before
considering if a user without an account should be redirected to an IDP,
or whether they could access the register page. This blocked users from
registering via identity providers when local registration was disabled
but IDPs were configured.
# How the Problems Are Solved
- Removed the allowRegister dependency when deciding to redirect an
unknown user to an IDP. The logic now only checks
!allowLocalAuthentication, correctly opening up the IDP registration
flow even when local auth/registration is not allowed.
- Modified the block condition so the register page is only restricted
if allowRegister is false and there are no configured identityProviders
available.
<!--
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. Do not remove any of the sections.
-->
# Which Problems Are Solved
The `/apis/introduction` page did not give developers clear guidance on
which API version to use. v1 and v2 were presented as equal choices, the
v2 resource list was incomplete, the API path prefix block was
misleading, and several links used inconsistent relative paths.
- No clear recommendation to use v2 for new integrations
- v1 APIs not labelled as legacy
- "APIs v2" section only listed 3 of 15 available v2 services
- Path prefix block only listed 5 of 15 v2 gRPC service paths, with no
distinction between REST and gRPC/Connect access patterns
- `/ui/` path listed as a single entry — the Management Console
(`/ui/console/`) and hosted Login UI (`/ui/login/`) were not
distinguished
- Relative links (`../guides/...`, `./assets/assets`) inconsistent with
the rest of the page
- Auth disclaimer paragraph was confusing; "Custom" section heading was
unclear
# How the Problems Are Solved
- **v2-first framing**: Added a clear directive — "Use the v2 APIs for
all new integrations" — and renamed the old section to "Legacy v1 APIs"
- **Complete v2 resource list**: All 15 v2 services now listed with
one-line descriptions (User, Session, Org, Instance, Project,
Application, IDP, Group, Settings, Feature, Authorization, Action,
WebKey, OIDC, SAML)
- **Full path prefix list**: All 15 v2 gRPC service paths listed; split
into `# REST (HTTP/JSON transcoding): /v2/` and `# gRPC + Connect
protocol (binary or JSON via connectRPC):`
- **`/ui/` paths clarified**: Split into `/ui/console/` (Management
Console) and `/ui/login/` (Hosted Login UI) with inline comments
- **Fixed relative links**: `../guides/...` → `/guides/...`;
`./assets/assets` → `/apis/assets/assets`
- **Section copy improvements**: Auth disclaimer removed; "Custom"
renamed to "Session-based and custom login" with clear bullet list; v1
API card descriptions updated with v2 pointers; Assets card, System card
title fix
- **Client libraries section**: Replaced noisy "API definitions" section
with cleaner "Client libraries & schemas"
# Additional Context
All changes are in `apps/docs/content/apis/introduction.mdx`,
`apps/docs/content/apis/v2.mdx`, and
`apps/docs/content/apis/migration_v1_to_v2.mdx`.
Co-authored-by: Copilot <[email protected]>
# Which Problems Are Solved
* v2 login ui was ignoring oicd `ui_locales` making it impossible to
sync the login ui locale with the apps ui
# How the Problems Are Solved
- Read `uiLocales` from `authRequest`
- check all listed if valid in ui
- take the first valid one
- set language cookie (if a valid locale is pressent in uiLocales)
# Additional Changes
- tests
# Additional Context
---------
Co-authored-by: Florian Forster <[email protected]>
Co-authored-by: Max Peintner <[email protected]>
# Which Problems Are Solved
The login unit tests broke due to a recent merge.
# How the Problems Are Solved
This PR fixes the broken tests.
# Additional Changes
None
# Additional Context
- requires backport to v4.x
## What
Shorten the `title` frontmatter on 20 docs pages so that the rendered
`<title>` tag stays within the 70-character SEO limit.
The root layout appends ` | ZITADEL Docs` (15 chars) to every page
title, meaning the raw frontmatter `title` must be ≤ 55 characters. A
site scan flagged all 20 pages for the "Title too long" warning (titles
ranged from 71 to 92 characters in the final rendered tag).
## Why
Search engines may truncate or ignore `<title>` tags longer than 70
characters, hurting click-through rates and keyword relevance in search
results.
## How
Each title was rewritten to:
- Fit within 55 characters (leaving room for ` | ZITADEL Docs`)
- Front-load the primary search keyword (product name, protocol, or
feature)
- Include "ZITADEL" where users realistically search for `{feature}
ZITADEL`
- Avoid generic filler words ("Configure", "Set up", "Support for")
All 20 files already have a `sidebar_label` field that preserves the
original descriptive title for sidebar navigation — no navigation
changes result from this PR.
## Pages updated
| Page | Before (chars) | After (chars) |
|---|---|---|
| concepts/features/passkeys | 82 | 64 |
| guides/integrate/identity-providers/openldap | 72 | 58 |
| guides/solution-scenarios/b2b | 78 | 59 |
| guides/integrate/services/cloudflare-oidc | 86 | 54 |
| guides/integrate/login/hosted-login | 71 | 55 |
| guides/integrate/service-accounts/private-key-jwt | 76 | 56 |
| guides/integrate/service-accounts/client-credentials | 78 | 60 |
| guides/integrate/services/google-cloud | 92 | 57 |
| guides/solution-scenarios/saas | 88 | 65 |
| guides/migrate/sources/auth0 | 73 | 65 |
| guides/integrate/login-ui/oidc-standard | 81 | 55 |
| guides/integrate/login-ui/username-password | 73 | 59 |
| guides/integrate/login-ui/device-auth | 78 | 60 |
| guides/integrate/identity-providers/linkedin_oauth | 72 | 58 |
| guides/integrate/identity-providers/pingfederate-saml | 74 | 61 |
| guides/integrate/service-accounts/personal-access-token | 82 | 62 |
| legal/service-description/cloud-service-description | 76 | 61 |
| guides/integrate/login/login-users | 83 | 55 |
| guides/integrate/identity-providers/migrate | 74 | 65 |
| guides/manage/console/projects-overview | 71 | 62 |
All final `<title>` values are between 54 and 66 characters (well under
the 70-char limit).
# 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]>