2026-06-11 — Broker confidential web-client support
Implemented plan Step 1 from
/demarkus-library/plans/phase-1b-web-sso.md
on branch feature/phase-1b-broker-web-client (demarkus repo, broker).
What landed
webClientsregistry in broker config:clientID,clientSecretHash(sha256-hex, normalized + shape-validated at load), exact-match httpsredirectURIs(no loopback, no userinfo, no fragment), optionalname./oauth/authorizebranches on registry membership: registered client → allowlist exact match; unregistered → existing loopback-only path untouched.authorization_codegrant requires client auth (Basic per RFC 6749 §2.3.1 with form-urlencoded halves, orclient_secret_post) when the presented client_id is registered. Verified constant-time before Redeem so a bad secret never burns the code. 401invalid_client+WWW-Authenticate: Basic.- Refresh tokens minted through a confidential exchange carry
clientID(omitempty— old Secret records decode as unbound); the refresh grant requires the bound client to authenticate. Deregistered client → bound tokens stop minting. - Discovery now advertises
token_endpoint_auth_methods_supported: ["none","client_secret_basic","client_secret_post"]. - New
client_auth.go(parse + verify + 401 helper),web_client_test.go(~7 test funcs incl. code-preserved-after-401 pin), ADR atdocs/adr/0001-broker-confidential-web-clients.md(first repo ADR).
Deviations from the plan (reasoned, recorded in the ADR)
- No
Confidentialstamp in the auth-code store. Redundant: Redeem already binds client_id constant-time and the registry is immutable for the process lifetime, so registry lookup of the presented client_id is authoritative. Checking the secret pre-Redeem also preserves the store's keep-code-on-client-error semantics. - No per-client
scopesfield. Scopes are declared-not-enforced broker-wide; the field would be dead config (conventions: question opt-in knobs).
Gotcha
deviceTokenRefresh verifies client binding after refreshStore.Refresh
(the record is the source of the requirement), so a failed client auth still
bumps LastUsedAt. Deliberate: observability metadata only, no token minted.
Documented in the handler comment.
Follow-ups
- Helm chart values surface for
webClients(config is additive; chart not touched in this change). /token/revokedoes not require client auth for bound tokens — RFC 7009 would suggest it; revocation-by-holder is fail-safe so left as is.- Tests +
bash pre-commit.shgreen. Fritz to commit + PR.