4625 Commits
Author SHA1 Message Date
Max PeintnerandGitHub 17f49323dd fix(login): preserve OIDC request context during email verification (#11990)
# Which Problems Are Solved

When a user needed to verify their email during an OIDC login flow, the
requestId was lost, preventing the flow from completing with a redirect
back to the relying party.

# How the Problems Are Solved

In `sendVerification()`, the session cookie lookup used `"loginName" in
command` to decide whether to fall back to `user.preferredLoginName`.
Since the `loginName` property key always exists in the command object
(even when its value is undefined), the fallback was never triggered.
This caused the lookup to search for loginName === undefined, finding no
session — and ultimately redirecting to a dead-end success page.

- /authenticator/set redirect: Added missing requestId to the URL params
when redirecting users who need to set up a primary auth method.
- /verify/success page: Added a "Continue" button that re-enters the
login flow with requestId preserved, handling the edge case where no
session cookie exists (e.g. email link opened in a different browser).
2026-04-08 10:25:43 +02:00
Livio SpringandGitHub fbb6a406c8 chore: fix generators in crypto package (#12008)
# Which Problems Are Solved

`@zitadel/api:generate-go` failed due to duplicate generated files.
https://github.com/zitadel/zitadel/pull/11820 removed the old generated
file and added a generate command to the `internal/crypto/crypto.go`
file. However, there was already a `internal/crypto/generate.go` with a
different output file name (the old file).

# How the Problems Are Solved

Removed the `internal/crypto/generate.go` file and moved the second
generate into `internal/crypto/code.go`.

# Additional Changes

Noticed that mockgen is an old version and updated it. Also then checked
all other tools and updated them.

# Additional Context

- relates to #11820
- noted internally
2026-04-08 08:48:05 +02:00
Wim Van LaerandGitHub 99ad1ea83d test: added checks for timestamps in passkey test (#12003)
# Which Problems Are Solved

A test was failing because of timezone flakiness

# How the Problems Are Solved

The actual problem was an `updatedAt` field was not filled in because of
the `createdAt` was missing on an event. This caused a zero value to be
filled in into the `updatedAt` field. Postgres then stored this value
with seconds in it's timezone info, which go could not store.

By adding filling in the `createdAt` field, this does not occur.
2026-04-07 16:27:45 +02:00
RamonandGitHub 5abb51c263 chore: deps update (#11981)
# Which Problems Are Solved

After merging #11968 and rechecking the dependabot alerts there are
still some issues leftover.

# How the Problems Are Solved

This pr makes overrides for vulnerable transitive depdencies to force
update to safe versions.
It also upgrades the next.js version in the docs and I also ran `pnpm
update` once more.

# Additional Changes

Removed the mochaawesome dependency is this is not really needed and
seems unmaintained.

# Additional Context

- Precursor: #11968
2026-04-07 14:14:12 +02:00
RamonandGitHub 23f0cd0ade chore(console): remove all console eslint warnings (#11853)
<!--
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

When running the nx target @zitadel/console:lint-check-ng currently
there are a lot of eslint warnings.

# How the Problems Are Solved

Removed unused variables, imports etc.

# Additional Changes

# Additional Context
2026-04-07 09:28:22 +00:00
f803ea8298 feat(login): add Portuguese (pt) translations for Login V2 (#11897)
## What does this PR do?

Adds complete **Portuguese (pt)** locale translations for the Login V2
interface, making it the 14th supported language.

### Problem

The Login V2 component currently supports 13 languages but does not
include Portuguese — one of the most spoken languages in the world
(~260M native speakers). This was reported in #11782.

### What we found

- The Login V2 translations are stored as JSON files under
`apps/login/locales/`
- Available languages are registered in the `LANGS` array in
`apps/login/src/lib/i18n.ts`
- Portuguese (`pt.json`) was missing from both the locales directory and
the `LANGS` array

### What we did

1. Created `apps/login/locales/pt.json` with complete Portuguese
translations for all login screens (loginname, password, register, MFA,
passkeys, OTP, sessions, errors, etc.)
2. Added `{ name: "Português", code: "pt" }` to the `LANGS` array in
`apps/login/src/lib/i18n.ts`

### Translation methodology

- Based on the existing `en.json` and `es.json` as reference
- Follows Brazilian Portuguese (pt-BR) conventions, which is understood
by all Portuguese-speaking countries
- All keys translated — no fallbacks to English needed

### Files changed

| File | Change |
|------|--------|
| `apps/login/locales/pt.json` | **New** — Complete Portuguese
translations |
| `apps/login/src/lib/i18n.ts` | **Modified** — Added `pt` entry to
`LANGS` array |

### Testing

We built and deployed this change from source (tag v4.12.1) to a
production Zitadel instance:

- ✅ Portuguese appears in the language dropdown  
- ✅ All login screens display correct Portuguese translations  
- ✅ Language selection persists across pages  
- ✅ OIDC flow works correctly with Portuguese selected  
- ✅ No build warnings or errors related to the translation  

Closes #11782

Co-authored-by: rofilho <[email protected]>
2026-04-07 10:51:55 +02:00
RamonandGitHub 6877f09c84 fix(console): disallow smtp double create #8964 (#11868)
<!--
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

When creating a new smtp providers it was possible to click the create
button multiple times and create duplicate smtp providers.

# How the Problems Are Solved

Disable the create button when the smtp provider creation is pending.

# Additional Context
- Closes: #8964
2026-04-03 10:12:25 +00:00
0945195f68 chore: deps update (#11968)
# Which Problems Are Solved
This pr updates major and minor dependencies and is the first step on
getting our dependabot alerts cut down.

# How the Problems Are Solved

Depedency updates across the board eg:
- Upgrade Angular to v21
- Upgrade next.js to v16.2
- Upgrade tailwind to v4 in the login
- Upgrade vitest to v4 in the login

This is an uncompleted list refer to the changed files for a full
overview of all the updates.

# Additional Changes

Migrated all control flow in the console to the modern control flow
syntax.
Fixed the dependsOn setting for the @zitadel/login:test-unit nx target.

# Additional Context

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

---------

Co-authored-by: Max Peintner <[email protected]>
2026-04-02 15:53:08 +02:00
Max PeintnerandGitHub 891c7473ca fix(login): invite flow instead of email verification for users with no primary method, improve sending behaviour (#11837)
Closes #10929

# Which Problems Are Solved

When a human user without a primary authentication method enters their
email on the login screen, the login historically auto-sent an email
code (send=true) and redirected them to the `/verify` flow. If the user
was newly created via the API and already received an initial
verify-email, navigating to the login page would trigger a new invite
code, silently invalidating the code they received in their first email.
Additionally instead of resending the same type of email (invitation) a
regular email verification mail was sent

# How the Problems Are Solved
- Resend an invitation email instead of a email verification if a user
has no method set (still in invitation state)
- Conditional Code Sending: Updated `loginname.ts` to check
`humanUser?.email?.isVerified`. We only auto-send a new code
(`send=true`) if the user's email is already verified. Unverified users
will be redirected with `send=false`, allowing them to safely enter the
code they already have.
- UI State Fix: Fixed an issue in `verify/page.tsx` where the send URL
parameter was being checked directly as a string ("false" is truthy). By
using the properly evaluated doSend boolean, the "Code Sent" alert now
correctly hides itself when a new code is not explicitly sent.
- Translation Updates: Refined the codeSent messaging across all locales
to specify "A new code has been sent..." to provide better context to
the user when they do explicitly request a resend.
2026-04-02 09:58:20 +02:00
Mridang AgarwallaandGitHub 140f07e60b feat(login): simplify login client auth and support PKCS#1 keys (#11888) 2026-04-02 13:10:57 +05:30
Aaron DewesandGitHub c97ffd6eb7 fix(console): pass data to user delete dialog (#11595)
# Which Problems Are Solved

The account deletion modal for users with the user.self.delete
permission was previously broken (displayed no text) because the
properties were not passed to it:

<img width="1920" height="951" alt="grafik"
src="https://github.com/user-attachments/assets/3bfc6126-1777-4f1a-9fa9-c151a8275cea"
/>


# How the Problems Are Solved

The data is correctly passed to the modal.
2026-04-01 17:22:14 +02:00
c7f92a6887 feat: session challenge passkey for the RT model (#11944)
# Which Problems Are Solved

Add Passkey challenge needed for Create/Set session in the RT model.

# How the Problems Are Solved

Introduce `PasskeyChallengeCommand` (validate/execute/events) for
session creation checks
Add a generic `BeginWebAuthNLogin` helper that returns session data +
assertion JSON bytes.
Add unit tests

# Additional Changes
N/A

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

---------

Co-authored-by: Copilot <[email protected]>
Co-authored-by: Marco A. <[email protected]>
2026-04-01 12:13:40 +02:00
Marco A.andGitHub 701bca6003 feat(session): TOTP Check API with relation tables (#11886)
# Which Problems Are Solved

As part of #11035 , this PR implements the TOTP check logic for session
validation

# How the Problems Are Solved

  - Implement TOTP check logic and tests
- The tarpit function has been moved to a common file so that it can be
used by both TOTP and password checks
- Manual transaction management to avoid stalling the DB while verifier
function is executed
- Update `database.Change` `Matches()` function to allow comparison of
`time.Time` values
  - A converter package from GRPC to Domain model has been added

# Additional Context

This is a cherry-picked PR + changes, coming from
https://github.com/zitadel/zitadel/pull/11164
- Relates to #11035
2026-04-01 11:34:03 +02:00
Vitor Bari BucciantiandGitHub 8c8fc47884 fix(console): Fix onboarding link for user login guide (#11958)
# Which Problems Are Solved

Onboarding steps has broken link to log in documentation:
https://zitadel.com/docs/guides/integrate/login-users

<img width="974" height="409" alt="Screenshot 2026-03-27 at 15 41 58"
src="https://github.com/user-attachments/assets/51863a49-14a2-45f2-b767-cf072dc30ea6"
/>

# How the Problems Are Solved

Change broken link to
https://zitadel.com/docs/guides/integrate/login/login-users

# Additional Changes

n/a

# Additional Context

n/a
2026-04-01 09:01:43 +00:00
5344a7f584 fix: invalid jwt assertion error handling (#11933)
# Which Problems Are Solved

Incorrectly mapped errors on the `/oauth/v2/token` endpoint lead to a
large number of HTTP status 500 errors.

# How the Problems Are Solved

By mapping invalid jwt assertion errors to OIDC `invalid_client` errors,
which returns a HTTP status 400.

# Additional Changes

N/A

# Additional Context

- Closes https://github.com/zitadel/zitadel/issues/11924
- Follow-up: 
- Fix the [error
handling](https://github.com/zitadel/oidc/blob/main/pkg/oidc/verifier.go#L195)
in the oidc package

---------

Co-authored-by: Copilot <[email protected]>
2026-04-01 10:44:02 +02:00
Mridang AgarwallaandGitHub 330548e13c feat: support standard OTEL env vars via autoexport (#11864) 2026-04-01 06:14:21 +00:00
Marco A.andGitHub 7a15a06d69 fix: reducer for PasskeyVerified sets VerifiedAt (#11929)
# Which Problems Are Solved

In https://github.com/zitadel/zitadel/pull/11858#discussion_r2993742914
we discussed on how to translate the ES passkey state to a relational
one. That is used to filter out passkeys during convertion to webauthn
credentials.

It was decided to consider passkeys in ready state those that have a
verified at `time.Time` set.

The change required fixing the reducer for the eventstore event.

# How the Problems Are Solved

  - Set `VerifiedAt` once `HumanWebAuthNVerifiedEvent` is received
  - Also set the verification to `nil`

# Additional Context

- Discussion #11858
- Follow-up for PR #11858
2026-03-31 17:38:47 +02:00
Max PeintnerandGitHub ec0bd5790f fix(login): respect branding themeMode for theme toggle, fix CSP (#11903)
Closes #11721

# Which Problems Are Solved

The login app now correctly handles the themeMode from branding
settings:

- Hide toggle when themeMode is LIGHT or DARK — the theme is forced,
users cannot switch
- Show 3-option toggle (light / system / dark) when themeMode is AUTO or
UNSPECIFIED

# How the Problems Are Solved

- Introduced a `BrandingContext` to pass `themeMode` from `ThemeWrapper`
down to `ThemeSwitch`

# Additional Changes

- removed the CSP from next.config.ts to prevent a precedency issue
where the CSP was actually not applied
2026-03-31 12:25:09 +00:00
604d5cb0a9 fix(login): prevent duplicate email-code verification issue (#11893)
<!--
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

- With Login V2 and EMAIL_VERIFICATION=true, opening the verify page
with send=true can trigger email code generation twice.
- The second code invalidates the first one, so users may receive two
emails where the first code is always invalid.
- This causes failed verification attempts and blocks onboarding for
affected users.

# How the Problems Are Solved

- Removed side-effectful email-code sending from direct server component
execution path.
- Ensured code sending is executed only once in a safe server-side flow,
so React Server Component re-fetches do not generate additional codes.
- Kept verify flow behavior intact while preventing duplicate code
invalidation.

# Additional Changes

- Added/updated logic around the verify flow to make repeated
render/re-fetch paths idempotent for email-code sending.
- Improved reliability of the Login V2 email verification step under App
Router navigation behavior.

# Additional Context

Fixes #11857
- Tested manually with Login V2 and EMAIL_VERIFICATION=true by
completing a new user registration flow to /verify?send=true.
- Verified that only one verification email is sent and the first
received code is valid (no duplicate invalidating code generated).
Related bug report with reproduction details:
[https://github.com/zitadel/zitadel/issues/11857](vscode-file://vscode-app/Applications/Visual%20Studio%20Code.app/Contents/Resources/app/out/vs/code/electron-browser/workbench/workbench.html)

---------

Co-authored-by: Max Peintner <[email protected]>
2026-03-31 12:04:28 +00:00
7c3d26b23b feat: rt sessions OTP email challenge (#11941)
# Which Problems Are Solved

Add OTP Email challenge needed for Create/Set session in the RT model.

# How the Problems Are Solved

Introduce `OTPEmailChallengeCommand` (validate/execute/events) for
session creation checks
Add unit tests

# Additional Changes
Remove unused fields from `session_challenge_otp_sms.go`

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

---------

Co-authored-by: Marco A. <[email protected]>
2026-03-31 11:50:53 +00:00
Max PeintnerandGitHub 9bab764796 fix(login): add OIDC/SAML requestId to resend invite / resend email code (#11927)
# Which Problems Are Solved

This fixes an issue where resending a code for invite flow did not have
the same context it was initially created for

# How the Problems Are Solved

by passing down thre requestId, the context is preserved though a resend
2026-03-31 11:52:06 +02:00
ff4aae7b3f fix(login): improve error classification (#11926)
Closes #11923

# Which Problems Are Solved

Client-side gRPC errors (e.g. NotFound, InvalidArgument,
PermissionDenied) were being surfaced as HTTP 500 Internal Server
Errors, causing false SRE alerts and poor UI feedback.

# How the Problems Are Solved

- New transport interceptor (`error-classification.ts`): Automatically
enriches every ConnectError with httpStatus and isUserError metadata via
a `ClassifiedConnectError` wrapper
- Route handler protection (`route.ts`, `flow-initiation.ts`): Catches
classified errors from `getAuthRequest` / `getSAMLRequest` and returns
correct HTTP status codes instead of 500
- Type safety: Replaced all magic number error.code === 9 checks with
typed Code.FailedPrecondition + instanceof ConnectError across
`oidc.ts`, `saml.ts`, `password.ts`, `zitadel.ts`
- Classification-aware logging (`session.ts`): Client/user errors log at
warn level, server errors at error level
- Observability (`otel.ts`): Spans now include error.is_user_error and
http.status_code attributes for alert filtering

# Additional Changes

Gitignore `next-env.d.ts`: This file is auto-generated by Next.js on
every next dev and next build invocation. The two modes write slightly
different import paths (.next/dev/types/ vs .next/types/), which causes
git diff --exit-code to fail in CI whenever a developer runs next dev
locally before committing. Since Next.js regenerates it automatically,
there's no need to track it

---------

Co-authored-by: Ramon <[email protected]>
Co-authored-by: Copilot <[email protected]>
2026-03-31 11:20:56 +02:00
8e41d288ff fix: use preparation filter for org existence check during setup (#11932)
<!--
Please inform yourself about the contribution guidelines on submitting a
PR here:
https://github.com/zitadel/zitadel/blob/main/CONTRIBUTING.md#submit-a-pull-request-pr.
Take note of how PR/commit titles should be written and replace the
template texts in the sections below. Don't remove any of the sections.
It is important that the commit history clearly shows what is changed
and why.
Important: By submitting a contribution you agree to the terms from our
Licensing Policy as described here:
https://github.com/zitadel/zitadel/blob/main/LICENSING.md#community-contributions.
-->

# Which Problems Are Solved

- Creating an organization via `SetUpOrg` failed when a custom domain
was provided in the same request.
- The org-domain setup path checked org existence only against persisted
state, so it could not see the newly created organization before the
batch was pushed.

# How the Problems Are Solved

- Added a preparation-aware org existence check that resolves the org
through the validation filter instead of the direct persisted-state
lookup.
- Reused the transaction-aware preparation filter so later validations
can see earlier in-flight commands from the same `PrepareCommands`
batch.

fixes #11677

---------

Co-authored-by: abhishek kumar gupta <[email protected]>
Co-authored-by: Wim Van Laer <[email protected]>
2026-03-31 09:58:42 +02:00
21b28b56ac fix: revert feature key for configs back to ConsoleUseV2UserApi (#11928)
# Which Problems Are Solved

https://github.com/zitadel/zitadel/pull/11390 renamed "Console" to
"Management Console". While
https://github.com/zitadel/zitadel/pull/11706 already reverted an
unintended rename of the feature key to enable the management console to
use the V2 API for user creation. It was now also discovered that the
rename of the feature itself also broke existing (default)
configurations.

# How the Problems Are Solved

Added a `mapstructure` tag on the instance feature to handle existing
configs.

# Additional Changes

Removed unused `TokenExchange` from the default configuration.

# Additional Context

- relates to #11390 
- relates to #11706
- requires backport to v4.x

---------

Co-authored-by: Copilot <[email protected]>
Co-authored-by: Marco A. <[email protected]>
2026-03-30 15:59:57 +00:00
Livio SpringandGitHub 0390e324e4 fix: do not send init mails for admins on instance setup (#11744)
# Which Problems Are Solved

Currently when setting up an instance, for example from the customer
portal through system api, an instance is created together with an
administrator. If no admin user is specified the default user from the
runtime configuration is automatically added.
For the new onboarding, we can to create instances without prompting the
user to set up a complete account right on start, but the current
behavior of the API prevents this, resp. the created account would
fallback to the default user or password.
By providing an empty `password` field in the `owner_password` in the
`AddInstanceRequest` or `huiman.password` in the
`CreateInstanceRequest`, it's already possible to create an account
without password. Until now this however ended up in an initial mail to
be sent to the user to finalize their account setup.

# How the Problems Are Solved

We simply set the `allowInitMail` to false in the `AddHumanCommand` for
setting up the admins. This will prevent an email to be sent out
immediately and gives us the possibility to use the invite flow later
on.

# Additional Changes

None

# Additional Context

- required for https://github.com/zitadel/website/issues/1611
- backport to v4.x
2026-03-30 15:31:51 +00:00
b145f1c85a docs: added documentation for jwt idp regarding callback uris (#11925)
# Which Problems Are Solved

The documentation did not reflect the difference between login v1 and v2
for configuring a JWT-idp

# How the Problems Are Solved

Added a warning in the docs which highlight that difference.

# Additional Changes

- Restructured the docs to reflect a more generic approach.
- Fixed indentation inside the `<Callout type="warning">` block so the
content renders as formatted text instead of a code block.
- Fixed inconsistent acronym casing in the use-case section: "jwt" →
"JWT" and "idp" → "IdP" to match the rest of the page and UI terms.

# Additional Context

- Closes: #11589

<!-- START COPILOT CODING AGENT TIPS -->
---

💡 You can make Copilot smarter by setting up custom instructions,
customizing its development environment and configuring Model Context
Protocol (MCP) servers. Learn more [Copilot coding agent
tips](https://gh.io/copilot-coding-agent-tips) in the docs.

---------

Co-authored-by: Copilot <[email protected]>
Co-authored-by: copilot-swe-agent[bot] <[email protected]>
2026-03-30 10:23:42 +02:00
022bf74060 feat(session): Passkey Check API with relation tables (#11858)
# Which Problems Are Solved

As part of #11035 , this PR implements the Passkey check logic for
session validation

# How the Problems Are Solved

  - Refactor webauth FinishLogin to support new domain model
  - Add webauth config to defaults
  - Implement passkey check logic and tests
- Manual transaction management to avoid stalling the DB while
FinishLogin callback is executed
- Update passkey Type condition to allow passing a text operation
(equal, contains, etc..)

# 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: Fabienne Bühler <[email protected]>
Co-authored-by: Gayathri Vijayan <[email protected]>
2026-03-27 12:38:40 +01:00
ec7a6d5526 fix: make recovery code active on add (#11734)
# Which Problems Are Solved

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

# How the Problems Are Solved

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

# Additional Changes

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

# Additional Context

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

---------

Co-authored-by: Marco A. <[email protected]>
Co-authored-by: Cursor <[email protected]>
2026-03-27 09:47:16 +00:00
Gayathri VijayanandGitHub f99142bc4a feat: implement otp sms session challenge (#11919)
# Which Problems Are Solved

This PR adds the OTP SMS Challenge needed for CreateSession API
https://github.com/zitadel/zitadel/issues/11035

# How the Problems Are Solved

- Introduce `OTPSMSChallengeCommand` (validate/execute/events) for
session creation checks
- Introduce `GetOTPCryptoGeneratorConfigWithDefault` to fetch
per-instance secret generator settings
- Add unit tests

# Additional Changes

Refactor tests in `session_check_recovery_code_test.go` to make the
helper functions reusable in `session_challenge_otp_sms_test.go`

# Additional Context
Related to https://github.com/zitadel/zitadel/issues/11035
2026-03-26 11:33:44 +00:00
Livio SpringandGitHub f94e4065c2 chore: update go dependencies (#11883)
Updates all dependencies to latests versions (apart from the ones where
there are already issues to solve their updates).
Some updates required minor changes.
2026-03-24 12:27:43 +01:00
SilvanandGitHub 4bc899d052 docs: Improve README for local development and standardize tab usage (#11865)
## Problem statement

- `<Tabs>` were not rendered in docs
- Missing steps in README for local dev

## How it was solved

- Enhance the README to better describe local development setup and
clean up formatting.
- Standardize the use of tabs across various components for consistency.

## Additional info

To not cause merge conflicts with
https://github.com/zitadel/zitadel/pull/11729 changes in
`/self-hosting/manage/configure/configure.mdx` were skipped
2026-03-23 14:39:07 +00:00
70adaff793 feat: add option to use x.509 certificate system-api-user tokens (#11876)
# Which Problems Are Solved

System API users currently authenticate using raw RSA public keys
configured via Path or KeyData. This approach doesn't integrate well
with Kubernetes tooling.

# How the Problems Are Solved

Allow for the `path`/`keyData` to be an X.509 certificate. 

The `NotBefore` and `NotAfter` fields of the certificate are beeing
respected when validating the JWT.

# Additional Changes

# Additional Context

- Closes #11442

---------

Co-authored-by: Livio Spring <[email protected]>
2026-03-23 13:32:27 +00:00
Livio SpringandGitHub 85ce8c153b chore: ignore pre-release tags for version docs build (#11900)
# Which Problems Are Solved

For switching v4.x releases to a corresponding maintenance branch, we
had to trick semantic release and create a `5.0.0-base` tag on main.
This now breaks the docs build, which tries to fetch all tags and build
a corresponding version.

# How the Problems Are Solved

- Ignore pre-released tags/releases for the moment.

# Additional Changes

None

# Additional Context

- requires backport to v4.x
2026-03-23 14:15:23 +01:00
c6386cb807 feat: rt recovery code check (#11848)
# Which Problems Are Solved

Adding recovery code check step required for the CreateSession RT
implementation.

# How the Problems Are Solved

- Introduce `RecoveryCodeCheckCommand` (validate/execute/events) for
session creation checks
- Add unit tests

# Additional Changes
- refactor password-check code to reuse a shared lockout-policy helper
- add some missing error translations in `internal/static/i18n/en.yaml`

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

---------

Co-authored-by: Silvan <[email protected]>
Co-authored-by: Copilot Autofix powered by AI <[email protected]>
2026-03-23 10:56:40 +01:00
Mridang AgarwallaandGitHub 471ed4a5d7 feat: add DSN/URL connection string support for PostgreSQL and Redis (#11729) 2026-03-20 15:21:15 +00:00
Max PeintnerandGitHub dad4565d5d fix: tar, rollup vulnerabilities (#11889)
# Which Problems Are Solved

Add pnpm overrides to resolve two security vulnerabilities in transitive
dependencies:

node-tar (CVE-2026-23745): Arbitrary file overwrite and symlink
poisoning via insufficient path sanitization — fixed by overriding to
>=7.5.3
Rollup 4 (#477): Arbitrary file write via path traversal — fixed by
overriding to >=4.59.0

# How the Problems Are Solved

applied overrides in package.json
2026-03-20 11:24:36 +01:00
f3ff0d59ec chore: Minor rework SECURITY.md (#11839)
# Which Problems Are Solved

Paragraph reorganization of `SECURITY.md` and some minor changes

# How the Problems Are Solved

  - Move out of scope section under `Scope`
  - Update `Supported Versions` with an up to date link
  - Extend `Out of Scope`

---------

Co-authored-by: Copilot <[email protected]>
2026-03-20 08:23:25 +00:00
Marco A.andGitHub 8d1a099deb fix(domain): Fix session checks failing tests (#11881)
# Which Problems Are Solved

2 tests were failing on the new session checks:

  - Password check (events) fails due to a race condition
- IDP intent check (events) (also password test) fails due to a flaky
time comparison

# How the Problems Are Solved

- Race condition: remove setting the password hasher in the test. It's
already globally set in `domain_test.go`
- Time comparison: use `assert.WithinRange` instead of `assert.InDelta`
and use 2 second range to make sure you don't get resolution issues

# Additional Context

- Closes #11878
2026-03-20 06:57:36 +01:00
Fabienne BühlerandGitHub 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
ca4bba3992 feat: add delete session on relation tables (#11334)
# Which Problems Are Solved

As part of moving the session API to the relational database, this PR
adds the functionality to delete sessions through the session API v2 and
the OIDC end_session endpoint.

# How the Problems Are Solved

- added `SessionDeleteCommand` in domain package
- added possibility to pass the session token verifier to the domain
package
- use feature flag to switch API and OIDC usage from CQRS to relation
table
- added a `permissionCheck` condition to let permissions be checked
directly in the repository / sql
- part of it is still a placeholder until actual permission tables are
done
- added a `session_deleted` table to store (recently) deleted sessions
to handle necessary checks / cases like delete my own session, which
needs to be idempotent

# Additional Changes

Fixed `Matches` function of `existsCondition` (as missing an
implementation)

# Additional Context

- closes #11037

---------

Co-authored-by: Stefan Benz <[email protected]>
2026-03-19 08:35:53 +01:00
Federico CoppedeandGitHub ae32508225 docs: postgresql 18 warning (#11871)
Added a callout to the Kubernetes deployment guide (`Deploy ZITADEL on
Kubernetes`) explicitly stating that PostgreSQL 18 is not currently
supported, ensuring users deploy with a compatible version (14-17).
2026-03-18 12:23:16 -07:00
Federico CoppedeandGitHub 80a20e9680 docs: added link to sidebar title for benchmarks (#11870)
This PR adds a link to the benchmarks title on the sidebar
2026-03-18 15:29:53 +00:00
997aa607c4 feat(telemetry): unify request details (#11509)
# Which Problems Are Solved

In the "new" structured logging, request details were added in different
middlewares, such as request, instance and user IDs. This meant the the
upstream request logging middleware did not have access to metadata that
got added later, resulting in incomplete logs. Furthermore it was not
possible to correlate an API error response to log output.

# How the Problems Are Solved

A mutable request details object is added to the context early on. When
the api authz function run, the instance and user IDs are added to this
object as they become available. Every logline emitted after this
(time-wise) will then all contain these details under the `request` log
group.

<details>

<summary>example output in JSON</summary>

```json
{
  "time": "2026-03-13T19:21:20.890428806Z",
  "level": "INFO",
  "source": {
    "function": "github.com/zitadel/zitadel/internal/api/grpc/server/connect_middleware.LogHandler.func1.1",
    "file": "/workspaces/zitadel/internal/api/grpc/server/connect_middleware/log_interceptor.go",
    "line": 34
  },
  "msg": "request served",
  "request": {
    "id": "d6q67c04vtjmi77cbbpg",
    "instance_host": "localhost:8080",
    "instance_id": "362349751439458307",
    "user_id": "362349751440048131"
  },
  "TraceID": "a9e0fee3522224f3583bbdcda737f4b4",
  "SpanID": "a563056eee36920a",
  "stream": "request",
  "version": "2026-03-13T19:20:59Z",
  "protocol": "connect",
  "service": "zitadel.user.v2.UserService",
  "http_method": "POST",
  "path": "/zitadel.user.v2.UserService/ListUsers",
  "code": "code_0",
  "duration": 12254350
}
```

</details>

Request IDs are now also returned with a response header or metadata.
Depending on the protocol:

- HTTP calls always return the request ID as header, regardless of
status
- gRPC calls always return the request ID as header, even if there was
an error
- connect RPC calls returns the request ID as header on success, trailer
in case of error. This is because header must be set on the response
object, which is nil in case of error. When there is an error, metadata
can be added which are then sent as trailers.

# Additional Changes

- Use the existing call duration middleware for both request ID and
logging for a consistent request start timestamp in all layers.
- Upgrade sloggcp for some fixes (notably TraceID)
- Modify the NoCache middleware so it uses `SetHeaders` instead of
`SendHeaders`. The latter prevented any other handler from setting
headers, including the new request ID middleware.

# Additional Context

Follow up on demo of:
  - https://github.com/zitadel/zitadel/pull/11159
  - https://github.com/zitadel/zitadel/pull/11435
  - backport to v4

---------

Co-authored-by: Copilot <[email protected]>
Co-authored-by: muhlemmer <[email protected]>
Co-authored-by: Copilot Autofix powered by AI <[email protected]>
Co-authored-by: Marco A. <[email protected]>
2026-03-18 14:07:33 +01:00
f138082b64 feat: add administrator repository (#11803)
Introduces the `administrators` relational table and repository layer
for the v3 backend, unifying instance, organization, project, and
project-grant membership into a single scoped model.

Closes #10220

## Changes

- **Domain**: `Administrator` struct, `AdministratorScope` enum,
`AdministratorRepository` interface with typed CRUD, column, condition,
and change helpers. Generated enumer and GoMock.
- **Migration** (`016`): `zitadel.administrators` table with a generated
`id`, scope-alignment check constraint, cascading foreign keys, and a
child `administrator_roles` table.
- **Repository**: CTE-based role mutations (`AddRole`, `RemoveRole`,
`SetRoles`) for atomicity. Roles aggregated via `ARRAY_AGG`.
- **Projection**: Event reducers for
`member.added/changed/removed/cascade_removed` across all four admin
scopes.
- **Fixes**: `Rows.Close()` error wrapping; `TextArray` nil-safe scan +
full `pgtype` array interface; `authorization` and `projectGrant` scan
helpers fixed for `ARRAY_AGG` under `database/sql`; removed unused `ctx`
parameter from `callReduce`.

---------

Co-authored-by: Marco Ardizzone <[email protected]>
2026-03-18 10:24:09 +01:00
SilvanandGitHub 6d90a120a6 feat: allow transactional table setup step to recreate the whole schema (#11833)
## Problem description

- Setup currently creates/updates relational tables, but there is no
built-in way to fully reset the relational schema during iterative
development.
- Re-running setup after schema/projection changes can leave stale
relational objects and projection state behind, which makes local/dev
validation harder.
- There is no explicit, configurable switch in setup steps for
destructive schema recreation behavior.

## How the Problems Are Solved

- Adds a new setup step configuration section for relational tables with
a `ShouldRecreateSchema` flag (default `false`).
- Wires the new config flag into the transactional tables setup step.
- Extends the transactional tables execution logic to optionally:
  - Drop the `zitadel` schema with `CASCADE`
- Clean related projection state entries for relational tables in
`projections.current_states`
  - Recreate tables through the existing setup flow afterward
- Wraps the destructive operations in a transaction and keeps
error/rollback handling plus logging for visibility.

## Additional Changes

- Adds an explicit warning in step configuration that schema recreation
is intended for development and not production use.
- Keeps behavior fully backward-compatible by default
(`ShouldRecreateSchema: false`), so existing setups are unchanged unless
the flag is enabled.

## Additional Context

- Follow-up for relational setup/dev workflow improvements.
- PR: #11833

## How to use it

### Env `export ZITADEL_RELATIONALTABLES_SHOULDRECREATESCHEMA=true`

### Config

Add the following to your custom setup steps config:

```yaml
RelationalTables:
  ShouldRecreateSchema: true
```
2026-03-18 03:53:57 +00:00
a864434b4b feat(login): update to nextjs 16, improve caching, change default colors (#11629)
# Which Problems Are Solved

Updated the project to use the latest versions of Next.js and React, and
implemented a SWR caching strategy for key settings API calls to improve
performance. Adjusted configuration to ensure compatibility with Next.js
16.

# How the Problems Are Solved

- Updated next to 16.1.6, react & react-dom to 19.2.4, and next-intl to
4.8.3.
- Implemented `API_CACHE_ENABLED` and `API_CACHE_CONFIG` (replacing
deprecated unstable_cacheLife) for:
  - getBrandingSettings
  - getSecuritySettings
  - getPasswordComplexitySettings
  - getLoginSettings ...
- Updated default theme colors from blue to a more neutral black and
white

# Additional changes

- Updated login docker image to node 24

---------

Co-authored-by: Ramon <[email protected]>
2026-03-17 16:01:50 +01:00
fca2589fc3 fix(login): http 2 memory leak's (#11830)
# Which Problems Are Solved
All http 2 based connect-es clients caused memory leaks in our testing
using the login v2 application as the host.

# How the Problems Are Solved
Switch to connect-rpc based http 1.1 transport for the login v2

# Additional Changes
Improved the otel interceptor implementation and tests.

# Additional Context
- connect-rpc is only enabled for v2 API's so we have to make sure to
not use any v1 apis in the login but this should be the case anyways.
- Discussion #10562

---------

Co-authored-by: Max Peintner <[email protected]>
2026-03-17 14:29:21 +00:00
c1be72765c chore(login): remove integration tests (#11608)
# Which Problems Are Solved

Removes the Cypress integration tests and associated configuration from
the apps/login project to streamline the build process.

# How the Problems Are Solved

- Removed cypress directory, integration directory, and
cypress.config.ts from apps/login.
- Updated project.json to remove test-integration targets and
dependencies.
- Updated package.json to remove the cypress dev dependency and clean
script reference.
- Updated tsconfig.json to remove the now-redundant integration
exclusion.
- Ensured acceptance tests are preserved and correctly excluded from
build inputs.

---------

Co-authored-by: Florian Forster <[email protected]>
Co-authored-by: Copilot <[email protected]>
Co-authored-by: conblem <[email protected]>
2026-03-17 14:16:39 +00:00
c3a6bdb0bb Merge commit from fork
* fix: add `Scopes` to `Request` interface so that scopes can be validated on all requests

* feat: assert org from scope exists when authorizing requests

* fix: check all scopes

* comments

* check org on callback creation

* fix tests

* clarifications

* fix scope marshaling

* fix: enfore organization for authrequest in initiation

* fix: filter sessions on the accounts page by organization scope

* add integration tests

---------

Co-authored-by: Livio Spring <[email protected]>
Co-authored-by: Max Peintner <[email protected]>
2026-03-17 12:54:27 +01:00
Marco A.andGitHub aa4432dc99 feat(session): IDP Intent Check API with relation tables (#11820)
# 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
2026-03-17 10:50:47 +00:00