Restoring the legacy chat/triage hosts is not enough on its own: both
proxies pinned --redirect-url to the renamed host, and oauth2-proxy
returns that value verbatim whenever it carries a host
(getOAuthRedirectURI short-circuits on redirectURL.Host != ""). A login
started on a legacy host would therefore send the browser to the
canonical host's callback, while the CSRF cookie stays behind: it is
issued with the __Host- prefix, which forbids a Domain attribute and
pins it to the exact origin. The callback lands without it and fails as
"unable to find a valid CSRF token".
Drop the host from both callback URLs so oauth2-proxy builds them from
the request host instead. For the renamed hosts the derived value is
byte-identical to the pinned one, so their behaviour is unchanged; the
legacy hosts now complete a login on the host the user actually visited.
Derivation reads X-Forwarded-Host only behind a trusted reverse proxy,
which both deployments already declare, and Keycloak still matches the
result against the redirect URIs registered by the ensure script.
The agent proxy keeps its pinned callback: it serves one host.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The #34 rename dropped the legacy chat/triage names from the certificate
SANs, the hermes-sites Ingress, the CoreDNS overrides and the Keycloak
ensure script at the same time, so nothing failed loudly: DNS and TLS
still looked healthy while the legacy hosts served 404 and the renamed
hosts could not finish a login.
Pin the invariant that makes that silent: a public host is either served
by all four layers or by none. The table of hosts is the contract, so
retiring a name stays a deliberate edit rather than a side effect.
Verified to catch the regression: against the pre-fix tree these fail for
both legacy hosts on all four layers (9 failures); against this branch
the suite is green.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>