---
title: "Setting Up Jellyfin SSO with Authentik: Surviving the Beta"
date: 2025-11-15
draft: false
---

I recently integrated Jellyfin with Authentik for Single Sign-On (SSO). While the plugin works, it is still very much in an early development phase. The logging is often sparse or cryptic, and the feedback loop can be frustrating. Here is a guide focused on the obscure errors you might encounter and the simple fixes that aren't immediately obvious.

## The Setup
The configuration is best handled via API (curl) rather than the UI, as it ensures all fields are correctly typed and persistent.

### 1. Authentik (Terraform)
Let Authentik manage the secrets. Don't hardcode them.
```hcl
resource "authentik_provider_oauth2" "jellyfin" {
  name          = "Jellyfin"
  client_id     = "jellyfin-ericxliu-me"
  # client_secret omitted -> auto-generated
  property_mappings  = [
    authentik_scope_mapping.openid.id,
    authentik_scope_mapping.profile.id,
    authentik_scope_mapping.email.id,
    authentik_scope_mapping.groups.id
  ]
  # ...
}
```

### 2. Jellyfin Plugin (Bash/Curl)
```bash
# ... (retrieve secret from terraform) ...
curl -X POST "https://jellyfin.ericxliu.me/SSO/OID/Add/authentik" ... -d '{
   "OidClientId": "jellyfin-ericxliu-me",
   "OidSecret": "'"${SECRET}"'",
   "OidScopes": ["openid", "profile", "email", "groups"],
   "SchemeOverride": "https",
   "RoleClaim": "groups"
 }'
```

## Obscure Errors & Fixes
Because the plugin is still maturing, it doesn't always handle configuration errors gracefully. Here are the two main "cryptic" failures I encountered.

### 1. The "Value cannot be null" Crash
**The Symptom**: 
You attempt to start the SSO flow and get a generic 500 error. The Jellyfin logs show a C# exception:
```
System.ArgumentNullException: Value cannot be null. (Parameter 'source')
   at System.Linq.Enumerable.Prepend[TSource](IEnumerable`1 source, TSource element)
   at Jellyfin.Plugin.SSO.Api.SSOController.OidChallenge(...)
```
**The Reality**:
This looks like deep internal failure, but it's actually a simple configuration miss. The plugin code attempts to prepend "openid profile" to your configured scopes without checking if your scopes array exists first.
**The Fix**:
You **must** explicitly provide `"OidScopes"` in your JSON configuration. It cannot be null or omitted.
```json
"OidScopes": ["openid", "profile", "email", "groups"]
```

### 2. The HTTP/HTTPS Mismatch (Redirect Loop)
**The Symptom**: 
Authentik rejects the authorization request with "Redirect URI mismatch", or the browser enters a redirect loop.
**The Reality**: 
Jellyfin often sits behind a reverse proxy (Ingress/Traefik) terminating TLS. Use `Browser Developer Tools` to inspect the network requests. You will likely see the `redirect_uri` parameter encoded as `http://jellyfin...` instead of `https://`. configuration. 
**The Fix**:
Do not rely on header forwarding magic. Force the scheme in the plugin configuration:
```json
"SchemeOverride": "https"
```

### 3. Case Sensitivity in JSON
**The Symptom**: Configuration seems to be ignored or fields remain empty after a POST.
**The Reality**: The plugin's API controller keys are Case Sensitive in some versions/contexts.
**The Fix**: Stick to PascalCase for the keys (`OidEndpoint`, `AdminRoles`) as seen in the C# DTOs, rather than camelCase (`oidEndpoint`), unless the specific version documentation explicitly states otherwise. When in doubt, checking the source code (`SSOController.cs`) is often faster than trusting the README.

## Summary
When debugging Jellyfin SSO, don't trust the UI to tell you what's wrong. 
1. **Check the logs** (`kubectl logs`) for C# stack traces.
2. **Sanitize your JSON** inputs (arrays can't be null).
3. **Inspect the URL parameters** in your browser to see what Redirect URI is actually being generated.

### References
- Jellyfin SSO Plugin Repository: `https://github.com/9p4/jellyfin-plugin-sso`
- Authentik Documentation: `https://goauthentik.io/docs/providers/oauth2/`
- Jellyfin API Documentation: `https://api.jellyfin.org/`
