diff --git a/nix/host-modules/hive-matrix.nix b/nix/host-modules/hive-matrix.nix index b532c5c6..dbcc34ae 100644 --- a/nix/host-modules/hive-matrix.nix +++ b/nix/host-modules/hive-matrix.nix @@ -665,6 +665,13 @@ in id = cfg.sso.clientId; description = "HyperHive matrix"; redirectUris = [ ssoCallbackUrl ]; + # tuwunel authenticates at the token endpoint by putting the + # secret in the POST body. Authelia enforces the *registered* + # method rather than accepting whichever one arrives, and its + # default is `client_secret_basic` — so without this the browser + # flow completes, consent is granted, and the very last hop fails + # with a 401 that names neither the secret nor the redirect. + tokenEndpointAuthMethod = "client_secret_post"; } ]; diff --git a/nix/host-modules/swarm-authelia.nix b/nix/host-modules/swarm-authelia.nix index 4aa98003..ca1a72e9 100644 --- a/nix/host-modules/swarm-authelia.nix +++ b/nix/host-modules/swarm-authelia.nix @@ -144,6 +144,9 @@ let printf -- " client_secret: '%s'\n" "$(cat ${lib.escapeShellArg "${clientsDir}/${c.id}.digest"})" printf -- ' authorization_policy: one_factor\n' '' + + lib.optionalString (c.tokenEndpointAuthMethod != null) '' + printf -- ' token_endpoint_auth_method: %s\n' ${lib.escapeShellArg c.tokenEndpointAuthMethod} + '' + ( if c.kind == "machine" then '' @@ -417,6 +420,35 @@ in rather than silently ignored. ''; }; + + tokenEndpointAuthMethod = lib.mkOption { + type = lib.types.nullOr ( + lib.types.enum [ + "client_secret_basic" + "client_secret_post" + "client_secret_jwt" + "private_key_jwt" + "none" + ] + ); + default = null; + example = "client_secret_post"; + description = '' + How this client proves its identity at the token + endpoint. `null` leaves authelia on its own default + (`client_secret_basic`), which is what every client that + does not say otherwise gets. + + Set it when the relying party's implementation differs, + because authelia enforces the registered method rather + than accepting whatever arrives. tuwunel sends + `client_secret_post`, and against a client registered for + basic the result is a 401 from `/api/oidc/token` **after + a successful consent** — the login looks like it worked + right up to the last hop, and neither the redirect nor + the secret is at fault. + ''; + }; }; } );