Logout
AuthProxy exposes a well-known logout endpoint that ends the current session and returns the user to a validated destination:
GET /.cratis/logout?redirect=<absolute-url>The endpoint is anonymous — it works even when the session is already invalid — and is handled before the authentication challenge stages, so it never bounces the user to a login provider.
Full-chain logout
Section titled “Full-chain logout”A plain cookie logout leaves the user signed in at the identity provider, so the next visit silently re-authenticates. To avoid that, AuthProxy performs a full-chain logout: it ends the session both locally and at the identity provider using OIDC RP-initiated logout.
When the session was established through an OIDC provider, a logout request:
-
Reads the stored
id_tokenand the provider the session was established with from the authentication cookie, and clears the local session (see What it clears). -
Redirects (
302 Found) the browser to that provider’s end-session endpoint (discovered from the provider’s OpenID configuration) with:id_token_hint— the storedid_token, so the provider knows which session to end.post_logout_redirect_uri— AuthProxy’s own callback,/.cratis/logout/callback.
The validated final
redirecttarget is carried across the round-trip in a short-lived, HTTP-only cookie (.cratis-logout) rather than in the URL. -
The identity provider ends its own session and redirects back to
/.cratis/logout/callback. -
The callback clears every AuthProxy cookie again (idempotent) and redirects (
302 Found) to the validated finalredirecttarget.
Register the callback with each OIDC provider.
post_logout_redirect_urimust be allow-listed at the provider, so registerhttps://<your-proxy-host>/.cratis/logout/callbackas a permitted post-logout redirect URI for every OIDC application.
OAuth 2.0 providers (e.g. GitHub)
Section titled “OAuth 2.0 providers (e.g. GitHub)”OAuth 2.0 providers have no standard OIDC end-session endpoint and cannot be force-logged-out via a
redirect. When the session was established through an OAuth provider — or when there is no active OIDC
session, or the provider’s discovery document advertises no end-session endpoint — AuthProxy falls back to
a local-only logout: it clears its own cookies and redirects straight to the validated redirect
target. The user’s session at the OAuth provider is left untouched, so a later visit may still
re-authenticate silently without asking for credentials. This is a limitation of the OAuth providers, not
of AuthProxy.
What it clears
Section titled “What it clears”Both the local logout and the post-logout callback:
- Sign the user out of the authentication cookie (
.Cratis.AuthProxy.Auth.v2unless you setSession:CookieName), including any chunked variants. WithSession:CookieDomainthe deletion carries the domain, so it ends the session on every host under it, and the stale host-only copy an earlier deployment left behind is deleted too. - Delete every AuthProxy session cookie:
.cratis-identity.cratis-identity-authorization.cratis-tenant.cratis-tenants.cratis-invite.cratis-invite-state.cratis-registration.cratis-providers
- Delete every transient sign-in handshake cookie the browser sent (
.AspNetCore.Correlation.*,.AspNetCore.OpenIdConnect.Nonce.*) — the leftovers of abandoned handshakes that would otherwise poison the next sign-in. See Failed Sign-ins. - Delete any additional cookies the deployment configured under
Cratis:AuthProxy:Logout:AdditionalCookies— cookies AuthProxy does not issue itself but that must not survive a logout. See Clearing additional cookies.
The .cratis-logout carry cookie is deleted by the callback once the final target has been read from it.
After logout nothing of the session survives, so the next visit to a protected resource lands on the provider-selection page (or the single provider’s login) rather than silently reusing anything local. Whether the identity provider still remembers the user is governed by the full-chain behavior above.
The redirect parameter
Section titled “The redirect parameter”The post-logout destination is supplied as an absolute URL in the redirect query-string parameter,
for example:
/.cratis/logout?redirect=https://cratis.studioBecause the target is absolute, it cannot be validated with the relative-URL check used elsewhere. Instead it is matched against an allow-list of origins so neither the endpoint nor its callback can be turned into an open redirect. The target is validated on both legs of the round-trip. A target is allowed when its origin (scheme + host + port) matches any of:
-
The proxy’s own public origin as seen by the browser (derived from the request, honoring
X-Forwarded-Proto). This covers redirecting back to the site the user is already on. -
Any configured service frontend (
Cratis:AuthProxy:Services:<name>:Frontend:BaseUrl). -
The configured lobby frontend (
Cratis:AuthProxy:Invite:Lobby:Frontend:BaseUrl). -
Any origin listed in
Cratis:AuthProxy:Logout:AllowedRedirectOrigins(see below). -
When
SignIn:CallbackHostis configured, the origin of every host a service declares inHosts, on the scheme the request arrived on. Without a callback host, hosts are not added: a deployment that serves several hosts without one lists them underAllowedRedirectOrigins.
Same-site relative URLs (a single leading /, but not //) are always allowed. Addresses carrying user
information (https://user@host/) are never allowed.
If redirect is missing, empty, or fails validation, AuthProxy falls back to the application root (/).
With a callback host, a logout that ends at the identity provider and starts on another host is sent to the callback host first, because the identity provider returns the browser to one registered address and the carrier of the final destination is a host-only cookie. The session cookie is deleted there and is shared, so the person is signed out on every host under the cookie domain.
Allowing additional post-logout origins
Section titled “Allowing additional post-logout origins”The implicit origins above cover redirecting back to the app itself, but a deployment often wants to send
the user somewhere else after logout — for example a separate marketing or landing site that is neither
the proxy’s own origin nor a configured frontend. List those origins under
Cratis:AuthProxy:Logout:AllowedRedirectOrigins. Each entry is an absolute origin (scheme + host,
optionally a port) with no path; malformed or non-HTTP(S) entries are ignored.
{ "Cratis": { "AuthProxy": { "Logout": { "AllowedRedirectOrigins": [ "https://cratis.studio" ] } } }}Equivalent environment variables (one indexed key per entry):
Cratis__AuthProxy__Logout__AllowedRedirectOrigins__0=https://cratis.studioWith the example above, GET /.cratis/logout?redirect=https://cratis.studio is permitted even when the
app itself is served from a different host such as https://app.cratis.studio.
Clearing additional cookies
Section titled “Clearing additional cookies”Logout clears every cookie AuthProxy issues — but a deployment often runs sibling authentication
infrastructure whose cookies AuthProxy knows nothing about. The classic case is a separate
oauth2-proxy guarding an admin app whose session cookie
was scoped to the parent domain (e.g. _oauth2_proxy_admin on .cratis.studio): every browser that
ever signed in there sends it on every *.cratis.studio request, and it survives AuthProxy’s logout —
leaving the user half-signed-in from the application’s point of view.
List such cookies under Cratis:AuthProxy:Logout:AdditionalCookies and the session-termination sweep
deletes them too. Each entry has:
Name(required) — the exact cookie name. Matching is by exact name only; there is no prefix or wildcard support.Domain(optional) — the domain the cookie was scoped to, e.g..cratis.studio. When set, the deletion is issued for that domain as well as the request host — necessary because a host-scoped deletion cannot touch a parent-domain cookie. Deleting for a parent domain of the current host is legal, which is exactly what makes this work. Leave it out for a cookie scoped to the request host itself.
Deletions are issued at the root path (Path=/) with the Secure attribute mirroring the request scheme,
so they reliably match how such cookies are typically written.
{ "Cratis": { "AuthProxy": { "Logout": { "AdditionalCookies": [ { "Name": "_oauth2_proxy_admin", "Domain": ".cratis.studio" } ] } } }}Equivalent environment variables (one indexed entry per cookie):
Cratis__AuthProxy__Logout__AdditionalCookies__0__Name=_oauth2_proxy_adminCratis__AuthProxy__Logout__AdditionalCookies__0__Domain=.cratis.studioThe configured cookies are cleared everywhere the session is terminated:
- the logout endpoint (both legs of a full-chain logout), and
- the sign-in sweep that runs when a provider callback completes — so a fresh sign-in also heals a browser still carrying the stale cookie, without requiring the user to log out first.
This is a cleanup mechanism for cookies that linger after the owning deployment has been fixed (for example, until an old parent-domain cookie expires) — it does not log the user out of the system that issued the cookie.
Example
Section titled “Example”A “Log out” control in the application simply navigates the browser to the endpoint:
<a href="/.cratis/logout?redirect=https://cratis.studio">Log out</a>For an OIDC session the browser is taken through the provider’s end-session endpoint and back via the callback; for an OAuth session it lands on the target directly. Either way the user ends up on the target unauthenticated at AuthProxy, and requesting a protected resource then triggers the normal login flow.