<!--
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
Outdated depdencies
# How the Problems Are Solved
This PR mostly just updates our NPM depdencies to the newest feature
releases.
The UUID package was update to version 14, the changelog only includes
changes to the supported node version.
# Additional Changes
Replace tsx for some scripts in the docs.
---------
Co-authored-by: Livio Spring <[email protected]>
Co-authored-by: Max Peintner <[email protected]>
# Which Problems Are Solved
- Login V2 signup does not resolve the `{{.Lang}}` placeholder in ToS,
Privacy Policy, and help links.
- Clicking those links on the registration page can open URL-encoded
placeholders like `%7B%7B.Lang%7D%7D` instead of the active
language-specific page.
# How the Problems Are Solved
- Adds a small login utility to resolve `{{.Lang}}` placeholders against
the active Login V2 locale.
- Updates the signup legal acceptance component to use the resolved
links before rendering them.
- Applies the same resolution to the optional help link shown alongside
the legal acceptance text.
# Additional Changes
- Adds unit tests for the link placeholder resolver.
- Adds a component test covering localized ToS, Privacy Policy, and help
links on the signup page.
# Additional Context
- Closes#11907
---------
Co-authored-by: Copilot <[email protected]>
Co-authored-by: Max Peintner <[email protected]>
Co-authored-by: Max Peintner <[email protected]>
# Which Problems Are Solved
- Logo and heading overlap on login pages due to a -mb-4 negative margin
on the logo container
- The /login route returns a 500 when `listSessions` fails (e.g. stale
session cookies), because loadSessions has no error handling.
- The proxy logs `"fetch() returned undefined"` because
`fetchIframeOrigins` returns undefined, which lru-cache's forceFetch
treats as a fetch failure.
# How the Problems Are Solved
- Remove `-mb-4` from the logo container in DynamicTheme.
- Wrap `loadSessions` in a try/catch — failures fall through as empty
sessions instead of crashing.
- Return `null` instead of `undefined` from `fetchIframeOrigins` so
lru-cache caches it normally.
---------
Co-authored-by: Livio Spring <[email protected]>
Co-authored-by: conblem <[email protected]>
# Which Problems Are Solved
The console provided conflicting warnings when creating a pkce based
project.
# How the Problems Are Solved
<img width="1026" height="432" alt="grafik"
src="https://github.com/user-attachments/assets/d6609d2d-1438-42bd-9bc4-2e896c3e47d9"
/>
Removed the `keep your client secret at a safe place...` warning when a
auth-method without a client secret is used.
Changed the dialog title to `Client Details` instead of `Client Secret`
# Additional Changes
- Improves type safety for data passed to the
`AppSecretDialogComponent`.
- Updates the `AppSecretDialogComponent` to use modern Angular features,
improving readability and maintainability.
# Additional Context
- Closes#11834
---------
Co-authored-by: Max Peintner <[email protected]>
# Which Problems Are Solved
- Users needed broader IAM read permissions to access the Actions V1
page in the console.
# How the Problems Are Solved
- Updates the console route configuration for `/actions` to require
`org.action.read`.
# Additional Context
- Closes#12001
## Summary
- Switch the docs catch-all route to full static generation and prebuild
both latest and versioned docs paths.
- Prebuild OG images for all docs pages, make sitemap and LLM export
static, and remove nondeterministic sitemap timestamps.
- Reduce build-time overhead by memoizing docs sidebar trees and
skipping processed markdown generation for versioned docs.
## Testing
- `pnpm nx run @zitadel/docs:build`
- `pnpm nx run @zitadel/docs:lint`
- `pnpm nx run @zitadel/docs:check-types`
- Verified the prerender manifest contains 8,816 prerendered routes,
3,293 versioned docs routes, 4,406 OG routes, and zero revalidating docs
routes.
This PR updates the "Private Key JWT Auth for Service Accounts"
documentation to explicitly clarify the relationship between the exp
(expiration) and iat (issued at) claims.
Previously, the documentation didn't make it clear what happens if a
developer sets an exp claim far into the future. This update clarifies
that while the exp value is strictly enforced, the iat claim takes
precedence if the exp is set to more than 1 hour in the future (i.e.,
ZITADEL will reject the JWT once the iat is older than 1 hour,
regardless of the exp time).
**Changes included:**
Updated the description of the exp claim in the JWT payload section to
highlight the 1-hour iat limit enforcement.
# Which Problems Are Solved
The Vercel `docs` project generated ~64M ISR writes over 30 days (99.5%
of ISR writes across all projects, ~\$258/month).
Root causes in the Next.js 16 docs app:
- `apps/docs/app/[[...slug]]/page.tsx` had `dynamicParams = true` +
`revalidate = 3600`. Bot traffic hitting unknown URLs (`/docs/wp-admin`,
`/docs/.env`, fuzzed paths) got rendered via \`notFound()\`, and the 404
response was cached as an ISR entry — 1 write per unique bad URL. Known
pages were also rewritten hourly for no reason since content only
changes on deploy.
- `apps/docs/app/og/docs/[...slug]/route.tsx` had `revalidate = false` +
empty `generateStaticParams()` + implicit `dynamicParams = true`. Every
unique OG URL (including bot probes) was cached forever — writes
accumulated permanently.
# How the Problems Are Solved
Switch the docs routes to pure SSG (content is static and only changes
on deploy, so ISR provides no value):
- `app/[[...slug]]/page.tsx`: `dynamicParams = false`, `revalidate =
false`, `dynamic = 'force-static'`. Unknown URLs now return a static 404
at the CDN — no function invocation, no ISR write. All 390 pages from
`source.generateParams()` are still pre-rendered.
- `app/og/docs/[...slug]/route.tsx`: `generateStaticParams()` now
returns all 390 pages via the existing `getPageImage(page).segments`
helper, so every OG image is pre-built as a static asset. `dynamicParams
= false` + `dynamic = 'force-static'` locks it down.
- `app/llms-full.txt/route.ts`: added `dynamic = 'force-static'` as a
safety net (already `revalidate = false`, single URL).
The tradeoff is longer CI builds (~40s–2min for 390 OG image
generations, paid on every preview deploy) in exchange for eliminating
~\$258/month in ISR writes plus associated function invocations and CPU
time.
# Additional Changes
None.
# Additional Context
- No changes to `next.config.mjs`, `vercel.json`, or redirects.
- Existing `apps/docs/redirects.json` (3,261 entries) covers legacy URLs
so `dynamicParams = false` won't 404 moved pages linked from elsewhere.
- Versioned routes: `content/versions.json` and `v*/` folders don't
exist yet. When versioning is activated, `generateStaticParams()` in
both files must also include `versionSource.generateParams()` —
otherwise versioned URLs will 404 under `dynamicParams = false`.
## Test plan
- [ ] CI build succeeds (expect modest build-time increase for OG
pre-generation)
- [ ] Inspect `apps/docs/.next/prerender-manifest.json` — all 390 doc
routes + 390 OG routes listed with `initialRevalidateSeconds: false`
- [ ] Local smoke: `/docs` → 200, `/docs/wp-admin` → 404 (static, no
function), `/docs/og/docs/guides/start/image.png` → PNG,
`/docs/og/docs/bogus/image.png` → 404
- [ ] Post-deploy: Vercel **ISR Writes** metric drops to near-zero
within 24h
- [ ] Post-deploy: Vercel **Function Invocations** for `/og/docs/*` drop
to zero
- [ ] Verify no legitimate docs pages 404 (cross-check logs against
`apps/docs/app/sitemap.ts`)
---------
Co-authored-by: Claude Opus 4.7 (1M context) <[email protected]>
# Which Problems Are Solved
1. SSL/TLS handshake failures on Cloud Run (middleware self-loopback)
PR #11903 changed the middleware (proxy.ts) to fetch security settings
via fetch(origin + "/security") on every request, including non-proxy
routes like /login. On Cloud Run, this self-loopback goes through the
Google Front End (GFE) load balancer, causing intermittent SSL
routines::record layer failure errors that were tenant-consistent.
2. The ClassifiedConnectError introduced in #11926 set this.name =
"ClassifiedConnectError", which broke ConnectError's custom
Symbol.hasInstance duck-typing check (v.name === "ConnectError"). This
caused ConnectError.from() inside the connectRPC transport's abort
handler to re-wrap classified errors as new ConnectError instances with
Code.Unknown — losing the original gRPC error code and all
classification metadata.
# How the Problems Are Solved
Middleware: eliminate self-loopback fetch:
- Replaced the fetch(origin + "/security") self-loopback with a direct
fetch to ZITADEL_API_URL using the Connect protocol (POST + JSON),
bypassing the load balancer entirely
- Security settings are cached in-memory with a 1-hour TTL per instance
host
- Extracted the fetching/caching logic into
src/lib/server/security-settings.ts
Removed the now-unused /security API route (src/app/security/route.ts)
- CSP headers with iframe origins are now applied to all routes without
any loopback
Error classification interceptor: fixed
- Keep this.name = "ConnectError" in ClassifiedConnectError so the
duck-typing Symbol.hasInstance check passes
- The branded Symbol.for check via isClassifiedError() still correctly
distinguishes the subclass
- Remove redundant Object.setPrototypeOf call (the super constructor
already handles it via new.target)
- Replace remaining instanceof ConnectError checks with
isClassifiedError() in setUserPassword and checkSessionAndSetPassword
<!--
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 Project Grant in the Zitadel console, the UI becomes
extremely sluggish/unusable. The issue appears tied to the organization
search dropdown attempting to load a very large dataset.
# How the Problems Are Solved
The refactored `SearchOrgAutocompleteComponent` uses server side
filtering and ondemand loading using infinite scrolling. This makes sure
on a subset of organizations is ever loaded on the client.
# Additional Changes
- Added tailwindcss for easier styling
- Removed build warnings
- Removed some of the SCSS syntax warnings
# Additional Context
- Closes#11121
---------
Co-authored-by: Max Peintner <[email protected]>
# Which Problems Are Solved
- Clearing OIDC redirect URI lists in the console does not persist
correctly resulting in no changes error.
# How the Problems Are Solved
- Normalizes empty OIDC URI list updates to [""] before sending the save
request.
- Uses the application v2 update call for the affected OIDC config save
path.
# References
- Closes#12053
# Which Problems Are Solved
The CreateInviteCode endpoint wrongly stated that a new code can only be
issued if the old had expired or was invalidated due to too many
attempts, which is not true.
# How the Problems Are Solved
Removed the note from the proto / API documentation.
# Additional Changes
None
# Additional Context
- noticed by a customer
- requires backport to v4.x
---------
Co-authored-by: Copilot <[email protected]>
Co-authored-by: Matías Racedo <[email protected]>
# Which Problems Are Solved
This PR introduces the possibility of using the relational DB when
calling the ListSession gRPC endpoint.
# How the Problems Are Solved
- Implement the Querier interface for ListSession:
- Create a `domain` model for the Session object to be able to map the
gRPC session into it.
- Match the permission filters on ES side to be sure the same sessions
are returned
- Implement converter methods to go from `gRPC` to `domain` models (both
ways)
- Fix the session sql relational migration: rework the trigger to update
the `expiration` field to perform the update only when the input
`lifetime` has a non-zero value.
- Link the Querier implementation with the gRPC endpoint
- Run the same integration tests against the relational DB, making sure
the outcome is the same. ⚠️ Due to missing permission checks, some
divergence is expected. Hence, specific code to circumvent the
differences has been put in place
# Additional Context
- Closes#11039
# Which Problems Are Solved
Users exporting larger orgsanizations were facing grpc message size
limits of 4 MiB, while trying to export 6.3 MiB of data. Other export
methods like S3 aren't implemented.
# How the Problems Are Solved
Set MaxSendMsgSize to 10 MiB (allow some overhead). This is not a
long-term solution and we should investigate better ways of export.
# Additional Changes
- none
# Additional Context
- Support ticket
# Which Problems Are Solved
This PR adds implementation to add a Zitadel IdP at the
organization-level.
# How the Problems Are Solved
- Added handling/converters for the `AddZitadelProvider` endpoint in
`ManagementService` in the server layer
- Registered a new `org.idp.zitadel.added` event for org-level Zitadel
providers
- Added `AddOrgZitadelProvider` command to validate the request and push
`org.idp.zitadel.added` event to the eventstore
- Added the `org.idp.zitadel.added` event to the projection reducer
- Added unit and integration tests
# Additional Changes
added more tests for the ZitadelProvider in AdminService
# Additional Context
- Closes https://github.com/zitadel/zitadel/issues/11823
- Follow-up for PRs https://github.com/zitadel/zitadel/pull/12018,
https://github.com/zitadel/zitadel/pull/12020,
https://github.com/zitadel/zitadel/pull/12055
# Which Problems Are Solved
Persisting instance-level Zitadel provider in the projections.
# How the Problems Are Solved
- Defining a new projection table `projections.idp_templates6_zitadel`
and columns for the Zitadel provider
- Adding a reducer `reduceZitadelIDPAdded` to process instance-level
`ZitadelIDPAddedEvent`
- Unit tests
# Additional Changes
N/A
# Additional Context
- Related to https://github.com/zitadel/zitadel/issues/11823
- Follow-up for PRs https://github.com/zitadel/zitadel/pull/12018,
https://github.com/zitadel/zitadel/pull/12020
This update introduces a new table for managing administrator role
permissions, along with the necessary repository and projection logic to
handle adding and removing permissions. It also includes tests to ensure
the correct functionality of the permission management system.
closes https://github.com/zitadel/zitadel/issues/10219
---------
Co-authored-by: Marco Ardizzone <[email protected]>
# Which Problems Are Solved
This PR contains the command-layer implementation to add an instance IDP
of the type `ZitadelProvider`
# How the Problems Are Solved
- Implementing `AddZitadelProvider` in AdminService
- Adding the command-layer to create a `ZitadelProvider` and push
`ZitadelIDPAddedEvent`
# Additional Changes
N/A
# Additional Context
- Related to https://github.com/zitadel/zitadel/issues/11823
- Follow-up for PR https://github.com/zitadel/zitadel/pull/12018
---------
Co-authored-by: Copilot <[email protected]>
# Which Problems Are Solved
Opaque tokens now use authenticated encryption.
# How the Problems Are Solved
- Upgrade zitadel/oidc to v3.47
- Copy crypto implementation for refresh and session tokens (internal to
zitadel)
- Added config that allows validating old tokens for gradual roll-out
# Additional Changes
- Set NX cache for `integration-test-build` to `false`, working on a
seperate fix.
# Additional Context
- closes#11315
---------
Co-authored-by: copilot-swe-agent[bot] <[email protected]>
Co-authored-by: muhlemmer <[email protected]>
# Which Problems Are Solved
The in-memory SWR promiseCache in zitadel.ts used keys like
getBrandingSettings-${org} that had no instance identifier. In
multi-tenant mode, where a single Next.js process serves multiple
instances, an instance A's cached settings without org context
(branding, languages, settings, etc.) could be served to Instance B
request without org context. The cache now additionally is bound to 100
entries by default (configurable via maxSize in `API_CACHE_CONFIG`).
When capacity is exceeded, expired entries are swept first
It additionally replaces the hand-rolled PromiseCache (Map-based, FIFO
eviction) with lru-cache, leveraging its built-in fetchMethod for
stale-while-revalidate, request deduplication, and true LRU eviction.
# How the Problems Are Solved
Added an instanceCacheKey() helpe that prefixes every cache key with
serviceConfig.instanceHost in addition to the org context if available.
---------
Co-authored-by: Ramon <[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
While updating our dependencies the protoc-gen-js library got out of
sync with the google-protobuf npm dependency. This caused problems with
certain grpc code relying on the old `reader.readPackedEnum`.
# How the Problems Are Solved
Updated protoc-gen-js to v4.0.2.
# Additional Changes
Increased the angular build size budget.
# Additional Context
---------
Co-authored-by: Copilot <[email protected]>
# Which Problems Are Solved
As part of https://github.com/zitadel/zitadel/issues/11917 we want to
introduce error slugs so (API) clients can rely on stable,
machine-readable errors and act accordingly.
# How the Problems Are Solved
- Added a `NewSlug` helper function in the domain package.
- Added `ErrorDetails` to the `ZitadelError`
- Added an `zitadel.error.v2.ErrorDetail` proto message
- Updated the connectRPC error interceptor to map new slug based errors
to the new `ErrorDetail`
- Defined some common slugs and error functions like internal errors
- Defined (session) specific slugs used in the `DeleteSession` and
`CheckUser` functions and replaced old implementations
- Updated integration tests to check specific errors if the relation
database feature is enabled
- Updated doc and guideline to reflect the latest changes and decisions
- Updated DeleteSession endpoint API to list possible slugs
# Additional Changes
None
# Additional Context
- closes#11957
---------
Co-authored-by: Wim Van Laer <[email protected]>
# Which Problems Are Solved
- Zitadel-api failed to reach PostgreSQL with connection refused,
Zitadel v4.11 does not implement a DSN field.
# How the Problems Are Solved
- Updated ZITADEL_VERSION variable in env.example to v4.13.0
Co-authored-by: Livio Spring <[email protected]>
Fixes#11730
The v1 gRPC middleware can return native gRPC status errors such as
`codes.Unauthenticated` when the auth header is missing.
Those errors were being passed through the generic gRPC error converter,
which only handled ZITADEL errors and downgraded raw gRPC statuses to
`codes.Unknown`.
Through grpc-gateway that caused `/auth/v1/users/me` to return HTTP 500
instead of HTTP 401.
So this change preserves native gRPC status errors in
`ZITADELToGRPCError`, keeps `ExtractZITADELError` aligned with those
transport codes for activity reporting, and adds regression coverage for
the converter, middleware, and gateway HTTP behavior.
---------
Co-authored-by: Gayathri Vijayan <[email protected]>
# Which Problems Are Solved
#11975 introduces new APIs to `SettingsService`, however,
`settingsconnect.SettingsServiceHandler` wasn't updated to satisfy the
interface containing the new APIs.
# How the Problems Are Solved
By adding a dummy implementation of new RPC methods to the
SettingsService Server.
# Additional Changes
n/a
# Additional Context
n/a
# Which Problems Are Solved
A new model is needed for links in settings.
# How the Problems Are Solved
Created the new contracts for `LinkSettings`
# Additional Changes
# Additional Context
Replace this example with links to related issues, discussions, discord
threads, or other sources with more context.
Use the Closing #issue syntax for issues that are resolved with this PR.
- Closes#11959
- Discussion #xxx
- Follow-up for PR #xxx
- https://discord.com/channels/xxx/xxx
---------
Co-authored-by: Copilot <[email protected]>
# Which Problems Are Solved
In the Zitadel API, provide an IdP template which allows connecting to
other Zitadel instances.
# How the Problems Are Solved
This PR adds API definitions to add Zitadel provider at instance and
organization levels.
- Add `AddZitadelProvider` to ManagementService and AdminService
- Add `InstanceRolesInfo` message to help determine instance admin role
assignments
# Additional Changes
N/A
# Additional Context
- Related to https://github.com/zitadel/zitadel/issues/11823
---------
Co-authored-by: Copilot <[email protected]>
# Which Problems Are Solved
The console didn't specify any callback url's for the JWT idp provider.
# How the Problems Are Solved
Added callback url's to the JWT idp provider screen in the management
console.
# Additional Changes
# Additional Context
- Closes#11589
# Which Problems Are Solved
Currently ZITADEL only allows the use of RSA public keys for machine
user authentication (jwt-bearer grant), including for system API users.
Attempting to use ECDSA (e.g. P-256) or ED25519 keys results in
`Errors.Internal` because `BytesToPublicKey` performs an
`ifc.(*rsa.PublicKey)` type assertion that returns `(nil, nil)` for
non-RSA keys, which then causes a nil key panic in go-jose during JWT
verification.
This is the same fix as #8433 (by @livio-a), rebased onto current
`main`.
# How the Problems Are Solved
- `BytesToPublicKey` now returns `crypto.PublicKey` (the standard
library interface) instead of `*rsa.PublicKey`
- A type switch validates the parsed key is one of `*rsa.PublicKey`,
`*ecdsa.PublicKey`, or `ed25519.PublicKey`
- A new `ErrNoPublicKey` sentinel error is returned for unsupported key
types instead of silently returning nil
- Callers in `system_token.go` and `query/key.go` are updated to use the
generic `crypto.PublicKey` interface
# Additional Changes
None
# Additional Context
Duplicate of #8433 which has been open since August 2024. We hit this
bug while implementing OIDC bootstrap for an SGX enclave that generates
ECDSA P-256 keys at runtime -- the `AddKey` API accepts the ECDSA SPKI
PEM fine, but the subsequent `jwt-bearer` token exchange fails with
`Errors.Internal` due to the nil key.
---------
Co-authored-by: Copilot <[email protected]>
Co-authored-by: Wim Van Laer <[email protected]>
# Which Problems Are Solved
The settings tab is hidden when there's only 1 organization. This was
very confusing when I created an IdP using terraform and then could not
find it. I eventually found the `gs` shortcut which brought me to the
org settings. This was last touched here #10912
# How the Problems Are Solved
Always show the settings tab, even if there's just 1 org.
Co-authored-by: Ramon <[email protected]>
# 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).
# Which Problems Are Solved
`@zitadel/api:generate-go` failed due to duplicate generated files.
https://github.com/zitadel/zitadel/pull/11820 removed the old generated
file and added a generate command to the `internal/crypto/crypto.go`
file. However, there was already a `internal/crypto/generate.go` with a
different output file name (the old file).
# How the Problems Are Solved
Removed the `internal/crypto/generate.go` file and moved the second
generate into `internal/crypto/code.go`.
# Additional Changes
Noticed that mockgen is an old version and updated it. Also then checked
all other tools and updated them.
# Additional Context
- relates to #11820
- noted internally
# Which Problems Are Solved
A test was failing because of timezone flakiness
# How the Problems Are Solved
The actual problem was an `updatedAt` field was not filled in because of
the `createdAt` was missing on an event. This caused a zero value to be
filled in into the `updatedAt` field. Postgres then stored this value
with seconds in it's timezone info, which go could not store.
By adding filling in the `createdAt` field, this does not occur.
# Which Problems Are Solved
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
<!--
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
## 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]>
<!--
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
# 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]>
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.
# 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.
# 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]>