Skip to content

Migrating from 9p4

Nils Lehnen edited this page Jul 12, 2026 · 8 revisions

Warning

This plugin is in pre-alpha and exists for developer testing only. Do the migration described here on a test instance with a config backup, never on a production system. The archived upstream receives no security updates anymore, so switching is the right move eventually — but the right time for a production server is a stable release, not now.

Migrating from 9p4/jellyfin-plugin-sso

This project continues the archived 9p4/jellyfin-plugin-sso from its last release (4.0.0.4). The short version: it is an in-place upgrade, not a move.

Why it is an upgrade, not a migration

Both versions share the same plugin identity:

  • Plugin GUID 505ce9d1-d916-42fa-86ca-673ef241d7df
  • Plugin name SSO Authentication
  • Configuration type Jellyfin.Plugin.SSO_Auth (same XML file)

Jellyfin therefore treats them as the same plugin. Swapping the binaries keeps the existing configuration file (<jellyfin data dir>/plugins/configurations/Jellyfin.Plugin.SSO_Auth.xml), and with it:

  • every configured OpenID and SAML provider (endpoints, client ids, certificates),
  • secrets (OidSecret, signing material),
  • all linked accounts (CanonicalLinks),
  • role/folder/Live-TV mappings.

New configuration fields added by this project are additive with safe defaults (false), so a config written by 4.0.0.4 loads unchanged. Nothing has to be re-entered.

How to switch

  1. Back up the config file named above (a plain file copy is enough).
  2. Stop Jellyfin.
  3. Replace the plugin binaries in <jellyfin data dir>/plugins/SSO-Auth*/ with a build of this repository — see Installation. There is no published plugin-repository manifest yet; building from source is the supported path for now (a proper repo URL for in-catalog updates is tracked in #150).
  4. Start Jellyfin and test a login for each configured provider.

What behaves differently after the switch

This project hardens the login path fail-closed. A provider that "worked" on 4.0.0.4 because nothing was checked can now be rejected — that is the hardening doing its job, and the fix is on the identity-provider side. If a login stops working, check these in order:

OpenID Connect

  • The id_token is now fully validated (signature against the discovery JWKS, issuer, audience, expiry). It must be signed with an asymmetric algorithm — RS256/384/512, PS256/384/512 or ES256/384/512. Tokens signed with HS256 or unsigned tokens are rejected; switch the IdP client's id_token signing algorithm to RS256. EdDSA is not supported.
  • A sub claim is required and must be stable. Account links are now keyed on sub instead of the username. Existing username-keyed links migrate automatically on each user's next login — no admin action needed. A user renamed at the IdP before the switch cannot be matched to their old link and gets a fresh account (the same outcome a rename already had on 4.0.0.4).
  • Clocks matter: expiry is checked with a 5-minute skew. Keep Jellyfin and the IdP on NTP.
  • Details and per-provider notes: providers.md.

SAML

  • Responses signed with SHA-1 are rejected — reconfigure the IdP to sign with RSA/ECDSA-SHA-256 or stronger.
  • A response carrying a DOCTYPE/DTD is rejected outright (XXE defense); well-formed SAML never has one.
  • An assertion without a parseable NotOnOrAfter, or failing its AudienceRestriction, is rejected instead of silently accepted. Replayed assertions are rejected (one-time use).

Optional new hardening (off by default)

Nothing else changes unless you opt in. Two new per-provider SAML switches (ValidateRecipient, ValidateInResponseTo) bind responses to this server and to solicited logins — see providers.md before enabling them (ValidateInResponseTo deliberately disables IdP-initiated SSO).

Rolling back

Straightforward: stop Jellyfin and put the 9p4 4.0.0.4 binaries back. The GUID is the same and the new config fields are additive, so the old version simply ignores them — the configuration, including account links, stays intact. One caveat: OpenID account links that were already migrated to sub keying are not consulted by the old username-keyed code; affected users are re-linked by name exactly as they were before the switch.

If something breaks

Check the Jellyfin log first — the plugin logs why a login was rejected (weak algorithm, missing sub, expired assertion, audience mismatch) with remediation hints, then see Troubleshooting. If you hit something undocumented, please open an issue.

Clone this wiki locally