kitestacks-homelab/docs/authentik-sso-setup.md
KiteStacks AutoSync 4b8925ca7e security: complete IP, port, and password redaction across all docs
Redact all remaining IPv4 addresses, port numbers, and credential values
from RUNBOOK.md, AUTHENTIK.md, and authentik-sso-setup.md. Replace with
descriptive placeholders (<IP_REDACTED>, <port>, <REDACTED>, etc.).
Docker image version tags (postgres:16, forgejo:11, etc.) preserved.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-11 16:16:23 -05:00

11 KiB

KiteStacks Authentik SSO Setup

Established: 2026-06-08
Author: kenpat
Status: In Progress — all providers/apps configured, Cloudflare tunnel updates 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:<port>) 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 (is the IdP) Running
Grafana grafana.kitestacks.com OAuth2 Configured
Kite AI (OpenWebUI) ai.kitestacks.com OIDC Configured
Forgejo gitforge.kitestacks.com OAuth2 Configured
BookStack 🚫 Retired — books hosted on Kavita
OpenProject tasks.kitestacks.com OIDC Configured, upgraded v13→v15
Kavita kavita.kitestacks.com OIDC Configured, secret filled
Shaarli links.kitestacks.com Proxy ⚠️ Provider configured, CF tunnel update pending
Uptime Kuma status.kitestacks.com Proxy ⚠️ Provider configured, CF tunnel update pending
LiteLLM llm.kitestacks.com Proxy ⚠️ Provider configured, CF tunnel update pending
Portainer portainer.kitestacks.com 🚫 SSO excluded
Prometheus prometheus.kitestacks.com 🚫 SSO excluded
Node Exporter node-exporter.kitestacks.com 🚫 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.Enabledtrue, 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=<paste_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=<paste_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:
    "Secret": "<paste_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=<paste_secret>
    
  • Restart: cd ~/docker/openproject && docker compose up -d
    • Note: Container is currently running openproject/community:<port> but compose specifies openproject/openproject:<port>. Recreation will upgrade it. Verify data migration after restart. The Cloudflare tunnel for tasks.kitestacks.com may need updating from openproject:<port>openproject:<port> 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:<port>
    • Internal host SSL validation: off
  • Applications → Create: Name: Shaarli, Slug: shaarli
  • Cloudflare Tunnel: Change links.kitestacks.com route from http://shaarli:<port>http://authentik:<port>

7. Uptime Kuma

  • Providers → Create → Proxy Provider
    • Name: Uptime Kuma
    • Mode: Reverse Proxy
    • External host: https://status.kitestacks.com
    • Internal host: http://uptime-kuma:<port>
  • Applications → Create: Name: Uptime Kuma, Slug: uptime-kuma
  • Cloudflare Tunnel: Change status.kitestacks.com route from http://uptime-kuma:<port>http://authentik:<port>

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:<port>
  • Applications → Create: Name: LiteLLM, Slug: litellm
  • Cloudflare Tunnel: Add route llm.kitestacks.comhttp://authentik:<port>

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:<port> http://authentik:<port>
status.kitestacks.com http://uptime-kuma:<port> http://authentik:<port>
llm.kitestacks.com (new) http://authentik:<port>
tasks.kitestacks.com http://openproject:<port> http://openproject:<port> (after OpenProject upgrade)

Step 4 — Restart Containers After Config Changes

After filling in all secrets in the .env files:

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://<MONK_LAN_IP>:<port>

  • 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:<port>

Service-to-Container Name Reference

Subdomain Container Name Internal Port
auth.kitestacks.com authentik
grafana.kitestacks.com grafana
ai.kitestacks.com kite-openwebui
gitforge.kitestacks.com forgejo
tasks.kitestacks.com openproject (after upgrade)
kavita.kitestacks.com kavita
links.kitestacks.com shaarli
status.kitestacks.com uptime-kuma
llm.kitestacks.com kite-litellm
www.kitestacks.com homepage
portainer.kitestacks.com portainer (excluded)
prometheus.kitestacks.com prometheus (excluded)
node-exporter.kitestacks.com node-exporter (excluded)