Files
pangolin/ADD-OIDC-INTEGRATIONS.md
Olaf b428721b07 Initial commit: cleaned project structure
- Consolidated documentation from Ralph Loop iterations
- Archived 20+ outdated/superseded files to .archive/
- Kept essential docs: OIDC integration, mobile setup, quick start
- Added operational scripts for health monitoring and backup
- Research artifacts preserved in .tasks/artifacts/

Current state:
- 3 VPS sites (fry, proton, photon) ONLINE in Pangolin
- brn-home site pending for local services (Jellyfin, etc.)
- Mobile access configuration pending

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-21 06:15:04 +00:00

16 KiB

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:

# 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:

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:

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:

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:

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:

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:

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:

# Add to /srv/docker/guacamole/.env
cat /home/olaf/pangolin/guacamole-oidc-creds.env >> /srv/docker/guacamole/.env

3. Restart Guacamole:

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:

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:

cat /home/olaf/pangolin/openwebui-oidc-creds.env >> /srv/docker/openwebui/.env

3. Restart OpenWebUI:

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:

ssh fry.obr.sh

2. Login to Gitea 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:

docker run -d --name newt --cap-add NET_ADMIN \
  -e SITE_TOKEN="<generated_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:

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:

docker run -d --name newt --restart unless-stopped \
  --cap-add NET_ADMIN \
  -e SITE_TOKEN="<from_pangolin>" \
  -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:

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:

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

#!/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

#!/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/<app>/.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