feat(3150): matrix SSO options — opt-in OIDC relying party

Stage 1 of the staged rollout mara laid out on the issue: the options
and nothing that changes a running hive. `enable` defaults false, so
this commit is inert until someone opts in.

Three rules taken from hive-forge/default.nix rather than re-derived,
since it is the same pattern already merged and reviewed:

- `enable` ADDS a login path and leaves password login alone. An
  identity provider that can take the homeserver offline when it
  hiccups is worse than two ways in. Making authelia the only path is
  tuwunel's `login_with_password`, a separate and reversible switch,
  deliberately not folded in here.
- the client secret is a PATH, never a value: it has two holders in two
  containers (authelia keeps a hash, the homeserver needs plaintext),
  and a literal would be rendered into the world-readable store.
- required when enabled, no fallback. Worse here than for the forge:
  tuwunel reads OIDC from its config file rather than a database row,
  so a malformed block can stop the server outright instead of merely
  hiding a button.

Also records the constraint that shapes the whole issue — matrix SSO
lives inside the homeserver, never behind a forward-auth proxy,
because the client-server API is spoken by non-browser clients holding
matrix access tokens plus federation.
This commit is contained in:
atlas 2026-08-14 10:19:50 +02:00
commit 9fa75a7f2f

View file

@ -394,6 +394,62 @@ in
'';
};
};
sso = {
enable = lib.mkOption {
type = lib.types.bool;
default = false;
description = ''
Let this homeserver delegate login to the swarm's authelia,
as an OIDC relying party ("matrix next-gen auth").
This **adds** a way in. Password login keeps working: an
identity provider that can take the homeserver offline when
it hiccups is a worse homeserver than one with two ways in.
Making authelia the only path is a separate, reversible
switch (tuwunel's `login_with_password`), deliberately not
folded in here.
Matrix SSO lives **inside** the homeserver, never behind a
forward-auth proxy: the client-server API is spoken by
non-browser clients holding matrix access tokens every
agent's own `hive-matrix-daemon` plus federation, and a
proxy in front of `/_matrix/` breaks all of it.
'';
};
clientId = lib.mkOption {
type = lib.types.str;
default = "tuwunel";
description = ''
OAuth2 client id this homeserver identifies itself with. Must
match the `id` of the corresponding entry in
`services.hyperhive.swarm.authelia.oidc.clients`.
'';
};
clientSecretFile = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = null;
example = "/var/lib/tuwunel-oidc/tuwunel.secret";
description = ''
Path **inside the matrix container** holding the client
secret's plaintext.
A path, never a value: an OIDC client secret has two holders
in two containers (authelia keeps a hash, this homeserver
needs the plaintext), and a literal written here would be
rendered into the world-readable nix store.
Required when `enable` is set deliberately no fallback. A
homeserver that boots with SSO half-configured is worse than
one that fails to evaluate: tuwunel reads OIDC from its
config file rather than a database row, so a malformed block
can stop the server outright instead of merely hiding a
button.
'';
};
};
};
config = lib.mkIf cfg.enable {