Document Authentik forwards auth for apps without SSO support, like Firefly iii

This commit is contained in:
Goyban
2026-09-01 10:02:28 +02:00
parent 64773f0a16
commit 50f9aff43a
2 changed files with 108 additions and 5 deletions
+96 -2
View File
@@ -24,9 +24,103 @@ app asks for:
- Client secret → `.env`, never committed - Client secret → `.env`, never committed
- Redirect URI - Redirect URI
## Forward auth — the shape ## Forward auth — putting an app with no SSO behind Authentik
TODO: the Caddy snippet, and which services you apply it to. This is the fallback, and it's what most self-hosted apps need. The app itself
learns nothing and changes nothing: **Caddy asks Authentik whether to allow the
request before it ever reaches the container.** An app with no accounts at all,
or one with its own login you can't replace, ends up behind a real SSO login
page either way.
### In Authentik
1. **Providers → Create → Proxy Provider**, mode **Forward auth (single
application)**. The external host is the public URL — `https://firefly.domain.com`.
2. **Applications → Create**, and bind it to that provider.
3. **Outposts** — add the application to an outpost. The built-in *embedded
outpost* is the one already listening on port **9000**, which is what the
Caddyfile below points at.
Step 3 is the one that gets forgotten. Provider and application exist, the
Caddyfile is right, and every request still fails because the outpost was never
told the application is its responsibility.
### In Caddy
```caddyfile
firefly.domain.com {
# directive execution order is only as stated if enclosed with route.
route {
# always forward outpost path to actual outpost
reverse_proxy /outpost.goauthentik.io/* http://127.0.0.1:9000
# forward authentication to outpost
forward_auth http://127.0.0.1:9000 {
uri /outpost.goauthentik.io/auth/caddy
# capitalization of the headers is important, otherwise they will be empty
copy_headers X-Authentik-Username X-Authentik-Groups X-Authentik-Entitlements X-Authentik-Email X-Authentik-Name X-Authentik-Uid X-Authentik-Jwt X-Authentik-Meta-Jwks X-Authentik-Meta-Outpost X-Authentik-Meta-Provider X-Authentik-Meta-App X-Authentik-Meta-Version
# optional, in this config trust all private ranges, should probably be set to the outposts IP
trusted_proxies private_ranges
}
# actual site configuration below, for example
reverse_proxy 10.10.0.2:8564
}
}
```
Only the last line changes per service: swap the address and port, and the
hostname at the top. Everything between is identical for every app.
### Why each piece is there
**`route { }` is not optional.** Caddy normally executes directives in its own
fixed order, not the order you wrote them. Without `route`, the final
`reverse_proxy` can run before `forward_auth`, and the app is served to
unauthenticated visitors. The config *looks* correct and protects nothing —
which is the worst possible failure mode for this feature, so wrap it and check
in a private window.
**The `/outpost.goauthentik.io/*` line comes first** because the login flow
itself lives on that path. If it fell through to the app, the browser would be
sent to a URL the app doesn't serve and the redirect loop would never resolve.
**`copy_headers` capitalization is load-bearing** — get it wrong and the headers
arrive empty rather than missing, so an app that reads them sees a blank
username instead of an error.
**`127.0.0.1:9000` assumes Caddy and Authentik are on the same host.** If Caddy
runs on a VPS and Authentik on the NAS, this is the line to change — and
`trusted_proxies private_ranges` should then name the outpost's actual address
rather than trusting every private range.
### What you give up
- **The app doesn't know who you are.** It sees an authenticated-by-someone
request. Apps with their own accounts still show their own login, so you get
**two logins** — Authentik, then the app. Some apps can read the
`X-Authentik-*` headers and skip theirs; most can't.
- **Non-browser clients break.** Mobile apps, API clients and anything doing
`curl` can't complete an interactive login flow. This is why Jellyfin and
Audiobookshelf use native OIDC instead — see
[jellyfin](../jellyfin/README.md) and
[audiobookshelf](../audiobookshelf/README.md). If a service has an API you
actually call, forward auth in front of it will stop that too.
- **It is all-or-nothing per hostname.** Every path behind that block requires
login, including webhooks and health checks.
### Where I use it
- **[Firefly III](../firefly/README.md)** — the config above is verbatim what
runs in front of it. Firefly keeps its own login underneath, so it's two
logins, and for bank data that's a trade worth making.
- **[copyparty](../copyparty/README.md)** and other apps with their own account
system, where the second login is the price of not exposing the app's login
form to the internet.
Prefer native OIDC wherever the app supports it. Reach for this when it doesn't.
## Groups and roles ## Groups and roles
+12 -3
View File
@@ -221,9 +221,18 @@ behind a proxy.
- [Reverse proxy with Caddy](../docs/reverse-proxy.md) — the default choice. - [Reverse proxy with Caddy](../docs/reverse-proxy.md) — the default choice.
- [Cloudflare Tunnel](../cloudflare-tunnel/) — fine for this one. It's a text - [Cloudflare Tunnel](../cloudflare-tunnel/) — fine for this one. It's a text
app; nothing here bumps the ~100 MB body cap unless you attach large files. app; nothing here bumps the ~100 MB body cap unless you attach large files.
- [Single sign-on with Authentik](../docs/authentik-sso.md) — **think first.** - [Single sign-on with Authentik](../docs/authentik-sso.md#forward-auth--putting-an-app-with-no-sso-behind-authentik)
This is your bank data, and Firefly's own login is the only thing in front of — **what I do.** Firefly has no OIDC support, so it sits behind Authentik
it today. Keep a working local admin until any SSO flow is proven. forward auth: Caddy checks with Authentik before the request reaches the
container. That means two logins, Authentik then Firefly, which for bank data
is a trade worth making — the app's own login form is never exposed to the
internet. The exact Caddyfile is in that doc.
Two things to keep in mind here specifically. Firefly's **API is behind the
same wall**, so external API clients stop working (the bundled importer is
unaffected — it talks to `app:8080` inside the compose network, never through
the proxy). And keep a working local admin until the flow is proven; locking
yourself out of your own ledger is an unpleasant afternoon.
## Links ## Links