Well-Known Pages
AuthProxy serves built-in HTML pages for a range of conditions — provider selection, invitation errors, tenant errors, and generic HTTP errors. Every page can be overridden by mounting a directory of custom pages into the container.
Built-in pages
Section titled “Built-in pages”The following pages are included with AuthProxy and are served automatically when the corresponding condition is detected:
| File name | Condition | HTTP status |
|---|---|---|
404.html | The requested resource was not found. | 404 |
403.html | The identity resolver denied access. | 403 |
not-authorized.html | The caller is signed in but does not satisfy the claim requirements declared in Cratis:AuthProxy:Authorization. | 403 |
tenant-not-found.html | The resolved tenant does not exist in the platform (see Tenant verification). | 404 |
select-provider.html | A protected resource was requested and multiple identity providers are configured, or a sign-in failed (see Failed Sign-ins). The page reads the .cratis-providers cookie to render a sign-in button for each available provider, and shows a message when a reason query parameter is present. | 200 |
select-tenant.html | Tenant selection is enabled and the authenticated user has not selected a tenant yet. The page reads the .cratis-tenants cookie to render selectable tenants. | 200 |
invitation-expired.html | The JWT token on an invite link has passed its expiry time. Served in either phase — when the link is followed (Phase 1) and when the token is re-validated at the exchange (Phase 2). | 401 |
invitation-invalid.html | The JWT token on an invite link is malformed or has an invalid signature. Served in either phase — when the link is followed (Phase 1) and when the token is re-validated at the exchange (Phase 2). | 401 |
invitation-select-provider.html | A valid invite link was followed and multiple identity providers are configured. The page reads the .cratis-providers cookie to render a sign-in button for each available provider. | 200 |
invitation-subject-already-exists.html | The authenticated user’s subject is already associated with an existing account during invite exchange (Phase 2). | 409 |
invitation-email-unavailable.html | Gateway email binding is enabled (Invite.EmailClaim), but the identity provider supplied no authenticated-session email address (Phase 2). | 403 |
invitation-email-mismatch.html | Gateway email binding is enabled (Invite.EmailClaim), and the identity provider supplied another address or explicitly reported email_verified=false (Phase 2). | 403 |
link-select-provider.html | The embeddable provider-selection page of the credential-link flow, served at /.cratis/link. Lists providers, opens the chosen provider’s link challenge in a top-level window, and reports the outcome to its embedding parent. | 200 |
link-complete.html | A credential link completed, at /.cratis/link/complete. Broadcasts the completion on the link flow’s BroadcastChannel and closes its window. | 200 |
link-failed.html | A credential link did not complete — the provider round-trip failed or the exchange was refused (see Credential Linking). Broadcasts the failure so an embedding selection page can offer a retry. | 403 |
Overriding pages
Section titled “Overriding pages”Mount a directory into the container and point Cratis:AuthProxy:PagesPath at the mount path.
AuthProxy looks up each page by its conventional file name inside that directory.
Any page file that is present overrides the built-in default; missing files fall back to the built-in version.
{ "Cratis": { "AuthProxy": { "PagesPath": "/mnt/pages" } }}Equivalent environment variable:
Cratis__AuthProxy__PagesPath=/mnt/pagesContainer mount example (Docker Compose)
Section titled “Container mount example (Docker Compose)”services: authproxy: image: cratis/authproxy:latest volumes: - ./my-pages:/mnt/pages environment: Cratis__AuthProxy__PagesPath: /mnt/pagesPage assets
Section titled “Page assets”Pages can reference stylesheets, images, and other assets.
Place asset files in the same pages directory — they are served at the /_pages/ URL prefix.
<!-- inside your custom page --><link rel="stylesheet" href="/_pages/styles.css" /><img src="/_pages/logo.svg" alt="Logo" />Provider selection pages
Section titled “Provider selection pages”select-provider.html and invitation-select-provider.html both serve the same purpose —
letting the user choose an identity provider when multiple are configured — but they are
triggered by different flows:
| Page | Triggered by |
|---|---|
select-provider.html | Direct navigation to a protected resource when not yet authenticated. |
invitation-select-provider.html | Following a valid invite link. |
Both pages receive provider data via the .cratis-providers cookie and work identically
from a customization standpoint. See Provider Selection Pages
for the full cookie schema, JavaScript examples, and guidance on building a custom branded page.
Invitation error pages
Section titled “Invitation error pages”Invitation error pages use full descriptive names rather than numeric HTTP status codes because they represent application-level conditions, not generic HTTP errors.
invitation-expired.html
Section titled “invitation-expired.html”Served when an invite token has a valid signature but has passed its exp claim. AuthProxy validates
the token both when the /invite/<token> link is followed (Phase 1) and again at the post-login
exchange (Phase 2), so this page is served whenever an expired token is detected in either phase.
The user should request a fresh invitation.
invitation-invalid.html
Section titled “invitation-invalid.html”Served when an invite token is malformed, carries an invalid signature, or cannot be parsed at all. Because AuthProxy re-validates the token at the Phase-2 exchange — not only when the link is first followed — this page is also served if a tampered or forged token is presented at the exchange.
invitation-subject-already-exists.html
Section titled “invitation-subject-already-exists.html”Served during Phase 2 (post-login invite exchange) when the exchange endpoint returns HTTP 409 Conflict, indicating that the authenticated user’s subject is already associated with an existing account.
invitation-email-mismatch.html
Section titled “invitation-email-mismatch.html”Served during Phase 2 (post-login invite exchange) when gateway email binding is enabled — the
Invite.EmailClaim claim is configured — the invite token was issued for a specific email address — and
the provider supplied another address or explicitly reported email_verified=false. This is distinct from
a provider that supplied no address at all.
invitation-email-unavailable.html
Section titled “invitation-email-unavailable.html”Served during Phase 2 when gateway email binding is enabled and the identity provider supplied no authenticated-session email address. The invite may still target the correct person, but AuthProxy has no address evidence to compare. Use this page to ask the invitee to choose an account or provider that exposes an address, rather than telling them their address mismatched.
Email binding is off by default. See Invitation to Organization for
configuration and the limits of provider-supplied email_verified evidence.
Tenant not found
Section titled “Tenant not found”tenant-not-found.html is served when tenant verification is enabled and the platform reports
that the resolved tenant ID does not exist. See Tenant verification
for how to configure the verification endpoint.
Not authorized
Section titled “Not authorized”not-authorized.html is served when first-gate authorization is configured and an
authenticated caller does not satisfy a required claim — a GitHub organization they do not belong to, a
role they do not hold. It is distinct from 403.html, which answers the application refusing a caller it
does recognize; this one is the proxy refusing before the application is reached at all.
If you override it, keep a way to sign out. It is the only refusal whose remedy is to come back as
somebody else, and someone who signed in with the wrong account is otherwise stuck looking at a page that
will not change. The built-in page links to /.cratis/logout?redirect=/:
<a href="/cratis/logout/?redirect=/">Sign out</a>This is a good page to brand and to make specific — “ask #it-support for access to the planner” is far more useful to the person reading it than “not authorized”.