Commit Graph
27 Commits
Author SHA1 Message Date
Max PeintnerandGitHub a331e5b7ba fix(login): redirect unknown users to external IdP after domain discovery when enumeration protection is active (#12581)
# Which Problems Are Solved

A `login_hint` that resolves an organization via domain discovery but
matches no
existing user is no longer automatically redirected to the
organization's external
IdP when enumeration protection (`ignoreUnknownUsernames`) is active on
the request
context.

#12369 combined the unknown-user IdP redirect into a single condition,
but gated it
with `&& !ignoreUnknownUsernames`:

```ts
if ((!effectiveLoginSettings?.allowLocalAuthentication || discoveredOrganization) && !ignoreUnknownUsernames) {
```

Since the flag is resolved from the pre-discovery context (the instance
default
settings — during domain discovery there is no organization context
yet), enabling
enumeration protection instance-wide disables the redirect even for
IdP-only
organizations (`allowLocalAuthentication: false`). The flow falls
through to
`preventUserEnumeration()` and strands the user on a decoy Password
screen for an
account that does not exist; the Back button re-enters the auto-submit
loop and
dead-ends identically. This breaks silent-SSO first logins where the
external IdP
is supposed to create the account on first authentication (Login V2).

The guard is also counterproductive on its own terms: existing users of
the same
org still auto-redirect to the IdP, so the divergent treatment acts as
an
enumeration oracle — redirect means the user exists, password screen
means it
doesn't. And it protects nothing in practice, since the IdP remains
reachable
manually via the account switcher → login-name screen → IdP button.

# How the Problems Are Solved

Split the condition by what known users of the resolved organization
actually
experience, so unknown usernames always mimic the known-user flow:

```ts
if (
  !effectiveLoginSettings?.allowLocalAuthentication ||
  (discoveredOrganization && !ignoreUnknownUsernames)
) {
```

- **Local authentication disabled (IdP-only org):** redirect unknown
usernames to
the single allowed IdP regardless of `ignoreUnknownUsernames`. Known
users are
auto-redirected there, so the identical redirect is precisely what keeps
unknown
usernames indistinguishable — and it restores first-login account
creation via
  the external IdP.
- **Local authentication enabled:** known (password) users see the
password screen,
so the decoy password screen remains the indistinguishable behavior and
enumeration protection keeps gating the discovery-based IdP redirect, as
  introduced by #12369.

Adds regression tests for both cases: domain discovery into an IdP-only
org with
`ignoreUnknownUsernames: true` expects the IdP redirect; discovery into
a
local-auth org expects the decoy `/password` redirect with no IdP flow
started.
2026-08-12 13:41:58 +02:00
464d1cb655 fix(login): resolve unknownContext error on password page caused by inconsistent ignoreUnknownUsernames handling (#12512)
# Which Problems Are Solved

The `/password` page (and related password pages) can show the
`unknownContext` error even though the user was resolved correctly and
login completes fine. Two causes:

1. `sendLoginname` used two different `ignoreUnknownUsernames` sources:
session creation was gated on the **user's org** login settings, while
the redirect's `loginName` masking and enumeration guards were gated on
a **caller-supplied flag** reflecting the request context (instance or
org scope). Whenever the two diverge — e.g. `ignoreUnknownUsernames`
enabled on the instance but not on the user's org, or the reverse — the
redirect carries a `loginName` that doesn't match the session cookie (or
no session is created at all), so the `/password` page can't load the
session and renders `unknownContext`, while password submission still
succeeds via its user-search fallback. This affects every caller of
`sendLoginname` — the manual `/loginname` form as well as the
server-side `login_hint` resolution; it was most reproducible with
`login_hint`, since that path resolves context settings at the instance
level, maximizing the chance of divergence with an org-level policy.

2. The password pages tried to re-derive "was enumeration protection
applied?" from login settings to suppress the error — but they resolve
settings from a different context than `sendLoginname` (falling back to
the default organization instead of the instance), so any org-level
custom policy made the suppression misfire. More fundamentally, the
alert was keyed on a failed session lookup, which is not an error state:
under enumeration protection no session exists by design, and the forms
recover without one (`sendPassword` falls back to user search;
`/password/set` works via code + userId).

# How the Problems Are Solved

`sendLoginname` no longer accepts `ignoreUnknownUsernames` from the
caller. It derives a single constant server-side from the
request-context login settings it already fetches and uses it for every
decision in the flow: session creation, `preventUserEnumeration`, the
multiple-users branch, the INITIAL-user check, the organization reset,
the auth-method guards, and the IdP redirect after domain discovery.
Redirect params use `session?.factors?.user?.loginName ??
command.loginName`: when a session exists, its loginName goes in the URL
so the next page always finds the session cookie; when protection
applies, no session (and no session cookie) is created and the raw input
is echoed, keeping known and unknown users fully indistinguishable —
including the previously observable `Set-Cookie` difference.
`UsernameForm` and `resolveLoginHint` stop forwarding the flag, which
also removes the redundant `getLoginSettings` call in
`resolveLoginHint`.

The password pages no longer consult login settings or the session
lookup for the `unknownContext` error and instead warn only when
required input is actually missing (matching the existing pattern on the
passkey/mfa/u2f pages): `/password` and `/password/change` when no
`loginName` searchParam is present, `/password/set` when neither
`loginName` nor `userId` is present. A missing session alone no longer
triggers the error.

Verified against a live instance in all four settings combinations
(uniform on/off, both divergence directions) including a
known-vs-unknown `login_hint` comparison producing byte-identical
responses under protection; full unit suite passes.

---------

Co-authored-by: Livio Spring <[email protected]>
2026-08-04 12:49:28 +00:00
3e94047da7 fix(login): redirect to external IdP after domain discovery regardless of registration policy (#12369)
Closes #12021
Closes #12023

# Which Problems Are Solved

When a user entered an email on the login page and domain discovery
resolved the correct organization, the login flow failed to redirect to
the configured external IdP. Instead it returned a "user not found"
error or showed the registration page.

This happened because the "user not found" decision tree in
`sendLoginname` only attempted an IdP redirect when
`allowLocalAuthentication` was disabled. If local auth was enabled but
`allowRegister` was `false`, the IdP check was skipped entirely.

# How the Problems Are Solved

Combined the IdP redirect logic into a single block that triggers when
either local authentication is disabled **or** domain discovery resolved
an organization. The registration policy (`allowRegister`) now only
affects local account creation and no longer gates external IdP
authentication.

---------

Co-authored-by: Copilot Autofix powered by AI <[email protected]>
Co-authored-by: Livio Spring <[email protected]>
2026-07-17 13:09:48 +00:00
Max PeintnerandGitHub 3a18cef281 fix: prevent double triggering of verification emails (#11995)
# Which Problems Are Solved

This fixes a critical bug where initial verification emails (or invite
codes) were occasionally sent twice, invalidating the first code and
confusing users.

Previously, the initial verification email was triggered via a
`send=true` URL parameter executing inside a frontend useEffect exactly
when the `/verify` page mounted. This was fragile and prone to race
conditions caused by component remounts or partial hydration.

# How the Problems Are Solved

- Removed `send=true` from URL state and ripped out the doSend effect in
`VerifyForm.tsx`.
- Shifted execution strictly to the Next.js server. The email is now
automatically dispatched via await `initialSendVerification(...)` during
the POST requests (acting over `sendLoginname`, `register`, `password`,
`passkeys`, and `idp`).
- The login flow is now idempotent and robust against unintended
frontend re-renders.
- Refactored `checkEmailVerification()` to be async and updated the
associated unit-test coverage (all tests passing).
2026-06-29 11:42:45 +03: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
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
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
Mridang AgarwallaandGitHub 7cdee1703f chore: standardised the eslint config structure accross the project (#11814) 2026-03-12 11:02:52 +01:00
RamonandGitHub 057fb8dff2 fix(login): prettier setup (#11798)
# Which Problems Are Solved
Invalid formatting in the login codebase due to invalid prettier
configuration

# How the Problems Are Solved
Fxed .prettierignore wildcards for login source files

# Additional Changes
Removed .prettierrc file because there is already a prettier.config.mjs
file

# Additional Context
2026-03-10 13:30:20 +00:00
Max PeintnerandGitHub b33c811a01 fix(login): remove loginSettings.allowRegister check for IDPs (#11731)
Closes #11138

# Which Problems Are Solved

Previously, the application strictly checked the allowRegister
setting—which typically applies to local account creation—before
considering if a user without an account should be redirected to an IDP,
or whether they could access the register page. This blocked users from
registering via identity providers when local registration was disabled
but IDPs were configured.

# How the Problems Are Solved

- Removed the allowRegister dependency when deciding to redirect an
unknown user to an IDP. The logic now only checks
!allowLocalAuthentication, correctly opening up the IDP registration
flow even when local auth/registration is not allowed.
- Modified the block condition so the register page is only restricted
if allowRegister is false and there are no configured identityProviders
available.
2026-03-05 08:16:49 +00:00
Mridang AgarwallaandGitHub 3f3413a230 feat(login): added support for otel push-based logs, metrics, and traces (#11429) 2026-03-04 15:58:56 +05:30
Max PeintnerandGitHub 3b74b86dc4 fix(login): check for primary auth methods on user discovery (#11689)
# Which Problems Are Solved

- Currently, if a user has only secondary authentication methods (like
TOTP) configured but no primary authentication method (Password,
Passkey, or IDP), the login flow fails to handle them correctly,
resulting in an unhelpful "user not found" error when they attempt to
log in.
- These users are not correctly prompted to set up a primary
authentication factor, leaving them in a state where they cannot
successfully authenticate.

# How the Problems Are Solved

- Updated `sendLoginname` to evaluate if a user has an active primary
authentication method (`AuthenticationMethodType.PASSWORD`, `PASSKEY`,
or `IDP`. If they lack a primary method, the flow now correctly
redirects them into the verification/invite process rather than falling
through the method checks and returning a generic error.
- Updated `sendVerification` to replace the empty `authMethodTypes`
array check with a specific check for primary authentication methods.
Now, after completing email/invite verification, users who do not have a
primary authentication method are explicitly redirected to
`/authenticator/set` to set one up.
2026-02-25 14:12:23 +01:00
b23346f6ca chore: consistent naming for organization domain (#11356)
# Which Problems Are Solved

As part of the consistent naming effort, this PR focuses on
"Organization domain".

# How the Problems Are Solved

- All terms referring referring to Organization Domains where changed to
be Organization Domain

# Additional Changes

None

# Additional Context

- closes [#11283](https://github.com/zitadel/zitadel/issues/11283)

---------

Co-authored-by: Copilot <[email protected]>
2026-02-18 14:46:21 +00:00
11d48edd84 fix(login): update login logic to correctly handle email and phone re… (#11618)
## Problem

Enabling `Disable Phone Login` (or `Disable Email Login`) in the login
policy caused some users to receive "User not found in the system" even
when logging in with a valid, non-phone identifier. Users whose
preferred login name looked like an email address (e.g. `[email protected]`
in an org-scoped context) were rejected incorrectly. Toggling the
setting back off immediately restored login for those users.

Fixes #11518

## Root Cause

In `loginname.ts` and `password.ts`, the post-lookup guard that enforces
the disable-phone/email restriction used `||` instead of `&&`:

```ts
// BEFORE (buggy): rejects if preferredLoginName doesn't match OR email doesn't match
// → any user whose preferredLoginName ≠ raw email is rejected
if (user.preferredLoginName !== concatLoginname || humanUser?.email?.email !== command.loginName) {
  return preventUserEnumeration(...);
}

// AFTER (correct): rejects only if preferredLoginName doesn't match AND email doesn't match
// → user passes through if they matched by either their preferred login name or their email
if (user.preferredLoginName !== concatLoginname && humanUser?.email?.email !== command.loginName) {
  return preventUserEnumeration(...);
}
```

The intent is to allow the user through if they matched by their
preferred login name **or** by the still-permitted identifier. By De
Morgan's law, the rejection condition must be `¬A ∧ ¬B`, not `¬A ∨ ¬B`.

## Changes

- **`loginname.ts`**: fixed 2 `||` → `&&` in the `disableLoginWithEmail`
and `disableLoginWithPhone` guards
- **`password.ts`**: fixed 4 `||` → `&&` across the same guards in both
`resetPassword` and `sendPassword`
- **`loginname.test.ts`**: added two regression tests:
- `disableLoginWithPhone=true`, user logs in with their email-format
preferred login name → must succeed (was broken)
- `disableLoginWithPhone=true`, user logs in with their actual phone
number → must be blocked (feature still works)

## Testing

All 654 unit tests pass.

Co-authored-by: Max Peintner <[email protected]>
2026-02-18 09:30:22 +01:00
9492c12c09 fix(login): refactor SAML Post Flow to bypass cookie limits, fix SAML SP post (#11170)
Closes #10816
Closes #10759

# Which Problems Are Solved

This PR refactors the SAML Post binding flow to address issues with
payloads exceeding browser cookie size limits (typically ~4KB).
Previously, the SAML form data was serialized into a cookie, and the
user was redirected to an intermediate /saml-post page to render the
form. This approach failed for large SAML assertions.

# How the Problems Are Solved

The new implementation bypasses cookies entirely for the payload
transfer. Server actions now return the form data directly to the
client, which immediately renders and submits the form.

- Direct Data Transfer: Updated `startIdentityProviderFlow` to return an
object { url, fields } instead of a redirect URL when the next step is
formData.
- Server Actions: Updated redirectToIdp, sendLoginname, and
completeAuthFlow to propagate this samlData object to the client.
- Client-Side Auto-Submission: Added a new AutoSubmitForm component that
renders a hidden form with the provided fields and automatically submits
it to the IdP on mount.

---------

Co-authored-by: conblem <[email protected]>
2026-02-09 13:46:30 +01:00
Max PeintnerandGitHub 38dbd4cf3e fix(login, console): replace allowUsernamePassword with allowLocalAuthentication in login, change translation in console (#11413)
# Which Problems Are Solved

This PR deprecates and replaces the use of `allowUsernamePassword` with
`allowLocalAuthentication`.
It additionally disables the username on organizations that disallow
local authentication. In such a case, only IDPs are shown.

# How the Problems Are Solved

- replace `allowUsernamePassword` by `allowLocalAuthentication`
- disable username form if !allowLocalAuthentication
- translate property in console UI
2026-02-04 12:54:37 +00:00
26f8238499 fix(login): correctly redirect to /password when ignoreUnknownUsername is set (#11130)
Closes #11006 

# Which Problems Are Solved

This PR addresses an issue where the ignoreUnknownUsernames setting was
not being respected in certain scenarios during the login flow.
Specifically:

- When a user was found but rejected due to login settings (e.g.,
disableLoginWithEmail), the system would return a "User not found" error
instead of redirecting to the password page as dictated by
ignoreUnknownUsernames.
- When a user was not found, and the flow fell through the registration
checks (e.g., IDP redirect failed), it would also return "User not
found" without checking ignoreUnknownUsernames.

# How the Problems Are Solved

- Introduced a helper function `handleUserNotFound` in 
`apps/login/src/lib/server/loginname.ts` to centralize the logic for
checking ignoreUnknownUsernames and redirecting to the password page.
- Updated the user validation logic to call handleUserNotFound when a
user is found but rejected by policy.
- Updated the registration fallback logic to call handleUserNotFound
instead of directly returning an error.
- Added new test cases in `apps/login/src/lib/server/loginname.test.ts`
to verify the fix and ensure no regressions.

# Additional Changes

- Fixed inconsistency in translation files

---------

Co-authored-by: Livio Spring <[email protected]>
2026-01-14 08:24:48 +00:00
df75be96ff Merge commit from fork
* fix: Improve host header handling and deployment mode detection

* ZITADEL_CLOUD env

* refactor service config

* service config

* cleanup

* cleanup

* util for original and public host

* instanceHost, publicHost

* cleanup constructUrl

* cleanup middleware

* add x-zitadel-forward-host as fallback for current cloud setup

* fix build

* fix: lint

* fix: update test mocks

* fix: provide basepath to unit tests

* host handling

* unit tests

* imports

* fix: getPublicHost instead of getInstanceHost

* unit tests

* update nextjs, implement jwt verify for logout_token

* pass logout information in jwt to login v2

* handle hosts in jwks url

* point idp callbacks to the api and not the login UI

* logout_hint out of logout token, typecheck

* rm unused imports

* fix oidc integration test

---------

Co-authored-by: Livio Spring <[email protected]>
2025-12-08 10:01:49 +01:00
75791361f3 fix(login): Organization Discovery for Login Without Org Context (#10996)
# Which Problems Are Solved

When users accessed the login page without an organization context and
entered a login name with a domain suffix (e.g., [[email protected]], the
system would return "user not found" instead of performing organization
discovery.

# How the Problems Are Solved

Added organization discovery logic that triggers after a global user
search returns no results. When no organization context is provided:

- Extracts the domain suffix from the loginName (e.g., @company.com)
- Queries for organizations with that domain as their primary domain
- If exactly one organization is found with allowDomainDiscovery
enabled, uses it as the discovered organization
- Redirects users to the appropriate flow (IDP, registration, or
password) with the discovered organization context

---------

Co-authored-by: Ramon <[email protected]>
2025-11-12 13:14:09 +01:00
Max PeintnerandGitHub c913904df3 fix(login): idp success url (#10997)
# Which Problems Are Solved

An IDP Intent could not be completed due to a missing change of
successUrl property in a recent PR.

# How the Problems Are Solved

The /success page has been replaced by /process to finish the IDP flow
in all occurences.
2025-10-29 10:54:28 +01:00
Max PeintnerandGitHub d10be4c09a fix(login): send invite codes only for users with unverified email (#10943)
# Which Problems Are Solved

When a user with no authentication methods attempted to log in, the
system always set `invite=true` in the verification flow, regardless of
whether their email was already verified. This could cause errors when
trying to send invite codes to already initialized users.

# How the Problems Are Solved

Added conditional logic to determine whether to send an invite code
based on the user's email verification status:

This prevents errors when attempting to send invite codes to users who
have already verified their email and been initialized, while still
properly handling new users who need invitation flows.
2025-10-21 13:44:31 +00:00
ff869482b1 fix(login): fallback for idp login (#10876)
Closes #10671

# Which Problems Are Solved

Users with password authentication disabled in their organization were
seeing "Username Password not allowed!" error instead of being
redirected to their organization's configured Identity Provider. This
affected domain discovery and multi-tenancy use cases in Login V2.

# How the Problems Are Solved

- Updated `redirectUserToIDP` to accept optional `userId` and
`organization` parameters
- Added fallback logic to check organization-level IDPs via
`getActiveIdentityProviders`
- Updated all call sites to pass appropriate organization context
- Added test coverage for the fallback behavior

# Additional Changes

- Consolidated duplicate logic by removing
`redirectUserToSingleIDPIfAvailable` function, which is now handled by
the unified `redirectUserToIDP` function
- improved error handling on verification page

---------

Co-authored-by: Ramon <[email protected]>
2025-10-21 11:04:33 +02:00
64e14de091 feat(login): translations (#10849)
# Which Problems Are Solved

Replace this example text with a concise list of problems that this PR
solves.
For example:
- password complexity requirements have hardcoded English text
- password, loginname, register and verify components have hardcoded
Engilsh error messages/alerts

# How the Problems Are Solved

Replace this example text with a concise list of changes that this PR
introduces.
For example:
- adds i18n for password complexity requirements
- adds i18n for password, loginname, register and verify components
error messages/alerts

# Additional Changes

- small change in code/styles for icons in PasswordComplexity to make
sure that icons keep size

# Additional Context

N.A

---------

Co-authored-by: Adam Kida <[email protected]>
2025-10-09 11:11:03 +02:00
Max PeintnerandGitHub 695db96745 fix(login): Redirect to IDP flow when password auth is disabled (#10839)
Closes #10671

# Which Problems Are Solved

Users with only password authentication method were immediately shown an
error "Username Password not allowed" when
`loginSettings.allowUsernamePassword` was set to false. However, the IDP
flow could potentially allow the user to register a new account or link
an existing account, providing a better user experience than a dead-end
error.

# How the Problems Are Solved

- Modified single password method case to attempt IDP redirect before
showing error
- This allows users to potentially register or link accounts through the
IDP flow instead of hitting an immediate error
- Only show error as last resort when no IDP alternative is available
2025-10-07 05:47:58 +00:00
Max PeintnerandGitHub 09d09ab337 fix(login): host utility to provide correct host behind proxies (#10770)
<!--
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 deploying the login application behind proxies or using Vercel
rewrites (e.g., `zitadel.com/login` → `login-zitadel-qa.vercel.app`),
the application was using the internal rewritten host instead of the
original user-facing host. This caused several issues:

1. **Broken Password Reset Emails**: Email links contained internal
hosts like `login-zitadel-qa.vercel.app` instead of `zitadel.com`
2. **Inconsistent User Experience**: Users would see different domains
in various parts of the flow
3. **Security Concerns**: Internal infrastructure details were exposed
to end users
4. **Scattered Logic**: Host detection logic was duplicated across
multiple files with inconsistent error handling

# How the Problems Are Solved

Created comprehensive host detection utilities in `/lib/server/host.ts`
and `/lib/client/host.ts`:

**Server-side utilities:**
- `getOriginalHost()` - Returns the original user-facing host
- `getOriginalHostWithProtocol()` - Returns host with proper protocol
(http/https)
2025-09-23 16:21:01 +00:00
Max PeintnerandGitHub a48cacfb02 fix(login): idp redirect (#10482)
This PR fixes an issue where a user was not redirected to an IDP
correctly if the user has entered the loginname and has an IDP as single
auth method
2025-08-14 13:42:33 +00:00
Elio BischofandGitHub b10455b51f chore: reproducible pipeline with dev containers (#10305)
# Which Problems Are Solved

- The previous monorepo in monorepo structure for the login app and its
related packages was fragmented, complicated and buggy.
- The process for building and testing the login container was
inconsistent between local development and CI.
- Lack of clear documentation as well as easy and reliable ways for
non-frontend developers to reproduce and fix failing PR checks locally.

# How the Problems Are Solved

- Consolidated the login app and its related npm packages by moving the
main package to `apps/login/apps/login` and merging
`apps/login/packages/integration` and `apps/login/packages/acceptance`
into the main `apps/login` package.
- Migrated from Docker Compose-based test setups to dev container-based
setups, adding support for multiple dev container configurations:
  - `.devcontainer/base`
  - `.devcontainer/turbo-lint-unit`
  - `.devcontainer/turbo-lint-unit-debug`
  - `.devcontainer/login-integration`
  - `.devcontainer/login-integration-debug`
- Added npm scripts to run the new dev container setups, enabling exact
reproduction of GitHub PR checks locally, and updated the pipeline to
use these containers.
- Cleaned up Dockerfiles and docker-bake.hcl files to only build the
production image for the login app.
- Cleaned up compose files to focus on dev environments in dev
containers.
- Updated `CONTRIBUTING.md` with guidance on running and debugging PR
checks locally using the new dev container approach.
- Introduced separate Dockerfiles for the login app to distinguish
between using published client packages and building clients from local
protos.
- Ensured the login container is always built in the pipeline for use in
integration and acceptance tests.
- Updated Makefile and GitHub Actions workflows to use
`--frozen-lockfile` for installing pnpm packages, ensuring reproducible
installs.
- Disabled GitHub release creation by the changeset action.
- Refactored the `/build` directory structure for clarity and
maintainability.
- Added a `clean` command to `docks/package.json`.
- Experimentally added `knip` to the `zitadel-client` package for
improved linting of dependencies and exports.

# Additional Changes

- Fixed Makefile commands for consistency and reliability.
- Improved the structure and clarity of the `/build` directory to
support seamless integration of the login build.
- Enhanced documentation and developer experience for running and
debugging CI checks locally.

# Additional Context

- See updated `CONTRIBUTING.md` for new local development and debugging
instructions.
- These changes are a prerequisite for further improvements to the CI
pipeline and local development workflow.
- Closes #10276
2025-07-24 14:22:32 +02:00