* feat(login): add shared enrollment authorization guard
Introduce assertSessionAuthorizedForEnrollment, a single gate that decides
whether a session may enroll a new authenticator: it requires a verified
primary factor (password, passkey or IDP) on a non-expired session, or, for
onboarding, a user with no auth methods plus a prior user-verification check.
This mirrors the gate previously inlined only in registerPasskeyLink, which
is refactored to reuse the shared helper. It is the foundation for gating the
remaining credential-enrollment entry points (GHSA-45f2-5q3r-xgg6).
Co-Authored-By: Claude Opus 4.8 <[email protected]>
* fix(login): require authentication before WebAuthn/U2F enrollment
addU2F and verifyU2F registered a credential for any session that resolved to
a user id, including a bare identify-only session created by merely submitting
a login name. An unauthenticated attacker who knew a victim's login name could
therefore attach an attacker-controlled authenticator to the victim's account
and then complete a login as the victim.
Both actions now run assertSessionAuthorizedForEnrollment before registering or
verifying, so an unauthenticated session is rejected and no credential is
persisted.
GHSA-45f2-5q3r-xgg6
Co-Authored-By: Claude Opus 4.8 <[email protected]>
* fix(login): require authentication before TOTP/OTP enrollment
verifyTOTP and the otp/<method>/set page activated a TOTP/OTP factor for any
session with a user id, and the u2f/set page rendered the registration form
without an authorization check. An identify-only session could thus enroll a
second factor on a victim's account.
Gate all of them with assertSessionAuthorizedForEnrollment. The setup pages now
render the unknown-context/error state instead of enrolling when the session is
not authorized. Also guard the method value in the OTP set page, since the added
guard branch removes the control-flow narrowing the previous throw provided.
GHSA-45f2-5q3r-xgg6
Co-Authored-By: Claude Opus 4.8 <[email protected]>
* fix(login): require authentication before legacy (V1) passwordless enrollment
The V1 passwordless registration handlers began and verified passwordless setup
for any auth request that carried a user id, without checking that a first
factor had been verified. An unauthenticated attacker could submit a victim's
login name and then POST directly to the passwordless prompt/init endpoints to
plant an attacker-controlled passkey, then log in as the victim.
Add passwordlessSetupAllowed / CheckPasswordlessSetupAllowed, which permit
enrollment only for a legitimate onboarding user (PasswordlessInitRequired) or
an auth request whose first factor is already verified, and call it before
BeginPasswordlessSetup and VerifyPasswordlessSetup. The verify path is also
bound to authReq.UserID instead of the attacker-controllable form field, so a
credential cannot be redirected onto a different account. The init-code
(mail/onboarding) path is unchanged.
GHSA-45f2-5q3r-xgg6
Co-Authored-By: Claude Opus 4.8 <[email protected]>
* fix(login): remove never-active legacy (V1) authReq passwordless setup path
Supersedes the runtime gate added in the previous commit. Maintainer review
(Livio, the original author) and investigation confirmed the auth-request based
passwordless *setup* path in the legacy login was a never-active leftover:
- The passwordless prompt page (passwordless_prompt.html) has no submit button
and no script; it only tells the user to complete setup via the emailed link
(the PasswordlessButtonText/NextButtonText/SkipButtonText i18n keys are unused).
- Legitimate onboarding for a PasswordlessInitRequired user goes through the
emailed init-code flow (authReq == nil, BeginPasswordlessInitCodeSetup /
VerifyPasswordlessInitCodeSetup), which is untouched.
- The authReq branch (handlePasswordlessPrompt -> BeginPasswordlessSetup /
VerifyPasswordlessSetup) was reachable only by a crafted direct POST — the
GHSA-45f2-5q3r-xgg6 attack.
Rather than gate the dead path, remove it entirely, eliminating the attack
surface:
- delete handlePasswordlessPrompt and the POST /login/passwordless/prompt route
(keep renderPasswordlessPrompt: the informational "use your emailed link" page
for PasswordlessRegistrationPromptStep),
- make renderPasswordlessRegistration / checkPasswordlessRegistration use only
the init-code path,
- drop the now-unused AuthRequestRepo.BeginPasswordlessSetup /
VerifyPasswordlessSetup (and the interface decls) and the passwordlessPromptUrl
template helper; the underlying HumanAddPasswordlessSetup /
HumanHumanPasswordlessSetup commands remain (used by the auth-API self-service
and the v2 passkey APIs).
A crafted POST to /login/passwordless/init carrying an authRequestID but no valid
code now falls through to the init-code path and fails.
GHSA-45f2-5q3r-xgg6
Co-Authored-By: Claude Opus 4.8 <[email protected]>
* check for userverified true as well, cleanup return message
---------
Co-authored-by: Claude Opus 4.8 <[email protected]>
Co-authored-by: Max Peintner <[email protected]>
## Which Problems Are Solved
- Add comprehensive Arabic language support to ZITADEL
## How the Problems Are Solved
- Added full Arabic translation files for the login UI, console, and
notification (yaml and json).
- Ensured all keys match the latest English reference files to avoid
missing or inconsistent entries.
- Updated the localization loader to include `ar` as a supported
language.
## Additional Changes
## Additional Context
Closes#11146
---------
Co-authored-by: Marco A. <[email protected]>
## Summary
- Add comprehensive Ukrainian language support to ZITADEL
- Complete translation of all user-facing interfaces
- Integration with existing language configuration system
## Changes Made
- ✅ **Console translations**: Complete Ukrainian translation for admin
console (2,861 translated strings)
- ✅ **Login interface**: Ukrainian translations for authentication flows
(535 strings)
- ✅ **Email notifications**: Ukrainian translations for system emails
(68 strings)
- ✅ **Common texts**: Ukrainian translations for success/error messages
(1,417 strings)
- ✅ **Language configuration**: Added Ukrainian to supported languages
and Angular locale registration
- ✅ **UI integration**: Added Ukrainian option to language selection
forms
## Translation Quality
- Professional translations using established Ukrainian IT terminology
- Formal language appropriate for business software
- Consistent terminology across all components (Users→Користувачі,
Organization→Організація, etc.)
- Preserved all technical placeholders, HTML tags, and formatting
## Contributing Guidelines Compliance
- ✅ Followed semantic commit message format
- ✅ Added Ukrainian to all required configuration files
- ✅ Maintained consistent file structure with existing languages
- ✅ Used formal Ukrainian appropriate for business software
The Ukrainian translation is now ready for review by the ZITADEL team! 🚀
---------
Co-authored-by: Marco A. <[email protected]>
# Which Problems Are Solved
As reported to support, the back button on the various 2FA pages in
login V1 opened the default redirect URI, which likely started a new
auth request (e.g. from Console).
# How the Problems Are Solved
Change the back buttons to navigate to the login screen again, where a
user can change the username.
Additionally, the back button has been added to the U2F verification
screen.
# Additional Changes
None
# Additional Context
- from support
- backport to v4
- Turkish language support is added.
- Updated other language files to add Turkish selection.
# Which Problems Are Solved
- Zitadel was not supporting Turkish language. Now supporting.
# How the Problems Are Solved
- Turkish language files are added and updated other language files in
below paths to add Turkish support;
- /console/src/assets/i18n/
- /internal/api/ui/login/static/i18n
- /internal/notification/static/i18n
- /internal/static/i18n
# Additional Changes
- Made changes below files for codes/docs changes;
- /console/src/app/utils/language.ts
- /console/src/app/app.module.ts
- /docs/docs/guides/manage/customize/texts.md
- /internal/api/ui/login/static/templates/external_not_found_option.html
- /internal/query/v2-default.json
- /login/apps/login/src/lib/i18n.ts
---------
Co-authored-by: Marco A. <[email protected]>
related to issue [#9379](https://github.com/zitadel/zitadel/issues/9379)
# Which Problems Are Solved
Copy to clipboard button was not compatible with Webkit/ Firefox
browsers.
# How the Problems Are Solved
The previous function used addEventListener without a callback function
as a second argument. I simply added the callback function and left
existing code intact to fix the bug.
# Additional Changes
Added `type=button` to prevent submitting the form when clicking the
button.
# Additional Context
none
---------
Co-authored-by: Livio Spring <[email protected]>
# Which Problems Are Solved
When registering passkeys or u2f methods as second factor, some users
pressed the "Enter" key, rather than clicking the submit button. This
method has bypassed the execution of the device registration and
encoding scripts, resulting in the form being submitted without the
necessary encoded values.
# How the Problems Are Solved
This PR ensures that device registration is always executed and the
required information are submitted in the form regardless of pressing
"Enter" or clicking the button.
# Additional Changes
None
# Additional Context
- closes#6592
- closes#2910
# Which Problems Are Solved
- Lack of support for the Romanian language in the application.
# How the Problems Are Solved
- Added translations for the Romanian language
---------
Co-authored-by: Silvan <[email protected]>
# Which Problems Are Solved
The current login will always prefer external authentication (through an
IdP) over local authentication. So as soon as either the user had
connected to an IdP or even when the login policy was just set up to
have an IdP allowed, users would be redirected to that IdP for
(re)authentication.
This could lead to problems, where the IdP was not available or any
other error occurred in the process (such as secret expired for
EntraID).
Even when local authentication (passkeys or password) was allowed for
the corresponding user, they would always be redirected to the IdP
again, preventing any authentication. If admins were affected, they
might not even be able to update the client secret of the IdP.
# How the Problems Are Solved
Errors during the external IdP flow are handled in an
`externalAuthFailed` function, which will check if the organisation
allows local authentication and if the user has set up such.
If either password or passkeys is set up, the corresponding login page
will be presented to the user. As already with local auth passkeys is
preferred over password authentication.
The user is informed that the external login failed and fail back to
local auth as an error on the corresponding page in a focused mode. Any
interaction or after 5 second the focus mode is disabled.
# Additional Changes
None.
# Additional Context
closes#6466
Hello everyone,
To support Korean-speaking users who may experience challenges in using
this excellent tool due to language barriers, I have added Korean
language support with the help of ChatGPT.
I hope that this contribution allows ZITADEL to be more useful and
accessible to Korean-speaking users.
Thank you.
---
안녕하세요 여러분, 언어의 어려움으로 이 훌륭한 도구를 활용하는데 곤란함을 겪는 한국어 사용자들을 위하여 ChatGPT의 도움을
받아 한국어 지원을 추가하였습니다.
이 기여를 통해 ZITADEL이 한국어 사용자들에게 유용하게 활용되었으면 좋겠습니다.
감사합니다.
Co-authored-by: Max Peintner <[email protected]>
- Fully translated all UI elements, documentation, and error messages
- Added Hungarian as a new supported language option
- Updated language selection menus and related configuration files
- Ensured consistency across all translated content
# Which Problems Are Solved
- ZITADEL was not accessible for Hungarian-speaking users due to lack of
language support
- Hungarian users had to rely on English or other languages to use the
platform
- Potential user base was limited due to language barrier
# How the Problems Are Solved
- Translated all user interface elements, including console and login
interfaces
- Translated all documentation files to Hungarian
- Added Hungarian translations for all error messages and notifications
- Implemented Hungarian as a selectable language option in the system
# Additional Changes
- Updated language selection menus to include Hungarian
- Modified configuration files to support Hungarian language
- Ensured consistent terminology and style across all translated content
- Added Hungarian language option to relevant dropdown menus and
settings
# Additional Context
- Relates to the ongoing internationalization efforts of ZITADEL
- Enhances accessibility for Hungarian-speaking developers and users
- Expands ZITADEL's potential user base in Hungary and
Hungarian-speaking regions
---------
Co-authored-by: Max Peintner <[email protected]>
Co-authored-by: Tim Möhlmann <[email protected]>
Co-authored-by: Stefan Benz <[email protected]>
# Which Problems Are Solved
As an administrator I want to be able to invite users to my application
with the API V2, some user data I will already prefil, the user should
add the authentication method themself (password, passkey, sso).
# How the Problems Are Solved
- A user can now be created with a email explicitly set to false.
- If a user has no verified email and no authentication method, an
`InviteCode` can be created through the User V2 API.
- the code can be returned or sent through email
- additionally `URLTemplate` and an `ApplicatioName` can provided for
the email
- The code can be resent and verified through the User V2 API
- The V1 login allows users to verify and resend the code and set a
password (analog user initialization)
- The message text for the user invitation can be customized
# Additional Changes
- `verifyUserPasskeyCode` directly uses `crypto.VerifyCode` (instead of
`verifyEncryptedCode`)
- `verifyEncryptedCode` is removed (unnecessarily queried for the code
generator)
# Additional Context
- closes#8310
- TODO: login V2 will have to implement invite flow:
https://github.com/zitadel/typescript/issues/166
# Which Problems Are Solved
There were UX issue with the autolinking prompt page and users were not
able to link their account or would not understand what to do. Since the
trust to the IdP is already bound by the configuration, the user can
directly be linked without any user input.
# How the Problems Are Solved
- remove the prompt page and directly link the user if possible
- remove corresponding customization texts from the API and Console
# Additional Changes
None
# Additional Context
- relates to https://github.com/zitadel/zitadel/issues/7977
- discussed with customers
- created as a `fix` to be able to backport
---------
Co-authored-by: Max Peintner <[email protected]>
# Which Problems Are Solved
As of now, **automatic creation** and **automatic linking options** were
only considered if the corresponding **allowed option** (account
creation / linking allowed) was enabled.
With this PR, this is no longer needed and allows administrators to
address cases, where only an **automatic creation** is allowed, but
users themselves should not be allowed to **manually** create new
accounts using an identity provider or edit the information during the
process.
Also, allowing users to only link to the proposed existing account is
now possible with an enabled **automatic linking option**, while
disabling **account linking allowed**.
# How the Problems Are Solved
- Check for **automatic** options without the corresponding **allowed**
option.
- added technical advisory to notify about the possible behavior change
# Additional Changes
- display the error message on the IdP linking step in the login UI (in
case there is one)
- display an error in case no option is possible
- exchanged deprecated `eventstoreExpect` with `expectEventstore` in
touched test files
# Additional Context
closes https://github.com/zitadel/zitadel/issues/7393
---------
Co-authored-by: Stefan Benz <[email protected]>
# Which Problems Are Solved
The initial load of the login UI with dark mode preference
(prefers-color-scheme: dark) first rendered the logo configured for
light mode. Also switching from dark to light or vice versa would result
in the same behavior.
This was due to a mixed logic of server (based on cookie) and client
(prefers-color-scheme and cookie) deciding which mode to render.
# How the Problems Are Solved
- Since the main logic of which mode to use (`prefers-color-scheme`) can
only be achieve client side, both logos will be served in the HTML and
either will be rendered based on CSS.
# Additional Changes
None
# Additional Context
- closes#2085
# Which Problems Are Solved
#8291 added backwards compatibilty for users who were created through
the user V2 API and want to sign in to the login UI.
There were however to issues, where users might be prompted to set a
password even if they already had one set or they would not be able to
submit the email verification code.
# How the Problems Are Solved
- Replaced `SearchUserAuthMethods `with `ListUserAuthMethodTypes` to
check for set up auth methods.
- Fixed page / javascript to disable submit button.
# Additional Changes
- Changed `ListActiveUserAuthMethodTypes ` to `ListUserAuthMethodTypes`
and a `activeOnly` boolean parameter
# Additional Context
- relates to #8291
- noticed internally on QA
# Which Problems Are Solved
User created through the User V2 API without any authentication method
and possibly unverified email address was not able to login through the
current hosted login UI.
An unverified email address would result in a mail verification and not
an initialization mail like it would with the management API. Also the
login UI would then require the user to enter the init code, which the
user never received.
# How the Problems Are Solved
- When verifying the email through the login UI, it will check for
existing auth methods (password, IdP, passkeys). In case there are none,
the user will be prompted to set a password.
- When a user was created through the V2 API with a verified email and
no auth method, the user will be prompted to set a password in the login
UI.
- Since setting a password requires a corresponding code, the code will
be generated and sent when login in.
# Additional Changes
- Changed `RequestSetPassword` to get the codeGenerator from the
eventstore instead of getting it from query.
# Additional Context
- closes https://github.com/zitadel/zitadel/issues/6600
- closes https://github.com/zitadel/zitadel/issues/8235
---------
Co-authored-by: Stefan Benz <[email protected]>
# Which Problems Are Solved
Some organizations / customers have the requirement, that there users
regularly need to change their password.
ZITADEL already had the possibility to manage a `password age policy` (
thought the API) with the maximum amount of days a password should be
valid, resp. days after with the user should be warned of the upcoming
expiration.
The policy could not be managed though the Console UI and was not
checked in the Login UI.
# How the Problems Are Solved
- The policy can be managed in the Console UI's settings sections on an
instance and organization level.
- During an authentication in the Login UI, if a policy is set with an
expiry (>0) and the user's last password change exceeds the amount of
days set, the user will be prompted to change their password.
- The prompt message of the Login UI can be customized in the Custom
Login Texts though the Console and API on the instance and each
organization.
- The information when the user last changed their password is returned
in the Auth, Management and User V2 API.
- The policy can be retrieved in the settings service as `password
expiry settings`.
# Additional Changes
None.
# Additional Context
- closes#8081
---------
Co-authored-by: Tim Möhlmann <[email protected]>
# Which Problems Are Solved
- Swedish speakers cannot use their beautiful native language ;-)
# How the Problems Are Solved
- Contributes Swedish language for Login, Console, common texts and
Emails
# Additional Changes
- none
# Additional Context
- The PR currently provides all translation files according to
https://github.com/zitadel/zitadel/blob/main/CONTRIBUTING.md#contribute-internationalization.
---------
Co-authored-by: Tim Möhlmann <[email protected]>
Co-authored-by: Livio Spring <[email protected]>
# Which Problems Are Solved
There is confusing ambiguity in the error messages for setting too long
passwords in different places.
# How the Problems Are Solved
A check for maximum password length is added so it's clear that
passwords can't exceed a maximum length of 70 or 72 bytes.
Password validation now provides a live updating check mark or cross
mark to indicate if the maximum length requirement is met.
# Additional Changes
Clarified requirement descriptions on the registration page with
complete sentences.
# Additional Context
Closes#6301
---------
Co-authored-by: Elio Bischof <[email protected]>
* init auto linking
* prompt handling
* working
* translations
* console
* fixes
* unify
* custom texts
* fix tests
* linting
* fix check of existing user
* fix bg translation
* set unspecified as default in the form
* feat: enable only specific themes in label policy
* feat: enable only specific themes in label policy
* feat: enable only specific themes in label policy
* feat: enable only specific themes in label policy
* add management in console
* pass enabledTheme
* render login ui based on enabled theme
* add in branding / settings service and name consistently
* update console to latest proto state
* fix console linting
* fix linting
* cleanup
* add translations
---------
Co-authored-by: Livio Spring <[email protected]>
Co-authored-by: Tim Möhlmann <[email protected]>
* feat: replace inactive remove active from select account
* fix: apply same behavior to console user select
---------
Co-authored-by: Livio Spring <[email protected]>
* fix: restrict AllowRegistration check to local registration
* add comment
* add additional tests
* hide registration fields if no registration allowed
* fix: always allow linking and creation of external idps on users in userV2 and admin import
* chore: exclude console dist and node_module folders from cache
* chore: include node_module folders into cache again
* linting
* add macedonian language to currently supported languages
* mk yaml login static with en values
* mk json assets with en values
* mk yaml notification static with en values
* add macedonian notification yaml
* mk yaml static with en values
* mk translations for login
* mk translations for internal
* macedonian translations
* - fix lint issues
* fix: 404 for robots.txt and meta robots tags
* fix: add unit tests for robots txt and tag
* fix: add meta tag robots none for login pages
* fix: weird format issue in header.go
* fix: add x-robots-tag=none to grpcwebserver
* fix linting
---------
Co-authored-by: Silvan <[email protected]>
Co-authored-by: Livio Spring <[email protected]>