Files
homelab-optimized/docs/infrastructure/authentik-sso.md
Gitea Mirror Bot 89aad4f882
Some checks failed
Documentation / Build Docusaurus (push) Failing after 5m2s
Documentation / Deploy to GitHub Pages (push) Has been skipped
Sanitized mirror from private repository - 2026-04-18 11:13:17 UTC
2026-04-18 11:13:18 +00:00

408 lines
17 KiB
Markdown

# Authentik SSO Setup
Single Sign-On (SSO) for homelab services using Authentik.
## Overview
Authentik provides centralized authentication for all homelab services via OAuth2/OpenID Connect.
- **URL**: https://sso.vish.gg
- **Admin Interface**: https://sso.vish.gg/if/admin/
- **User Portal**: https://sso.vish.gg/if/user/
- **Host**: Calypso NAS (Synology DS723+)
- **Stack**: Docker Compose via Portainer
## Admin Credentials
- **Username**: `akadmin`
- **Email**: `admin@example.com`
- **Password**: REDACTED_PASSWORD in password manager
## Architecture
```
┌──────────────────┐
│ Cloudflare │
│ (DNS + SSL) │
└────────┬─────────┘
┌────────▼─────────┐
│ sso.vish.gg │
│ (Authentik) │
│ Calypso NAS │
└────────┬─────────┘
┌────────────────────┼────────────────────┐
│ │ │
▼ ▼ ▼
┌─────────┐ ┌─────────┐ ┌──────────┐
│ Grafana │ │ Gitea │ │Portainer │
│gf.vish.gg│ │git.vish.gg│ │ internal │
│homelab-vm│ │ Calypso │ │ Calypso │
└─────────┘ └─────────┘ └──────────┘
```
## OAuth2 Providers
### Grafana
| Setting | Value |
|---------|-------|
| Client ID | `lEGw1UJ9Mhk6QVrNA61rAsr59Kel9gAvdPQ1FAJA` |
| Client Secret | `ArP5XWdkwVyw9nvXZaqjE9sIjXdmIgpgI4ZR8oKvTUVLgmIGVvKU8T867diMGSQXgTcWQQPbdbEdXTU1v3y9RKMnAqu2k6V4xlmxwNYlCDuk5inxJSdoC0V8ICtZxk1X` |
| Redirect URI | `https://gf.vish.gg` |
| Scopes | `openid profile email` |
**Configuration File**: `hosts/vms/homelab-vm/monitoring.yaml`
### Gitea
| Setting | Value |
|---------|-------|
| Client ID | `7KamS51a0H7V8HyIsfMKNJ8COstZEFh4Z8Em6ZhO` |
| Client Secret | `3IjyKCbHtgev6eMb1hYpQGHoGwPSRKda4ijRtbWfkhguNomxexxTiWtoWtyrXwGaF0ORj4D7D0kzB3Z1YN9DN5iz0HOKjAn5AdWJrSyxan02MjiwKmEriAbSGyh53uph` |
| Redirect URI | `https://git.vish.gg/user/oauth2/authentik/callback` |
| Discovery URL | `https://sso.vish.gg/application/o/gitea/.well-known/openid-configuration` |
**Configuration File**: `hosts/synology/calypso/gitea-server.yaml`
**Manual Setup Required**: Add OAuth2 source in Gitea admin UI:
1. Go to Site Administration → Authentication Sources
2. Add new OAuth2 source
3. Use Discovery URL for auto-configuration
### Portainer
| Setting | Value |
|---------|-------|
| Client ID | `fLLnVh8iUyJYdw5HKdt1Q7LHKJLLB8tLZwxmVhNs` |
| Client Secret | `xD9u47XbJd2g7vCeIyJC7MNvfEqytEnnHeVtJ7nU5Y1XGxYncXkejNAYkToUiRWcym3GpZIXgMpUnNNuUwud0Ff493ZwSHCiSKsk9n6RJLJ1iVvR20NdDnMe4YEGYXrt` |
| Redirect URI | `http://vishinator.synology.me:10000` |
| User Identifier | `email` |
**Configuration**: Via Portainer API (`/api/settings`)
### Reactive Resume v5
| Setting | Value |
|---------|-------|
| Client ID | `QU5qA7jLP9ghxy7iGMJoyZsCja2vY2Y2oGaLGjxA` |
| Client Secret | `wX1aFaby4aIABjLBBClYu4ukmIOjviL85GJBX8bAB3srQnt1BD31LcblRKyxzuv1yGwtsKLTFjwz12rUy6HknOqpIwk1QQ21jMjpWb1aa77iRG6lDkf4eNf8wWpE9Apo` |
| Redirect URI | `https://rx.vish.gg/api/auth/callback/custom` |
| Discovery URL | `https://sso.vish.gg/application/o/reactive-resume/.well-known/openid-configuration` |
**Configuration File**: `hosts/synology/calypso/reactive_resume_v5/docker-compose.yml` (also live at `/volume1/docker/rxv5/docker-compose.yml` on Calypso)
### Homarr
| Setting | Value |
|---------|-------|
| Client ID | `8oP0ha7gLjdz13MAPVsb7fe7TBkFBz7mt1eU8MEO` |
| Client Secret | `SpJXIGDk3SJfiS9GJwzH0fKrePsrumvCOmvFd2h0hEfxXMO77aCtpPEs6FShLTaUW5YxqgEDFkQi7q9NIOQDJTPQHlSy3nIeyDQmS2tVIV1BpSdGpnLQedouOkXACwe2` |
| Redirect URI | `https://dash.vish.gg/api/auth/callback/oidc` |
| Admin Group | `Homarr Admins` (Authentik group, pk=`892da833-5283-4672-a906-7448ae3ba9b6`) |
| Discovery URL | `https://sso.vish.gg/application/o/homarr/.well-known/openid-configuration` |
**Configuration File**: `hosts/synology/atlantis/homarr.yaml`
**Note**: `SECRET_ENCRYPTION_KEY` is required by Homarr — a 64-char hex key must be provided as an env var. The `AUTH_OIDC_ADMIN_GROUP` and `AUTH_OIDC_OWNER_GROUP` map to an Authentik group name.
### Immich
| Setting | Value |
|---------|-------|
| Client ID | `XSHhp1Hys1ZyRpbpGUv4iqu1y1kJXX7WIIFETqcL` |
| Client Secret | `mlbc4NbqiyRyUSqeUupaob7WsA3sURWExmoxYAcozClnmsdCPzGHlyO6zmErnS9YNyBsKOYoGUPvSTQPrE07UnYDLSMy286fycHoAJoc0cAN8BMc5cIif5kf88NSNCj2` |
| Redirect URIs | `http://192.168.0.250:8212/auth/login`, `http://calypso.vish.local:8212/auth/login`, `app.immich:/` |
| Issuer URL | `https://sso.vish.gg/application/o/immich/` |
| Button Text | `Sign in with Authentik` |
| Auto Register | true |
**Configuration**: Via `immich-config.json` mounted at `/config/immich-config.json` inside the container. Config file lives at `/volume1/docker/immich/config/immich-config.json` on Calypso and is tracked at `/home/homelab/immich-config.json`.
**Note**: Immich constructs the redirect URI dynamically from the hostname the browser used to access it — so every access hostname must be registered in Authentik. Currently registered: IP, `calypso.vish.local`, `app.immich:/`. `mobileRedirectUri` in the config file must be empty string — Immich's validator rejects custom URI schemes there.
### Headplane
| Setting | Value |
|---------|-------|
| Provider PK | `16` |
| Client ID | `1xLx9TkufvLGKgq8UmQV2RfTB6raSpEjZExBOhJ4` |
| Client Secret | `4r4n96jBGc8MlonyHStiN09ow0txTwERLupt9hsoNswpicEnJZHgKwi38jYP5zlou5J525dVFUmXNSvnxwBJgKIIAfpC43zi8yUVtT0NYNdEBeYQOsh1YW5jK8nVPSdc` |
| Redirect URI | `https://headscale.vish.gg:8443/admin/oidc/callback` |
| Issuer URL | `https://sso.vish.gg/application/o/headplane/` |
| Scopes | `openid profile email` |
| Sub Mode | `hashed_user_id` |
**Configuration File**: `hosts/synology/calypso/headplane-config.yaml` (reference, secrets redacted). Live config at `/volume1/docker/headscale/headplane/config.yaml` on Calypso.
**Note**: Headplane is served at `https://headscale.vish.gg:8443/admin` — no separate domain. NPM proxy host 44 routes `/admin` to port 3002. First user to log in via OIDC is automatically assigned the Owner role.
### NetBox
| Setting | Value |
|---------|-------|
| Provider PK | `23` |
| Client ID | `BB7PiOu8xFOl58H2MUfl9IHISVLuJ4UwwMGvmJ9N` |
| Client Secret | `CRdRVCM13JN9bSiT2aU74cFXSI9GpVBLBShOFGBpVHOQ4brnDWOzk8I02cEww8Gcrr6GnsU0XdBxHTEpfvX2u9rhmey7XDT3XUVVh9ADaSldww83hp4hAzH5eNx1zKvB` |
| Redirect URI | `https://nb.vish.gg/oauth/complete/oidc/` |
| Discovery URL | `https://sso.vish.gg/application/o/netbox/.well-known/openid-configuration` |
| Scopes | `openid profile email` |
**Configuration**: NetBox `configuration.py` on homelab-vm (`/home/homelab/docker/netbox/config/configuration.py`). Uses `python-social-auth` with `social_core.backends.open_id_connect.OpenIdConnectAuth` backend. `associate_by_email` pipeline maps Authentik users to existing NetBox accounts by email.
## Authentik Endpoints
| Endpoint | URL |
|----------|-----|
| Authorization | `https://sso.vish.gg/application/o/authorize/` |
| Token | `https://sso.vish.gg/application/o/token/` |
| User Info | `https://sso.vish.gg/application/o/userinfo/` |
| JWKS | `https://sso.vish.gg/application/o/{app-slug}/jwks/` |
| OpenID Config | `https://sso.vish.gg/application/o/{app-slug}/.well-known/openid-configuration` |
| End Session | `https://sso.vish.gg/application/o/{app-slug}/end-session/` |
## Docker Compose Configuration
**Location**: `hosts/synology/calypso/authentik.yaml`
Key environment variables:
- `AUTHENTIK_SECRET_KEY`: Random secret for encryption
- `AUTHENTIK_REDIS__HOST`: Redis container hostname
- `AUTHENTIK_POSTGRESQL__*`: PostgreSQL connection settings
## SSL/TLS Configuration
SSL is handled by Cloudflare Origin Certificate:
- Certificate ID: `lONWNn` (Synology reverse proxy)
- Covers: `*.vish.gg`
- Origin: Cloudflare Full (Strict) mode
## DNS Configuration
| Domain | Type | Target | Proxy |
|--------|------|--------|-------|
| sso.vish.gg | CNAME | calypso DDNS | Orange (proxied) |
## Adding New Services
### Method 1: OAuth2/OpenID (for apps that support it)
1. **Create Provider in Authentik**
- Admin → Providers → Create → OAuth2/OpenID
- Set name, redirect URIs, scopes
2. **Create Application**
- Admin → Applications → Create
- Link to provider
- Set launch URL
3. **Configure Service**
- Add OAuth2/OIDC settings to service config
- Use Authentik endpoints
- Test login flow
### Method 2: Proxy Provider (for apps without OAuth support)
Use this for apps like Actual Budget, Paperless-NGX, etc.
1. **Create Proxy Provider in Authentik**
- Admin → Providers → Create → Proxy Provider
- Name: e.g., "actual-proxy"
- Authorization flow: default-provider-authorization-implicit-consent
- External host: `https://actual.vish.gg`
- Mode: Forward auth (single application)
2. **Create Application**
- Admin → Applications → Create
- Name: e.g., "Actual Budget"
- Slug: `actual`
- Provider: Select the proxy provider
- Launch URL: `https://actual.vish.gg`
3. **Create Outpost** (if not exists)
- Admin → Applications → Outposts
- Create embedded outpost or deploy standalone
- Add the application to the outpost
4. **Configure Nginx/Reverse Proxy**
Add forward auth to your reverse proxy config:
```nginx
location / {
# Forward auth to Authentik
auth_request /outpost.goauthentik.io/auth/nginx;
error_page 401 = @goauthentik_proxy_signin;
auth_request_set $auth_cookie $upstream_http_set_cookie;
add_header Set-Cookie $auth_cookie;
auth_request_set $authentik_username $upstream_http_x_authentik_username;
auth_request_set $authentik_groups $upstream_http_x_authentik_groups;
auth_request_set $authentik_email $upstream_http_x_authentik_email;
proxy_set_header X-authentik-username $authentik_username;
proxy_set_header X-authentik-groups $authentik_groups;
proxy_set_header X-authentik-email $authentik_email;
# Your existing proxy_pass
proxy_pass http://localhost:PORT;
}
location /outpost.goauthentik.io {
proxy_pass https://sso.vish.gg/outpost.goauthentik.io;
proxy_set_header Host $host;
proxy_set_header X-Original-URL $scheme://$http_host$request_uri;
}
location @goauthentik_proxy_signin {
internal;
add_header Set-Cookie $auth_cookie;
return 302 /outpost.goauthentik.io/start?rd=$request_uri;
}
```
### Bypassing Auth for Share Links
For services like Seafile that have share links:
```nginx
# Allow share links without auth
location /f/ {
proxy_pass http://localhost:8611;
}
location /d/ {
proxy_pass http://localhost:8611;
}
# Everything else requires auth
location / {
auth_request /outpost.goauthentik.io/auth/nginx;
# ... rest of auth config
proxy_pass http://localhost:8611;
}
```
## Services Protection Summary
### OAuth2/OpenID Connect (Login Button)
Services with native OAuth support - users see a "Sign in with Authentik" button.
| Domain | Service | Backend | Port | Status |
|--------|---------|---------|------|--------|
| gf.vish.gg | Grafana | 192.168.0.210 | 3300 | ✅ Working |
| git.vish.gg | Gitea | 192.168.0.250 | 3052 | ✅ Working |
| sf.vish.gg | Seafile | 192.168.0.250 | 8611 | ✅ Working |
| vishinator.synology.me:10000 | Portainer | 192.168.0.250 | 9000 | ✅ Working |
| rx.vish.gg | Reactive Resume v5 | 192.168.0.250 | 4550 | ✅ Working |
| dash.vish.gg | Homarr | 192.168.0.200 | 7575 | ✅ Working |
| immich.vish.gg | Immich | 192.168.0.250 | 8212 | ✅ Working |
| headscale.vish.gg/admin | Headplane | 192.168.0.250 | 3002 | ✅ Working |
| nb.vish.gg | NetBox | 192.168.0.210 | 8443 | ✅ Working |
### Proxy Provider (Forward Auth)
Services without OAuth support - Authentik intercepts all requests and requires login first.
| Domain | Service | Backend | Port | Status |
|--------|---------|---------|------|--------|
| paperless.vish.gg | Paperless-NGX | 192.168.0.250 | 8777 | ✅ Working |
| docs.vish.gg | Paperless-NGX | 192.168.0.250 | 8777 | ✅ Working |
| actual.vish.gg | Actual Budget | 192.168.0.250 | 8304 | ✅ Working |
| npm.vish.gg | NPM Admin | 192.168.0.250 | 81 | ✅ Working |
| kuma.vish.gg | Uptime Kuma | 192.168.0.66 | 3001 | ✅ Working — `/status/*` public, rest gated |
| ollama.vish.gg | Ollama | 192.168.0.200 | 11434 | ✅ Working |
| wizarr.vish.gg | Wizarr | 192.168.0.200 | 5690 | ❌ Removed — caused redirect loop; Wizarr uses own auth |
### Services Without SSO
These services use their own authentication or are public.
| Domain | Service | Backend | Notes |
|--------|---------|---------|-------|
| sso.vish.gg | Authentik | 192.168.0.250:9000 | SSO itself |
| pw.vish.gg | Vaultwarden | 192.168.0.200:4080 | Own auth |
| ntfy.vish.gg | Ntfy | 192.168.0.210:8081 | Own auth |
| cal.vish.gg | Baikal | 192.168.0.200:12852 | CalDAV auth |
| dav.vish.gg | Seafile WebDAV | 192.168.0.250:8612 | WebDAV auth |
| mm.crista.love | Mattermost | 192.168.0.154:8065 | Own auth |
| mastodon.vish.gg | Mastodon | 192.168.0.154:3000 | Own auth |
| mx.vish.gg | Mail | 192.168.0.154:8082 | Own auth |
| ollama.vish.gg | Ollama | 192.168.0.200:11434 | See Forward Auth table above |
| retro.vish.gg | Retro Site | 192.168.0.250:8025 | Static site |
| rackula.vish.gg | Rackula | 192.168.0.250:3891 | Own auth |
| ost.vish.gg | OpenSpeedTest | 192.168.0.250:8004 | Public |
### Other Domains
| Domain | Service | Backend | Notes |
|--------|---------|---------|-------|
| hoarder.thevish.io | Hoarder | 192.168.0.210:3000 | Own auth |
| matrix.thevish.io | Matrix | 192.168.0.154:8081 | Own auth |
| joplin.thevish.io | Joplin Server | 192.168.0.200:22300 | Own auth |
| meet.thevish.io | Jitsi | 192.168.0.200:5443 | Public |
| binterest.thevish.io | Binternet | 192.168.0.210:21544 | Own auth |
| crista.love | Personal Site | 192.168.0.100:28888 | Static |
| rxv4access.vish.gg | Reactive Resume v4 | 192.168.0.250:9751 | STALE - 525 SSL error, dead instance |
## Troubleshooting
### OAuth Login Fails with "Unauthorized"
- Verify user has email set in Authentik
- Check redirect URI matches exactly
- Verify client secret is correct
### Certificate Errors
- Ensure Cloudflare proxy is enabled (orange cloud)
- Verify origin certificate is valid
- Check Synology reverse proxy SSL settings
### User Auto-Creation Not Working
- Enable "Auto Create Users" in service OAuth settings
- Verify email scope is requested
- Check user identifier matches (email/username)
## Recovery Access
If locked out of Authentik admin, you can create a recovery token:
```bash
# Via Portainer exec or SSH to Calypso
docker exec -it Authentik-SERVER ak create_recovery_key 10 akadmin
```
This generates a one-time recovery URL valid for 10 minutes.
## Related Documentation
- [Cloudflare Tunnels](./cloudflare-tunnels.md)
- [Port Forwarding Configuration](./port-forwarding-configuration.md)
- [Security](./security.md)
- [Grafana OAuth](../services/individual/grafana-oauth.md)
- [Gitea OAuth](../services/individual/gitea.md#-oauth2-single-sign-on-authentik)
- [Seafile OAuth](../services/individual/seafile-oauth.md)
## Change Log
- **2026-03-17**: Added NetBox OIDC provider (pk=23) — nb.vish.gg, associate_by_email pipeline
- **2026-03-17**: Removed Wizarr forward auth from NPM (wizarr has own auth, forward auth caused redirect loop)
- **2026-03-11**: Added Headplane OIDC provider (pk=16) — Headscale web UI at headscale.vish.gg/admin, port 3002
- **2026-03-08**: Added Forward Auth for Uptime Kuma (kuma.vish.gg), Ollama (ollama.vish.gg), Wizarr (wizarr.vish.gg)
- **2026-03-08**: Kuma /status/* and Wizarr /i/* paths are public; all other paths gated
- **2026-03-08**: Removed Forward Auth from dash.vish.gg NPM proxy (Homarr handles auth natively via OIDC)
- **2026-03-08**: Disabled Uptime Kuma built-in auth (disableAuth=true in SQLite); Authentik is sole gate
- **2026-03-08**: Calibre-Web started on port 8183 (8083 was occupied by Watchtower)
- **2026-03-08**: Added OIDC for Reactive Resume v5 (rx.vish.gg), Homarr (dash.vish.gg), Immich (immich.vish.gg) — all working
- **2026-03-08**: Fixed Homarr startup crash — SECRET_ENCRYPTION_KEY is mandatory (64-char hex)
- **2026-03-08**: Immich OAuth configured via immich-config.json mount (not Admin UI); mobileRedirectUri must be empty
- **2026-03-08**: Immich stack.env added to repo so stack is self-contained (no Portainer env injection needed)
- **2026-03-08**: Flagged rxv4access.vish.gg as stale (dead RR v4 instance, 525 SSL error)
- **2026-01-31**: Verified all OAuth2 and Forward Auth services working
- **2026-01-31**: Fixed Grafana OAuth "InternalError" - added scope mappings to provider
- **2026-01-31**: Removed Forward Auth from NPM for gf.vish.gg (conflicts with native OAuth)
- **2026-01-31**: Added scope mappings to Gitea, Portainer, Seafile OAuth2 providers
- **2026-01-31**: Updated comprehensive service protection summary