Forward auth
Forward auth puts a login page in front of an application that has none. Caddy asks CPM about every request; CPM either says yes or redirects the visitor to sign in.
A host has one sign-in, but it can add a bot challenge in front of it: Anubis is a separate switch, checked first, so bots never reach the login page.
The built-in portal
Section titled “The built-in portal”No external identity provider required. CPM serves the login page itself, issues a session cookie, and validates each request against it. Visitors sign in with a local account or through an OAuth provider. A local account with two-factor sign-in is asked for its code here too.
Who gets in
Section titled “Who gets in”Access is granted per host, by user or by group. Groups are the maintainable form - add
someone to staff once and they reach every host staff can reach, rather than being added to
each host individually.
Excluded paths
Section titled “Excluded paths”Some paths must not be authenticated: a webhook receiver, a health check, an API the application serves to machines. Excluded paths bypass the portal while the rest of the host stays protected.
- adminsRuns the stack2 members
- staff11 members
- Averyavery@example.com
- Samsam@example.com
Header forwarding
Section titled “Header forwarding”Once a visitor is authenticated, their identity can be forwarded to the application as headers, so an app that understands “trusted proxy told me who this is” does not need its own login at all.
| Header | Carries |
|---|---|
X-CPM-User |
The sign-in username, or the email address for an account without one |
X-CPM-Email |
The email address |
X-CPM-Groups |
The user’s groups, comma-separated |
X-CPM-User-Id |
An opaque UUID that never changes for the account |
Key an application’s accounts on X-CPM-User-Id when it can: a username or email can be edited,
the id cannot. Installs upgraded from before the UUID keep sending the sequential account number
here, which their upstreams were already keyed on; Settings → Forward Auth → Numeric forward-auth
user IDs switches between the two, and changes the id every upstream sees for every user.
Bring your own auth server
Section titled “Bring your own auth server”A host can instead be pointed at a forward-auth server you already run - Authelia, tinyauth, anything that answers a forward-auth subrequest. Pick the Authelia preset and the endpoint and identity headers are filled in; pick Custom and you supply them. Settings → Forward Auth → Forward Auth Defaults sets what new hosts inherit.
The identity headers the auth server returns are stripped from every inbound request before the
upstream sees it, on protected and unprotected paths alike, so a caller cannot forge Remote-User
by simply sending it.
Mixed UI and API hosts
Section titled “Mixed UI and API hosts”An auth server answers an unauthenticated browser with a redirect to its login page. An API client or a WebSocket handshake cannot follow that, and gets an HTML page where it expected JSON.
Answer non-browser callers with 401 splits the two: a request that asked for HTML keeps the redirect, everything else gets a bare 401.
Where the application has its own API credential - Moonraker’s X-Api-Key, say - list that header
under Bypass headers. A request carrying it skips forward auth entirely and the application
checks the credential itself.
Authentik
Section titled “Authentik”If you already run Authentik, CPM can point at its outpost instead of serving the portal itself, with configurable header forwarding and protected paths. Settings → Forward Auth → Authentik Defaults sets what new hosts inherit, and each host can override it.
The route that proxies the outpost’s own paths (such as /outpost.goauthentik.io/*) drops the
client’s Authorization header: none of the host’s other handlers run there to strip it, and the
outpost’s start, callback and sign-out endpoints work from cookies.