diff --git a/nix/host-modules/swarm-authelia.nix b/nix/host-modules/swarm-authelia.nix index 9b6c9584..5fff0a71 100644 --- a/nix/host-modules/swarm-authelia.nix +++ b/nix/host-modules/swarm-authelia.nix @@ -587,6 +587,15 @@ in 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. + + ⚠️ `null` is NOT accepted on a client with `bearerAuthz`. + Measured against authelia 4.39.20: under that scope the + method must be *stated*: omitting it is refused with + `must be configured as 'client_secret_basic', … but it's + configured as` an empty string. The sentence above is + true of an ordinary client and false of that one, which + is exactly how a reviewer reads this option and concludes + the assertion below is wrong. ''; }; @@ -935,7 +944,30 @@ in + ". A confidential client carrying authelia.bearer.authz must " + "authenticate with client_secret_basic, client_secret_jwt or " + "private_key_jwt. Notably client_secret_post is refused, and " - + "it is what an OAuth2 client library may reach for first."; + + "it is what an OAuth2 client library may reach for first. " + + "Leaving it null is refused too: authelia requires the method " + + "to be STATED under this scope rather than defaulted."; + } + # Nothing else stops `bearerAuthz` on an interactive client, and it + # would silently do nothing: `renderClient` reads the flag only in + # the `machine` branch, so the scope is simply never emitted and the + # client authenticates fine while being authorised for nothing. + # + # That is this module's own failure mode one level up — a green + # build and a grant that does not exist — and `kind` defaults to + # `interactive`, so it is reached by FORGETTING a field rather than + # by writing a wrong one. + { + assertion = lib.all (c: !c.bearerAuthz || c.kind == "machine") cfg.oidc.clients; + message = + "services.hyperhive.swarm.authelia.oidc.clients: " + + lib.concatStringsSep ", " ( + map (c: "client '${c.id}'") (lib.filter (c: c.bearerAuthz && c.kind != "machine") cfg.oidc.clients) + ) + + " sets bearerAuthz with kind != \"machine\". The scope is only " + + "emitted for machine clients, so this grants nothing while " + + "evaluating and deploying cleanly. A browser client has a user " + + "to authorise and does not need it."; } ];