Release v2.12.0
Summary
AuthProxy authenticated but never authorized. On a public host with a public identity provider that means every account on the internet completes sign-in and reaches the application. Cratis:AuthProxy:Authorization makes the proxy the first gate: an authenticated caller who does not carry what you require never reaches a service at all. It is off unless configured, so an existing deployment is unaffected.
Added
Cratis:AuthProxy:Authorization:RequiredClaims— require an authenticated caller to carry a claim, optionally with a set of accepted values, before any request is forwarded. Every requirement must be satisfied (an and); within one requirement any listed value will do (an or). Values are compared case-insensitively.- The same section on a service (
Cratis:AuthProxy:Services:<key>:Authorization) applies in addition to the proxy-wide requirements, so a service can narrow who reaches it but never widen it. The targeted service is resolved the way the route table resolves it — the single configured service, otherwise theService-IDheader or theservicequery parameter. - GitHub organization and team membership as claims. A GitHub OAuth provider that requests the
read:orgscope has its organizations and teams read once while sign-in completes and added to the session asurn:github:organizationandurn:github:team(asorganization/team-slug). The claims also travel to the application on the forwarded principal. GitHub Enterprise works without extra configuration — the endpoints are derived from the configuredUserInformationEndpoint. not-authorized.html, a new well-known page served at403to a signed-in caller who does not satisfy a requirement. It carries a sign-out link, since coming back as a different account is the only way forward, and can be overridden like every other page throughPagesPath.- Aspire builders
WithRequiredClaim(claim, anyOf…)andWithRequiredClaimForService(service, claim, anyOf…). Repeated calls append. - Documentation: a new Authorization page with a worked GitHub organization and team example, and an OAuth 2.0 provider section in Authentication, which was previously undocumented.
Changed
- A claim requirement that names no claim type now fails startup, naming the exact configuration key. It could never be satisfied, so starting would refuse every caller and ignoring it would leave the gate silently open.
Notes on behavior worth knowing before configuring it:
- Paths a service declares in
AnonymousPathsare not gated. They exist for callers with no session, who carry no claims, so gating them would refuse every one of them — a webhook receiver would get a403it could do nothing about. - The authentication endpoints and callers with no session are not gated either; the existing sign-in machinery handles them.
- GitHub membership is read at sign-in and lives in the session, so revoked membership takes effect when the session ends — bounded by
Cratis:AuthProxy:Session:Lifetime.