# KiteStacks Authentik SSO Setup **Established:** 2026-06-08 **Author:** kenpat **Status:** In Progress — config files deployed, manual Authentik UI steps pending --- ## Architecture All services sit behind Cloudflare Tunnels on the `kitestacks` Docker network. `cloudflared` routes external traffic directly to each service container by hostname. Authentik (`authentik:9000`) is the single identity provider. ``` Internet → Cloudflare → cloudflared → [service container] ↕ Authentik auth check ``` **Two integration patterns are used:** | Pattern | How it works | Services | |---------|-------------|---------| | Native OIDC/OAuth2 | App calls Authentik directly for login | Grafana, OpenWebUI, Forgejo, OpenProject, Kavita | | Authentik Proxy Provider | Cloudflare tunnel → Authentik (embedded outpost) → service | Shaarli, Uptime Kuma, LiteLLM | --- ## SSO Status | Service | Subdomain | Port | Method | Status | |---------|-----------|------|--------|--------| | Authentik | auth.kitestacks.com | 9000 | (is the IdP) | ✅ Running | | Grafana | grafana.kitestacks.com | 3000 | OAuth2 | ⚠️ env set, Authentik app needed | | Kite AI (OpenWebUI) | ai.kitestacks.com | 8080 | OIDC | ⚠️ env set, Authentik app needed | | Forgejo | gitforge.kitestacks.com | 3000 | OAuth2 | ⚠️ Forgejo admin UI config needed | | BookStack | — | — | — | 🚫 Retired — books hosted on Kavita | | OpenProject | tasks.kitestacks.com | 80 | OIDC | ⚠️ env set, Authentik app needed | | Kavita | kavita.kitestacks.com | 5000 | OIDC | ⚠️ appsettings.json updated, Authentik app needed | | Shaarli | links.kitestacks.com | 80 | Proxy | ⚠️ Authentik Proxy Provider needed + CF tunnel update | | Uptime Kuma | status.kitestacks.com | 3001 | Proxy | ⚠️ Authentik Proxy Provider needed + CF tunnel update | | LiteLLM | llm.kitestacks.com | 4000 | Proxy | ⚠️ Authentik Proxy Provider needed + CF tunnel update | | Portainer | portainer.kitestacks.com | 9000 | — | 🚫 SSO excluded | | Prometheus | prometheus.kitestacks.com | 9090 | — | 🚫 SSO excluded | | Node Exporter | node-exporter.kitestacks.com | 9100 | — | 🚫 SSO excluded | | OpenRouter | openrouter.ai | — | — | 🚫 external, excluded | *BookStack has been retired. All books are hosted on Kavita (`kavita.kitestacks.com`). --- ## Files Changed (2026-06-08) | File | What changed | |------|-------------| | `apps/authentik/docker-compose.yml` | Added `kitestacks` network declaration, `AUTHENTIK_ERROR_REPORTING__ENABLED: false` | | `apps/kavita/config/appsettings.json` | `OpenIdConnectSettings.Enabled` → `true`, `Authority` set | | `apps/bookstack/docker-compose.yml` | OIDC env vars added, `kitestacks` network added, `APP_URL` updated | | `apps/bookstack/.env` | Created with `BOOKSTACK_OIDC_SECRET` placeholder | | `apps/openproject/docker-compose.yml` | OIDC env vars added, `kitestacks` network declared | | `apps/openproject/.env` | Created with `OPENPROJECT_OIDC_SECRET` placeholder | --- ## Step 1 — Authentik Admin UI: Create Providers and Applications Go to **https://auth.kitestacks.com** → Admin Interface. ### For each native OIDC service, create one OAuth2/OpenID Provider: **General settings (all providers):** - Signing Key: select the default RS256 key - Token validity: 10 minutes (access), 30 days (refresh) #### 1. Grafana - **Providers → Create → OAuth2/OpenID Provider** - Name: `Grafana` - Client type: `Confidential` - Client ID: `grafana` - Redirect URIs: `https://grafana.kitestacks.com/login/generic_oauth` - Scopes: `openid`, `email`, `profile` - **Applications → Create** - Name: `Grafana`, Slug: `grafana` - Provider: `Grafana` (above) - Copy the **Client Secret** → put it in `/home/kenpat/docker/grafana/.env`: ``` GRAFANA_OAUTH_CLIENT_SECRET= ``` - Restart: `cd ~/docker/grafana && docker compose up -d` #### 2. Kite AI (Open WebUI) - **Providers → Create → OAuth2/OpenID Provider** - Name: `Open WebUI`, Client ID: `open-webui` - Redirect URIs: `https://ai.kitestacks.com/oauth/oidc/callback` - Scopes: `openid`, `email`, `profile` - **Applications → Create**: Name: `Kite AI`, Slug: `open-webui` - Copy secret → `/home/kenpat/docker/kite-ai/.env`: ``` OPENWEBUI_OAUTH_CLIENT_SECRET= ``` - Restart: `cd ~/docker/kite-ai && docker compose up -d` #### 3. Kavita - **Providers → Create → OAuth2/OpenID Provider** - Name: `Kavita`, Client ID: `kavita` - Redirect URIs: `https://kavita.kitestacks.com/api/Account/OIDCCallback` - Scopes: `openid`, `email`, `profile` - **Applications → Create**: Name: `Kavita`, Slug: `kavita` - Copy secret → `/home/kenpat/docker/kavita/config/appsettings.json`: ```json "Secret": "" ``` - Restart: `cd ~/docker/kavita && docker compose restart` (if a compose exists) or `docker restart kavita` #### 4. OpenProject - **Providers → Create → OAuth2/OpenID Provider** - Name: `OpenProject`, Client ID: `openproject` - Redirect URIs: `https://tasks.kitestacks.com/auth/oidc/callback` - Scopes: `openid`, `email`, `profile` - **Applications → Create**: Name: `OpenProject`, Slug: `openproject` - Copy secret → `/home/kenpat/docker/openproject/.env`: ``` OPENPROJECT_OIDC_SECRET= ``` - Restart: `cd ~/docker/openproject && docker compose up -d` - **Note:** Container is currently running `openproject/community:13` but compose specifies `openproject/openproject:15`. Recreation will upgrade it. Verify data migration after restart. The Cloudflare tunnel for `tasks.kitestacks.com` may need updating from `openproject:8080` → `openproject:80` after the upgrade. --- ### For proxy services, create Proxy Providers: These services have no native OIDC. Authentik will act as the reverse proxy. **After creating each Proxy Provider + Application, add all three to the Embedded Outpost:** Outposts → `authentik Embedded Outpost` → Edit → move all three proxy applications to "Selected Applications". #### 6. Shaarli - **Providers → Create → Proxy Provider** - Name: `Shaarli` - Mode: `Reverse Proxy` - External host: `https://links.kitestacks.com` - Internal host: `http://shaarli:80` - Internal host SSL validation: off - **Applications → Create**: Name: `Shaarli`, Slug: `shaarli` - **Cloudflare Tunnel**: Change `links.kitestacks.com` route from `http://shaarli:80` → `http://authentik:9000` #### 7. Uptime Kuma - **Providers → Create → Proxy Provider** - Name: `Uptime Kuma` - Mode: `Reverse Proxy` - External host: `https://status.kitestacks.com` - Internal host: `http://uptime-kuma:3001` - **Applications → Create**: Name: `Uptime Kuma`, Slug: `uptime-kuma` - **Cloudflare Tunnel**: Change `status.kitestacks.com` route from `http://uptime-kuma:3001` → `http://authentik:9000` #### 8. LiteLLM *(when ready to expose publicly)* - **Providers → Create → Proxy Provider** - Name: `LiteLLM` - Mode: `Reverse Proxy` - External host: `https://llm.kitestacks.com` - Internal host: `http://kite-litellm:4000` - **Applications → Create**: Name: `LiteLLM`, Slug: `litellm` - **Cloudflare Tunnel**: Add route `llm.kitestacks.com` → `http://authentik:9000` --- ## Step 2 — Forgejo: Add Authentik OAuth2 Source Forgejo stores OAuth sources in its database (not in app.ini), so this requires the Forgejo admin UI. 1. Go to **https://gitforge.kitestacks.com** → Site Administration → Authentication Sources 2. Click **Add Authentication Source** 3. Settings: - Authentication Type: `OAuth2` - Authentication Name: `authentik` - OAuth2 Provider: `OpenID Connect` - Client ID: `forgejo` - Client Secret: *(create an Authentik app first — see below)* - OpenID Connect Auto Discovery URL: `https://auth.kitestacks.com/application/o/forgejo/.well-known/openid-configuration` - Additional scopes: `email profile` 4. Save **Create the Authentik app for Forgejo first:** - Provider: OAuth2/OpenID, Client ID: `forgejo` - Redirect URI: `https://gitforge.kitestacks.com/user/oauth2/authentik/callback` - Application slug: `forgejo` --- ## Step 3 — Cloudflare Tunnel Updates In the Cloudflare Zero Trust Dashboard → Networks → Tunnels → your tunnel → Configure → Public Hostnames: | Hostname | Change From | Change To | |----------|------------|-----------| | `links.kitestacks.com` | `http://shaarli:80` | `http://authentik:9000` | | `status.kitestacks.com` | `http://uptime-kuma:3001` | `http://authentik:9000` | | `llm.kitestacks.com` | (new) | `http://authentik:9000` | | `tasks.kitestacks.com` | `http://openproject:8080` | `http://openproject:80` *(after OpenProject upgrade)* | --- ## Step 4 — Restart Containers After Config Changes After filling in all secrets in the `.env` files: ```bash cd ~/docker/grafana && docker compose up -d cd ~/docker/kite-ai && docker compose up -d cd ~/docker/bookstack && docker compose up -d cd ~/docker/openproject && docker compose up -d cd ~/docker/authentik && docker compose up -d docker restart kavita ``` --- ## Troubleshooting **OIDC redirect loop / 400 error** - Check that the Redirect URI in the Authentik provider exactly matches what the app sends. - Grafana: `https://grafana.kitestacks.com/login/generic_oauth` (no trailing slash) **Kavita "OIDC is not configured" message** - The `appsettings.json` change requires a container restart: `docker restart kavita` - Verify `Enabled: true` and `Secret` is not empty. **BookStack redirects to `http://192.168.1.205:6875`** - `APP_URL` must be updated to the real HTTPS domain and the container recreated. **OpenProject: OIDC provider not visible in login** - Env var format is version-specific. If env vars don't work in v15, configure via: Administration → Authentication → OpenID Connect Providers → Add **Proxy services (Shaarli/Uptime Kuma) show Authentik login but then 502** - Verify the Embedded Outpost has the proxy providers assigned. - Verify internal host is reachable: `docker exec authentik curl -v http://shaarli:80` --- ## Service-to-Container Name Reference | Subdomain | Container Name | Internal Port | |-----------|---------------|--------------| | auth.kitestacks.com | authentik | 9000 | | grafana.kitestacks.com | grafana | 3000 | | ai.kitestacks.com | kite-openwebui | 8080 | | gitforge.kitestacks.com | forgejo | 3000 | | tasks.kitestacks.com | openproject | 80 (after upgrade) | | kavita.kitestacks.com | kavita | 5000 | | links.kitestacks.com | shaarli | 80 | | status.kitestacks.com | uptime-kuma | 3001 | | llm.kitestacks.com | kite-litellm | 4000 | | www.kitestacks.com | homepage | 3000 | | portainer.kitestacks.com | portainer | 9000 (excluded) | | prometheus.kitestacks.com | prometheus | 9090 (excluded) | | node-exporter.kitestacks.com | node-exporter | 9100 (excluded) |