Summary
On self-hosted v0.75.0 with --single-account-mode-domain=<domain> and the
embedded IdP (Dex + Google upstream connector), an uninvited-but-legitimate
Google user logging in for the first time got a brand-new account (owner of an
empty tenant) instead of joining the existing account — while single-account
mode was armed. Reading the management source, this appears to be a general
trap, not a config error:
updateUserAuthWithSingleMode() (management/server/account.go ~1572-1599)
overrides the JWT Domain/DomainCategory with the domain stored on the
existing account (via GetAnyAccountID) — not with the configured
--single-account-mode-domain value.
- If that stored domain is empty (common: any account that existed before the
first IdP login — e.g. a /api/setup bootstrap account — causes subsequent
IdP-created accounts to inherit domain=""), isDomainValid("") fails and
the flow falls through to GetOrCreateAccountByUser() → a NEW account is
created for every unknown user, silently defeating single-account mode.
- The empty-domain account can never self-heal on later logins:
domainIsUpToDate() returns early whenever the stored domain differs from
the claims domain.
- Once ≥2 accounts exist, the next management restart logs
single account mode disabled, accounts number N and SAM is off entirely.
Reproduction (self-hosted 0.75.0)
- Deploy with
--single-account-mode-domain=example.com, embedded IdP +
Google connector, create the first account such that its domain column
ends up empty (first login while a setup account existed is enough).
- Have a second, uninvited Google user (same Workspace domain) log in.
- Observed: user gets a fresh empty account with owner role; management boot
log subsequently reports single account mode disabled, accounts number 2.
Expected: user joins the single existing account (pending approval when
user_approval_required is set).
Impact
The new user sees a fully-featured empty "admin" dashboard (confusing; looks
like a breach or a broken instance), their peers register into a dead tenant,
and the operator's account silently stops being "single". Recovery requires
owner-token account deletion plus direct store surgery to set
domain/domain_category/is_domain_primary_account on the surviving account.
Suggested fix
When single-account mode is armed, fall back to the configured
--single-account-mode-domain whenever the stored account domain is
empty/invalid (or claim the domain for the surviving account at boot). Also
consider logging account creation at INFO — v0.75 has no log line for it, which
makes this failure mode invisible.
Related: #2773, #3545, #1712, #964 (same symptom class reported against
Zitadel/Authentik setups; this analysis may explain them).
Environment: management/signal/relay 0.75.0, dashboard v2.90.6, sqlite
store, embedded IdP (Dex) with Google Workspace connector, single-node k8s
(arm64).
Summary
On self-hosted v0.75.0 with
--single-account-mode-domain=<domain>and theembedded IdP (Dex + Google upstream connector), an uninvited-but-legitimate
Google user logging in for the first time got a brand-new account (owner of an
empty tenant) instead of joining the existing account — while single-account
mode was armed. Reading the management source, this appears to be a general
trap, not a config error:
updateUserAuthWithSingleMode()(management/server/account.go ~1572-1599)overrides the JWT Domain/DomainCategory with the domain stored on the
existing account (via
GetAnyAccountID) — not with the configured--single-account-mode-domainvalue.first IdP login — e.g. a
/api/setupbootstrap account — causes subsequentIdP-created accounts to inherit
domain=""),isDomainValid("")fails andthe flow falls through to
GetOrCreateAccountByUser()→ a NEW account iscreated for every unknown user, silently defeating single-account mode.
domainIsUpToDate()returns early whenever the stored domain differs fromthe claims domain.
single account mode disabled, accounts number Nand SAM is off entirely.Reproduction (self-hosted 0.75.0)
--single-account-mode-domain=example.com, embedded IdP +Google connector, create the first account such that its
domaincolumnends up empty (first login while a setup account existed is enough).
log subsequently reports
single account mode disabled, accounts number 2.Expected: user joins the single existing account (pending approval when
user_approval_requiredis set).Impact
The new user sees a fully-featured empty "admin" dashboard (confusing; looks
like a breach or a broken instance), their peers register into a dead tenant,
and the operator's account silently stops being "single". Recovery requires
owner-token account deletion plus direct store surgery to set
domain/domain_category/is_domain_primary_accounton the surviving account.Suggested fix
When single-account mode is armed, fall back to the configured
--single-account-mode-domainwhenever the stored account domain isempty/invalid (or claim the domain for the surviving account at boot). Also
consider logging account creation at INFO — v0.75 has no log line for it, which
makes this failure mode invisible.
Related: #2773, #3545, #1712, #964 (same symptom class reported against
Zitadel/Authentik setups; this analysis may explain them).
Environment: management/signal/relay 0.75.0, dashboard v2.90.6, sqlite
store, embedded IdP (Dex) with Google Workspace connector, single-node k8s
(arm64).