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>
This commit is contained in:
2026-01-21 06:15:04 +00:00
commit b428721b07
17 changed files with 5749 additions and 0 deletions

View File

@@ -0,0 +1,619 @@
# Jellyfin SSO-Auth Plugin Configuration for Authentik OIDC
**Research Date:** 2026-01-20
**Plugin:** jellyfin-plugin-sso by 9p4
**Target IDP:** Authentik OIDC
**Documentation Version:** Based on plugin v3.5+ and Jellyfin 10.9+
---
## Executive Summary
The Jellyfin SSO-Auth plugin enables OpenID Connect (OIDC) authentication with Authentik, allowing users to authenticate via SSO. This document covers installation, claim mapping configuration, and critical mobile app authentication workflows.
**Key Findings:**
- Plugin supports OIDC providers including Authentik, Authelia, Keycloak, and others
- Claim mapping is essential for role-based authorization
- Mobile apps have SSO limitations requiring alternative authentication methods
- Quick Connect and API tokens are recommended for mobile app access
---
## 1. Plugin Installation Process
### 1.1 Installation via Web GUI
1. **Access Jellyfin Administration Dashboard**
- Navigate to your Jellyfin instance (e.g., `https://jellyfin.example.com`)
- Log in with administrator credentials
- Go to **Dashboard****Plugins**
2. **Add Plugin Repository**
- Click on the **Repositories** tab
- Click the **+** button to add a new repository
- Enter the following details:
- **Repository Name:** `Jellyfin SSO`
- **Repository URL:** `https://raw.githubusercontent.com/9p4/jellyfin-plugin-sso/manifest-release/manifest.json`
- Click **Save**
- Confirm the repository installation
3. **Install SSO-Auth Plugin**
- Go to the **Catalog** tab
- Find **SSO Authentication** in the **Authentication** section
- Click **Install**
- Confirm the plugin installation
- **Restart Jellyfin** for the plugin to activate
### 1.2 Configuration File Location
After installation, the plugin configuration is stored at:
```
/config/data/plugins/configurations/SSO-Auth.xml
```
---
## 2. Authentik OIDC Provider Configuration
### 2.1 Authentik Setup
In Authentik, create an OIDC provider with the following settings:
**Provider Settings:**
- **Name:** `Jellyfin`
- **Client Type:** `Confidential`
- **Client ID:** `jellyfin` (or custom value)
- **Client Secret:** Generate secure secret
- **Redirect URIs:**
```
https://jellyfin.example.com/sso/OID/redirect/authentik
```
- **Token Endpoint Auth Method:** `client_secret_post` (CRITICAL for compatibility)
- **Scopes:** `openid`, `profile`, `email`, `groups`
**Important Note:** The plugin uses `client_secret_post` authentication method. Ensure Authentik is configured to accept this method. Mismatch causes authentication failures:
```
Client authentication failed... The registered client with id 'jellyfin' is configured
to only support 'token_endpoint_auth_method' method 'client_secret_basic'.
```
### 2.2 Authentik Group Configuration
Create groups for role-based access:
- **jellyfin-admins** - Administrative access
- **jellyfin-users** - Standard user access
Assign users to appropriate groups in Authentik.
### 2.3 Authentik Scope and Property Mappings
Ensure the following claim mappings are configured:
- **preferred_username** - Username claim
- **email** - Email address
- **groups** - User group memberships (CRITICAL for role authorization)
---
## 3. Jellyfin SSO Plugin Configuration
### 3.1 Configuration via Web GUI
1. **Navigate to Plugin Settings**
- Dashboard → **Plugins** → **SSO-Auth**
2. **Add OIDC Provider**
- Click **Add Provider**
- Configure the following settings:
**Basic Configuration:**
```
Name of OID Provider: authentik
OID Endpoint: https://auth.example.com
OpenID Client ID: jellyfin
OID Secret: <your-secure-secret>
```
**Authorization Settings:**
```
Enabled: ☑ (checked)
Enable Authorization by Plugin: ☑ (checked)
Enable All Folders: ☑ (checked)
```
**Role Mapping:**
```
Roles: jellyfin-users, jellyfin-admins
Admin Roles: jellyfin-admins
Role Claim: groups
```
**Advanced Settings:**
```
Request Additional Scopes: groups
Default Username Claim: preferred_username
New Path (recommended): ☑ (checked)
Disable HTTPS: ☐ (unchecked)
Do Not Validate Endpoints: ☐ (unchecked)
Do Not Validate Issuer Name: ☐ (unchecked)
```
3. **Save Configuration**
- Click **Save**
- The plugin is now active
### 3.2 Configuration via XML File
Alternatively, configure via the XML file at `/config/data/plugins/configurations/SSO-Auth.xml`:
```xml
<?xml version="1.0" encoding="utf-8"?>
<PluginConfiguration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<SamlConfigs />
<OidConfigs>
<item>
<key>
<string>authentik</string>
</key>
<value>
<PluginConfiguration>
<OidEndpoint>https://auth.example.com</OidEndpoint>
<OidClientId>jellyfin</OidClientId>
<OidSecret>your-secure-secret</OidSecret>
<Enabled>true</Enabled>
<EnableAuthorization>true</EnableAuthorization>
<EnableAllFolders>true</EnableAllFolders>
<EnabledFolders />
<AdminRoles>
<string>jellyfin-admins</string>
</AdminRoles>
<Roles>
<string>jellyfin-users</string>
<string>jellyfin-admins</string>
</Roles>
<EnableFolderRoles>false</EnableFolderRoles>
<EnableLiveTvRoles>false</EnableLiveTvRoles>
<EnableLiveTv>false</EnableLiveTv>
<EnableLiveTvManagement>false</EnableLiveTvManagement>
<LiveTvRoles />
<LiveTvManagementRoles />
<FolderRoleMappings />
<RoleClaim>groups</RoleClaim>
<OidScopes>
<string>groups</string>
</OidScopes>
<DefaultUsernameClaim>preferred_username</DefaultUsernameClaim>
<NewPath>true</NewPath>
<CanonicalLinks />
<DisableHttps>false</DisableHttps>
<DisablePushedAuthorization>false</DisablePushedAuthorization>
<DoNotValidateEndpoints>false</DoNotValidateEndpoints>
<DoNotValidateIssuerName>false</DoNotValidateIssuerName>
</PluginConfiguration>
</value>
</item>
</OidConfigs>
</PluginConfiguration>
```
---
## 4. Claim Mapping Configuration
### 4.1 Understanding Role Claims
The plugin uses the `RoleClaim` setting to determine which OIDC claim contains user roles. Common patterns:
**Standard Groups Claim:**
```xml
<RoleClaim>groups</RoleClaim>
```
**Nested Claims (e.g., Keycloak):**
```xml
<RoleClaim>realm_access.roles</RoleClaim>
```
**Complex Nested Claims:**
```xml
<RoleClaim>resource_access.jellyfin.roles</RoleClaim>
```
### 4.2 Common Claim Mapping Issues
**Issue: Incorrect role claims warning**
```
OpenID user "username" has one or more incorrect role claims:
[{"Type": "groups", "Value": "jellyfin-admin"}]. Expected any one of: ["jellyfin-admins"]
```
**Solution:** Ensure exact match between:
1. Group names in Authentik
2. Role values in plugin configuration (`<AdminRoles>`, `<Roles>`)
3. Case sensitivity matters
### 4.3 Username Claim Mapping
The plugin supports multiple username claim sources:
```xml
<DefaultUsernameClaim>preferred_username</DefaultUsernameClaim>
```
**Supported Claims:**
- `preferred_username` - Most common
- `email` - Email address as username
- `sub` - OIDC subject identifier
- `name` - Display name
### 4.4 Additional Scopes
Request additional claims beyond the default `openid` scope:
```xml
<OidScopes>
<string>groups</string>
<string>email</string>
<string>profile</string>
</OidScopes>
```
---
## 5. Mobile App Authentication Workflow
### 5.1 The Mobile App SSO Problem
**Critical Finding:** Jellyfin mobile apps (Android/iOS) have limited SSO support. When using SSO login on mobile:
**Observed Behavior:**
- User clicks "Sign in with SSO"
- Browser-based authentication completes successfully
- Redirect returns to app
- App hangs on "Logging in..." indefinitely
- Session is not established
**Root Cause:**
- Mobile apps expect traditional username/password authentication
- Web-based OIDC flow completes but token is not properly transferred to app
- Issue documented in plugin Issue #189 (Jellyfin 10.9+)
### 5.2 Recommended Mobile App Solutions
#### Option 1: Quick Connect (Recommended)
Quick Connect allows mobile apps to authenticate without entering credentials:
**How It Works:**
1. User opens Jellyfin mobile app
2. App displays a 6-digit code
3. User logs into web interface (via SSO)
4. User enters the 6-digit code in web dashboard
5. Mobile app is authorized automatically
**Configuration:**
- Enable Quick Connect in Jellyfin Dashboard
- Dashboard → **Networking** → **Quick Connect**
- Check "Enable Quick Connect"
**Usage:**
1. Mobile app: **Settings** → **Add Server** → **Quick Connect**
2. Note the 6-digit code
3. Web browser: Login via SSO → **Dashboard** → **Quick Connect**
4. Enter code and authorize
5. Mobile app connects automatically
#### Option 2: API Token Authentication
Generate an API token for mobile app access:
**Steps:**
1. Login to Jellyfin web interface via SSO
2. Navigate to **Dashboard** → **API Keys**
3. Click **+** to create new API key
4. Name: "Mobile App - [Device Name]"
5. Copy the generated API token
6. In mobile app: Use token instead of password
**Security Considerations:**
- Tokens should be device-specific
- Revoke tokens for lost/stolen devices
- Rotate tokens periodically
- Monitor active sessions in Dashboard
#### Option 3: Fallback Local Authentication
Configure the plugin to allow fallback to local Jellyfin authentication:
```xml
<DefaultProvider>Jellyfin.Server.Implementations.Users.DefaultAuthenticationProvider</DefaultProvider>
```
**Workflow:**
- Web users: Use SSO
- Mobile users: Use Jellyfin username/password
- Maintain separate password for mobile access
- Less secure but functional
### 5.3 Mobile App Compatibility Matrix
| App | SSO Support | Quick Connect | API Token | Notes |
|-----|-------------|---------------|-----------|-------|
| Jellyfin Android | Partial | ✓ | ✓ | SSO hangs on "Logging in" |
| Jellyfin iOS | Partial | ✓ | ✓ | Similar issues as Android |
| Jellyfin Web | ✓ | N/A | ✓ | Full SSO support |
| Finamp (Music) | ✗ | ✓ | ✓ | No SSO, Quick Connect recommended |
| Jellyfin Kodi | ✗ | ✓ | ✓ | Token authentication works |
---
## 6. Testing and Troubleshooting
### 6.1 Testing Web Login
**Login URL:**
```
https://jellyfin.example.com/sso/OID/start/authentik
```
**Expected Flow:**
1. User navigates to URL
2. Redirects to Authentik login page
3. User authenticates with Authentik
4. Redirects back to Jellyfin
5. User is logged in with appropriate role
### 6.2 Adding SSO Button to Login Page
Create a custom login button on the Jellyfin login page:
1. Navigate to Dashboard → **General** → **Custom CSS**
2. Add the following CSS to create an SSO button:
```css
/* SSO Login Button */
.raised.emby-button {
padding: 0.9em 1em;
color: inherit !important;
}
.disclaimerContainer {
display: block;
}
```
3. Use browser developer tools or custom HTML injection to add button (plugin documentation has detailed instructions)
### 6.3 Common Errors and Solutions
#### Error: "Client authentication failed"
```
The registered client with id 'jellyfin' is configured to only support
'token_endpoint_auth_method' method 'client_secret_basic'.
```
**Solution:** Change Authentik provider settings:
- Edit OIDC Provider in Authentik
- Set **Client Authentication Method** to `client_secret_post`
- Save and restart Jellyfin
#### Error: "Incorrect role claims"
```
OpenID user "user123" has one or more incorrect role claims:
[{"Type": "groups", "Value": "jellyfin-user"}]. Expected any one of: ["jellyfin-users"]
```
**Solution:** Check exact spelling and case:
- Authentik groups must match exactly
- Plugin `<Roles>` must match exactly
- Claim name in `<RoleClaim>` must match Authentik scope mapping
#### Error: "Error processing request"
```
[ERR] Jellyfin.Api.Middleware.ExceptionMiddleware: Error processing request.
URL "GET" "/sso/OID/start/authentik"
```
**Common Causes:**
1. **DNS Resolution:** Jellyfin container cannot resolve Authentik hostname
2. **Network Connectivity:** Firewall blocking connection
3. **Certificate Issues:** SSL/TLS validation failing
**Solutions:**
- Verify DNS: `docker exec jellyfin ping auth.example.com`
- Check network connectivity
- Set `<DoNotValidateEndpoints>true</DoNotValidateEndpoints>` for testing (not production)
### 6.4 Debugging with Logs
Enable verbose logging in Jellyfin:
1. Dashboard → **Logs**
2. Look for `Jellyfin.Plugin.SSO_Auth` entries
3. Check for claim mismatches, authentication failures
**Useful Log Patterns:**
```
[INF] Jellyfin.Plugin.SSO_Auth.Api.SSOController: SSO Controller initialized
[WRN] OpenID user "username" has one or more incorrect role claims
[ERR] Error processing request
```
---
## 7. Security Best Practices
### 7.1 HTTPS Configuration
**Always use HTTPS in production:**
- Configure reverse proxy (Traefik, Nginx, Caddy)
- Obtain valid SSL/TLS certificates
- Set `<DisableHttps>false</DisableHttps>`
### 7.2 Client Secret Security
**Protect the client secret:**
- Store securely in configuration files
- Use environment variables or secrets management
- Never commit to version control
- Rotate periodically
### 7.3 Endpoint Validation
**Enable validation in production:**
```xml
<DoNotValidateEndpoints>false</DoNotValidateEndpoints>
<DoNotValidateIssuerName>false</DoNotValidateIssuerName>
```
**Disable only for testing/debugging**
### 7.4 Role-Based Access Control
**Implement least privilege:**
- Separate admin and user roles
- Use folder permissions for content restriction
- Enable `<EnableAuthorization>true</EnableAuthorization>`
- Audit user access regularly
### 7.5 API Token Management
**For mobile apps using tokens:**
- Generate device-specific tokens
- Use descriptive names: "iPhone - John's Device"
- Revoke tokens for lost devices
- Set token expiration if supported
- Monitor active sessions
---
## 8. Advanced Configuration Options
### 8.1 Folder-Based Role Mapping
Restrict access to specific libraries based on roles:
```xml
<EnableFolderRoles>true</EnableFolderRoles>
<FolderRoleMappings>
<FolderRoleMappings>
<Role>kids-content</Role>
<Folders>
<string>Kids Movies</string>
<string>Kids TV Shows</string>
</Folders>
</FolderRoleMappings>
</FolderRoleMappings>
```
### 8.2 Canonical User Links
Link SSO users to existing Jellyfin accounts:
```xml
<CanonicalLinks>
<item>
<key>
<string>sso-username</string>
</key>
<value>
<guid>existing-jellyfin-user-guid</guid>
</value>
</item>
</CanonicalLinks>
```
### 8.3 Live TV Permissions
Control Live TV access via roles:
```xml
<EnableLiveTv>true</EnableLiveTv>
<EnableLiveTvRoles>true</EnableLiveTvRoles>
<LiveTvRoles>
<string>livetv-users</string>
</LiveTvRoles>
<EnableLiveTvManagement>true</EnableLiveTvManagement>
<LiveTvManagementRoles>
<string>jellyfin-admins</string>
</LiveTvManagementRoles>
```
### 8.4 Port Override
Override the default port for callback URLs:
```xml
<PortOverride>8096</PortOverride>
```
Useful when Jellyfin runs behind a reverse proxy on a non-standard port.
---
## 9. Integration Testing Checklist
- [ ] Plugin installed and Jellyfin restarted
- [ ] Authentik OIDC provider configured with correct redirect URI
- [ ] Client authentication method set to `client_secret_post`
- [ ] Groups scope enabled in Authentik
- [ ] Test users assigned to jellyfin-users or jellyfin-admins groups
- [ ] Plugin configured with correct endpoint, client ID, and secret
- [ ] Role claim mapping matches Authentik group claim
- [ ] Web login successful via `/sso/OID/start/authentik`
- [ ] User receives correct permissions (admin vs. user)
- [ ] Quick Connect enabled for mobile apps
- [ ] API tokens generated for mobile testing
- [ ] Mobile app authentication tested
- [ ] HTTPS enabled in production
- [ ] Endpoint validation enabled
- [ ] Logs reviewed for errors
---
## 10. References and Resources
**Official Documentation:**
- Jellyfin SSO Plugin Repository: https://github.com/9p4/jellyfin-plugin-sso
- Authentik Jellyfin Integration: https://docs.goauthentik.io/integrations/services/jellyfin/
- Jellyfin Official Documentation: https://jellyfin.org/docs/
**Community Resources:**
- Plugin Issue Tracker: https://github.com/9p4/jellyfin-plugin-sso/issues
- Jellyfin Forum: https://forum.jellyfin.org/
- Authentik Forum: https://github.com/goauthentik/authentik/discussions
**Key Issues Referenced:**
- Mobile App SSO Issue #189: https://github.com/9p4/jellyfin-plugin-sso/issues/189
- Authelia Configuration Discussion: https://www.authelia.com/integration/openid-connect/clients/jellyfin/
- Quick Connect Feature Request: https://support.symfonium.app/t/quick-connect-for-jellyfin/6428
---
## 11. Conclusion
The Jellyfin SSO-Auth plugin provides robust OIDC integration with Authentik for web-based authentication. Key takeaways:
1. **Web authentication works well** when properly configured with correct claim mappings
2. **Mobile app support is limited** - Quick Connect or API tokens are required for mobile access
3. **Role-based authorization** requires exact matching between Authentik groups and plugin configuration
4. **Security configuration** is critical - always use HTTPS and validate endpoints in production
5. **Troubleshooting** relies heavily on log analysis and understanding OIDC claim flows
**Recommended Deployment Strategy:**
- Primary users: SSO via web interface
- Mobile apps: Quick Connect for initial setup, API tokens for ongoing access
- Administrators: SSO + 2FA in Authentik for enhanced security
- Regular audits of active sessions and API tokens
This configuration provides a secure, user-friendly authentication experience while accommodating the limitations of mobile client applications.
---
**Document Version:** 1.0
**Last Updated:** 2026-01-20
**Author:** Research Task RESEARCH-004
**Status:** Complete