# OIDC Integration Guide - Complete Reference **Created:** 2026-01-20 21:27:00+00:00 **Purpose:** Step-by-step guide to add SSO to all deployed platforms **Prerequisites:** - ✅ Authentik admin account created - ✅ Pangolin admin account created - ✅ Guacamole password changed --- ## Step-by-Step Integration Process ### Phase 1: Create OIDC Providers in Authentik **Login to Authentik Admin:** https://sso.obr.sh/if/admin --- #### Provider 1: Pangolin Control Plane **Navigation:** Admin → Applications → Providers → Create **Configuration:** ``` Provider Type: OAuth2/OpenID Provider Name: Pangolin Control Plane Client Configuration: Client Type: Confidential Client ID: (auto-generated - COPY THIS) Client Secret: (click Show - COPY THIS) Redirect URIs: https://tunnel.obr.sh/api/v1/auth/callback Scopes: (select these) ✓ openid ✓ profile ✓ email ✓ groups Advanced Protocol Settings: Token validity: 720 minutes (12 hours) Signing Key: authentik Self-signed Certificate Subject mode: Based on User's hashed ID ``` **Click Create** **Then create Application:** ``` Name: Pangolin Provider: (select Pangolin Control Plane provider) ``` **Save Client ID and Secret for later:** ```bash # Save to file cat > /home/olaf/pangolin/pangolin-oidc-creds.env << 'EOF' PANGOLIN_OIDC_CLIENT_ID=paste_here PANGOLIN_OIDC_CLIENT_SECRET=paste_here EOF chmod 600 /home/olaf/pangolin/pangolin-oidc-creds.env ``` --- #### Provider 2: Guacamole RDP Gateway **Navigation:** Admin → Applications → Providers → Create **Configuration:** ``` Provider Type: OAuth2/OpenID Provider Name: Guacamole RDP Gateway Client Configuration: Client Type: Confidential Client ID: (auto-generated - COPY THIS) Client Secret: (click Show - COPY THIS) Redirect URIs: https://remote.obr.sh/guacamole/ Scopes: ✓ openid ✓ profile ✓ email Advanced Protocol Settings: Token validity: 300 minutes (5 hours - Guacamole maximum) Signing Key: authentik Self-signed Certificate ``` **Click Create** **Then create Application:** ``` Name: Guacamole Provider: (select Guacamole RDP Gateway provider) ``` **Optional: Create MFA Policy:** ``` Admin → Policies → Create Type: Expression Policy Name: Require TOTP for Guacamole Expression: return True # Require MFA for all Guacamole users Bindings: Go to Applications → Guacamole → Policy Bindings Add Binding → Select "Require TOTP for Guacamole" ``` **Save credentials:** ```bash cat > /home/olaf/pangolin/guacamole-oidc-creds.env << 'EOF' GUAC_OIDC_CLIENT_ID=paste_here GUAC_OIDC_CLIENT_SECRET=paste_here EOF chmod 600 /home/olaf/pangolin/guacamole-oidc-creds.env ``` --- #### Provider 3: Jellyfin Media Server **Configuration:** ``` Provider Type: OAuth2/OpenID Provider Name: Jellyfin Media Server Client Configuration: Client Type: Confidential Client Authentication: client_secret_post (CRITICAL!) Redirect URIs: https://video.obnh.io/sso/OID/redirect/Authentik Scopes: ✓ openid ✓ profile ✓ email ✓ groups ``` **Create Groups for Jellyfin:** ``` Admin → Directory → Groups → Create Name: jellyfin-admins Name: jellyfin-users ``` **Save credentials to file:** ```bash cat > /home/olaf/pangolin/jellyfin-oidc-creds.env << 'EOF' JELLYFIN_OIDC_CLIENT_ID=paste_here JELLYFIN_OIDC_CLIENT_SECRET=paste_here EOF ``` --- #### Provider 4: OpenWebUI **Configuration:** ``` Provider Type: OAuth2/OpenID Provider Name: OpenWebUI Redirect URIs: https://ll.obr.sh/oauth/oidc/callback Scopes: ✓ openid ✓ profile ✓ email ✓ groups ``` **Create Groups:** ``` Admin → Directory → Groups → Create Name: openwebui-admins Name: openwebui-users ``` **Save credentials:** ```bash cat > /home/olaf/pangolin/openwebui-oidc-creds.env << 'EOF' OPENWEBUI_OIDC_CLIENT_ID=paste_here OPENWEBUI_OIDC_CLIENT_SECRET=paste_here EOF ``` --- #### Provider 5: Gitea (fry.obr.sh) **Configuration:** ``` Provider Type: OAuth2/OpenID Provider Name: Gitea (fry) Redirect URIs: https://git.obnh.io/user/oauth2/authentik/callback Scopes: ✓ openid ✓ profile ✓ email ``` **Save credentials:** ```bash cat > /home/olaf/pangolin/gitea-fry-oidc-creds.env << 'EOF' GITEA_FRY_CLIENT_ID=paste_here GITEA_FRY_CLIENT_SECRET=paste_here EOF ``` --- #### Provider 6: Gitea (proton.obr.sh) **Configuration:** ``` Provider Type: OAuth2/OpenID Provider Name: Gitea (proton) Redirect URIs: https://git.proton.obr.sh/user/oauth2/authentik/callback Scopes: ✓ openid ✓ profile ✓ email ``` **Save credentials:** ```bash cat > /home/olaf/pangolin/gitea-proton-oidc-creds.env << 'EOF' GITEA_PROTON_CLIENT_ID=paste_here GITEA_PROTON_CLIENT_SECRET=paste_here EOF ``` --- ## Phase 2: Add OIDC to Deployed Platforms ### Pangolin OIDC Integration **After creating Provider 1 in Authentik:** **1. Login to Pangolin:** https://tunnel.obr.sh **2. Navigate to:** Settings → Identity Providers → Add Provider **3. Select:** Generic OAuth2/OIDC **4. Configure:** ``` Provider Name: Authentik SSO Provider Type: Generic OIDC Discovery URL: https://sso.obr.sh/application/o/pangolin/.well-known/openid-configuration Client ID: (from pangolin-oidc-creds.env) Client Secret: (from pangolin-oidc-creds.env) Scopes: openid profile email groups ``` **5. Save and Test:** - Logout of Pangolin - Click "Login with Authentik" - Should redirect to Authentik - Login with Authentik credentials - Should return to Pangolin dashboard --- ### Guacamole OIDC Integration **After creating Provider 2 in Authentik:** **1. Update docker-compose.yml:** Add these environment variables to the `guacamole` service: ```yaml environment: # Existing variables... GUACD_HOSTNAME: guacd POSTGRESQL_HOSTNAME: postgres # ... etc # Add OIDC configuration: OPENID_AUTHORIZATION_ENDPOINT: https://sso.obr.sh/application/o/authorize/ OPENID_JWKS_ENDPOINT: https://sso.obr.sh/application/o/guacamole/jwks/ OPENID_ISSUER: https://sso.obr.sh/application/o/guacamole/ OPENID_CLIENT_ID: ${GUAC_OIDC_CLIENT_ID} OPENID_REDIRECT_URI: https://remote.obr.sh/guacamole/ OPENID_USERNAME_CLAIM_TYPE: preferred_username OPENID_SCOPE: openid profile email EXTENSION_PRIORITY: openid ``` **2. Update .env file:** ```bash # Add to /srv/docker/guacamole/.env cat /home/olaf/pangolin/guacamole-oidc-creds.env >> /srv/docker/guacamole/.env ``` **3. Restart Guacamole:** ```bash cd /srv/docker/guacamole sudo docker compose up -d ``` **4. Test SSO Login:** - Go to https://remote.obr.sh/guacamole/ - Should see "Login with SSO" option - Click it - Should redirect to Authentik - Login with Authentik credentials - Should return to Guacamole dashboard --- ## Phase 3: Service SSO Integrations ### Jellyfin SSO Plugin **After creating Provider 3 in Authentik:** **1. Install SSO-Auth Plugin:** - Login to Jellyfin: https://video.obnh.io - Navigate to: Dashboard → Plugins → Catalog - Find "SSO-Auth" plugin - Click Install - Restart Jellyfin when prompted **2. Configure Plugin:** - Dashboard → Plugins → SSO-Auth → Settings ``` Provider: Generic OpenID Provider Name: Authentik OID Endpoint: https://sso.obr.sh/application/o/jellyfin/ Client ID: (from jellyfin-oidc-creds.env) Client Secret: (from jellyfin-oidc-creds.env) OID Client Authentication Method: client_secret_post Enable Authorization by Plugin Default: Yes Enable All Folders: Yes Admin Role: jellyfin-admins User Role: jellyfin-users Role Claim: groups ``` **3. Test:** - Logout of Jellyfin - Should see "Sign in with Authentik" button - Click it - Login with Authentik - Should return to Jellyfin **4. Mobile Apps:** - Use Quick Connect (6-digit code pairing) - OR generate API tokens in Jellyfin dashboard --- ### OpenWebUI OIDC Configuration **After creating Provider 4 in Authentik:** **1. Edit OpenWebUI docker-compose.yml:** Add environment variables: ```yaml environment: # Existing variables... # Add OIDC configuration: ENABLE_OAUTH_SIGNUP: "true" OAUTH_MERGE_ACCOUNTS_BY_EMAIL: "true" OAUTH_CLIENT_ID: ${OPENWEBUI_OIDC_CLIENT_ID} OAUTH_CLIENT_SECRET: ${OPENWEBUI_OIDC_CLIENT_SECRET} OPENID_PROVIDER_URL: https://sso.obr.sh/application/o/openwebui/.well-known/openid-configuration OAUTH_SCOPES: openid profile email groups # Role management: ENABLE_OAUTH_ROLE_MANAGEMENT: "true" OAUTH_ROLES_CLAIM: groups OAUTH_ADMIN_ROLES: openwebui-admins ``` **2. Update .env:** ```bash cat /home/olaf/pangolin/openwebui-oidc-creds.env >> /srv/docker/openwebui/.env ``` **3. Restart OpenWebUI:** ```bash cd /srv/docker/openwebui sudo docker compose restart ``` **4. Test:** - Go to https://ll.obr.sh - Click "Sign in with SSO" - Login with Authentik - Should have admin role if in openwebui-admins group --- ### Gitea OAuth2 Configuration (Both Instances) **After creating Providers 5 & 6 in Authentik:** **For Gitea on fry.obr.sh:** **1. SSH to fry:** ```bash ssh fry.obr.sh ``` **2. Login to Gitea admin:** - URL: https://git.obnh.io - Login as admin **3. Add Authentication Source:** - Navigate to: Site Administration → Authentication Sources → Add Source - Type: OAuth2 - Provider: OpenID Connect **Configuration:** ``` Name: Authentik SSO Provider: OpenID Connect Client ID: (from gitea-fry-oidc-creds.env) Client Secret: (from gitea-fry-oidc-creds.env) Auto Discovery URL: https://sso.obr.sh/application/o/gitea-fry/.well-known/openid-configuration Additional Scopes: groups Required Claim Name: (leave blank) Group Claim Name: groups Admin Group: gitea-admins Restricted Group: (leave blank) This Source is Activated: ✓ ``` **4. Test:** - Logout of Gitea - Should see "Sign in with Authentik SSO" - Click and login - Should create/login user account **Repeat for Gitea on proton.obr.sh** with gitea-proton credentials --- ## Phase 4: Configure Pangolin Sites **After Pangolin admin setup complete:** **Login to Pangolin Dashboard:** https://tunnel.obr.sh ### Create Site: brn-home **1. Navigate to:** Sites → Create Site **2. Configuration:** ``` Site Name: brn-home Description: Home LAN services (Jellyfin, OpenWebUI, Transmission, Pi-hole) Type: Newt Site ``` **3. Deploy Newt Client:** The dashboard will show a connection command like: ```bash docker run -d --name newt --cap-add NET_ADMIN \ -e SITE_TOKEN="" \ -e PANGOLIN_URL="https://tunnel.obr.sh" \ fosrl/newt:latest ``` **Run this on brn** to connect local services ### Create Resources for brn-home Site **After Newt connected:** **Resource 1: Jellyfin** ``` Type: Public Resource (HTTPS) Name: Jellyfin Media Server Public Domain: video.obnh.io Backend Address: jellyfin:8096 Protocol: HTTP Site: brn-home Access Control: Authenticated Users ``` **Resource 2: OpenWebUI** ``` Type: Public Resource (HTTPS) Name: OpenWebUI AI Chat Public Domain: ll.obr.sh Backend Address: openwebui:8080 Protocol: HTTP Site: brn-home Access Control: Authenticated Users ``` **Resource 3: Transmission** ``` Type: Public Resource (HTTPS) Name: Transmission Public Domain: tor.obnh.network Backend Address: transmission:9091 Protocol: HTTP Site: brn-home Access Control: Authenticated Users ``` **Resource 4: Pi-hole** ``` Type: Public Resource (HTTPS) Name: Pi-hole Admin Public Domain: dns.obnh.io Backend Address: host.docker.internal:8080 Protocol: HTTP Site: brn-home Access Control: Authenticated Users ``` --- ## Phase 5: Deploy Newt to VPS Hosts ### fry.obr.sh (Gitea) **SSH to fry:** ```bash ssh fry.obr.sh ``` **Create site in Pangolin dashboard:** ``` Site Name: fry-vps Description: Gitea hosting ``` **Get Newt connection command from Pangolin** **Run on fry:** ```bash docker run -d --name newt --restart unless-stopped \ --cap-add NET_ADMIN \ -e SITE_TOKEN="" \ -e PANGOLIN_URL="https://tunnel.obr.sh" \ fosrl/newt:latest ``` **Add Resource in Pangolin:** ``` Name: Gitea (fry) Domain: git.obnh.io Backend: gitea:3000 Site: fry-vps ``` **Repeat for proton.obr.sh and photon.obr.sh** --- ## Phase 6: Restrict Public WAN Access (Final Step) **ONLY after verifying all services work through Pangolin:** **Backup Traefik config:** ```bash sudo cp /srv/docker/traefik/traefik_dynamic.yaml \ /srv/docker/traefik/traefik_dynamic.yaml.backup-$(date +%Y%m%d) ``` **Edit traefik_dynamic.yaml:** **Remove or comment out public routes for:** - video.obnh.io (Jellyfin) - ll.obr.sh (OpenWebUI) - tor.obnh.network (Transmission) **Keep public routes for:** - sso.obr.sh (Authentik - must be public for auth) - tunnel.obr.sh (Pangolin - must be public for tunnels) - remote.obr.sh (Guacamole - accessible via Pangolin) - bern.social (Mastodon - public federated) - git.obnh.io, git.proton.obr.sh (Gitea - public with SSO) - dns.obnh.io (Pi-hole - for VPS DNS queries) **Reload Traefik:** ```bash sudo docker exec traefik kill -SIGHUP 1 # Or: docker compose restart (brief downtime) ``` **Test:** - From internet: Jellyfin/OpenWebUI should be unreachable - From Pangolin tunnel: Should work normally --- ## Automated Integration Scripts ### Script 1: Add OIDC to Pangolin **File:** `/home/olaf/pangolin/scripts/integrate-pangolin-oidc.sh` ```bash #!/bin/bash # Read credentials source /home/olaf/pangolin/pangolin-oidc-creds.env # Update Pangolin config.yml cat >> /srv/docker/pangolin/config/config.yml << EOF # OIDC Integration added: $(date -Iseconds) identity_providers: - type: oidc name: Authentik SSO discovery_url: https://sso.obr.sh/application/o/pangolin/.well-known/openid-configuration client_id: ${PANGOLIN_OIDC_CLIENT_ID} client_secret: ${PANGOLIN_OIDC_CLIENT_SECRET} scopes: - openid - profile - email - groups EOF # Restart Pangolin cd /srv/docker/pangolin sudo docker compose restart pangolin echo "✅ Pangolin OIDC integration added" echo "Test at: https://tunnel.obr.sh" ``` ### Script 2: Add OIDC to Guacamole **File:** `/home/olaf/pangolin/scripts/integrate-guacamole-oidc.sh` ```bash #!/bin/bash # Read credentials source /home/olaf/pangolin/guacamole-oidc-creds.env # Add to environment file cat >> /srv/docker/guacamole/.env << EOF # OIDC Integration added: $(date -Iseconds) GUAC_OIDC_CLIENT_ID=${GUAC_OIDC_CLIENT_ID} EOF # Update docker-compose.yml (manual edit needed) echo "⚠️ Manual step required:" echo "Edit /srv/docker/guacamole/docker-compose.yml" echo "Add OPENID_ environment variables" echo "See: /home/olaf/pangolin/ADD-OIDC-INTEGRATIONS.md Phase 2" echo "Then run:" echo "cd /srv/docker/guacamole && sudo docker compose up -d" ``` --- ## Verification Checklist **After completing all integrations:** - [ ] Pangolin SSO login works - [ ] Guacamole SSO login works (MFA if configured) - [ ] Jellyfin web SSO works - [ ] Jellyfin mobile Quick Connect works - [ ] OpenWebUI SSO works with admin role - [ ] Gitea fry SSO works - [ ] Gitea proton SSO works - [ ] Services unreachable from public WAN (if restricted) - [ ] Services accessible via Pangolin tunnel - [ ] LAN access still works for all services - [ ] WAN internet routing still works --- ## Troubleshooting ### OIDC Login Fails **Check:** - Redirect URI matches exactly in Authentik provider - Client ID and Secret are correct - Discovery URL is accessible: `curl https://sso.obr.sh/application/o//.well-known/openid-configuration` - Scopes include at minimum: openid, profile, email ### Services Not Accessible **Through Pangolin:** - Check Newt client connected in Pangolin dashboard - Verify resource backend address correct - Check site is online **From LAN:** - Should still work (direct access) - Check Traefik dynamic config not removed ### Mobile Apps **Jellyfin:** - Use Quick Connect (web login + 6-digit code) - OR API tokens (Settings → API Keys) **Pangolin:** - Install Pangolin mobile app - Connect to tunnel.obr.sh - Login with Authentik credentials --- ## Summary **This guide provides:** - Complete OIDC provider creation steps (6 providers) - Platform integration configurations (Pangolin, Guacamole) - Service integration steps (Jellyfin, OpenWebUI, Gitea) - Pangolin site/resource configuration - Newt client deployment - Traefik restriction procedure - Verification checklist - Troubleshooting guidance **Use this after completing platform setup wizards.** --- **File:** `/home/olaf/pangolin/ADD-OIDC-INTEGRATIONS.md` **Ready for:** After admin accounts created on all platforms