From 3e5587dd4d3c0c356f201b0eb957ee96f5c2e4bd Mon Sep 17 00:00:00 2001 From: atlas Date: Sun, 16 Aug 2026 18:28:57 +0200 Subject: [PATCH] fix(#3150): let an SSO login adopt the matrix account it names An SSO login whose derived localpart already exists silently gets a random one instead: the candidate must be *available*, an existing unlinked account is not, and `unique_id_fallbacks` defaults to true. The operator's own login minted a stray account this way. Fill the three identity_provider fields that decide which account a login lands on: `trusted` (upstream's precondition -- self-hosted and fully controlled -- is structural here, the issuer is always the swarm's own authelia), `userid_claims` pinned to preferred_username so the default ladder cannot fall through to an email local part, and `unique_id_fallbacks = false` so a collision errors instead of succeeding as the wrong user. --- nix/host-modules/hive-matrix.nix | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/nix/host-modules/hive-matrix.nix b/nix/host-modules/hive-matrix.nix index dbcc34ae..e6fbe717 100644 --- a/nix/host-modules/hive-matrix.nix +++ b/nix/host-modules/hive-matrix.nix @@ -887,6 +887,30 @@ in # relying on that logs a warning every startup, and a # recurring warning that is expected is one nobody reads. default = true; + + # Upstream's rule is "only ever set `trusted` for + # identity providers you self-host and fully control", + # and this module cannot point anywhere else: the issuer + # is `swarm.authelia.url`, whose client, secret and user + # database are all ours. It does mean whoever can make + # authelia emit a given name gets that account — for our + # own identity provider that IS the identity. + # Without it, an SSO login cannot adopt an account that + # already exists; it can only ever create a new one. + trusted = true; + + # One claim instead of upstream's ladder + # (`preferred_username` → `username` → `nickname` → + # `login` → `email`). The tail is the hazard: an email + # local part is a different namespace, so a login can + # land on a name that means someone else here. + userid_claims = [ "preferred_username" ]; + + # The default (`true`) makes a name collision SILENT — + # tuwunel invents a random localpart and the login + # succeeds as the wrong user. `false` errors instead, + # which is the only form of this an operator can act on. + unique_id_fallbacks = false; } ]; };