Skip to content

Migrating from 9p4

shippingToken edited this page Jul 15, 2026 · 8 revisions

Warning

This plugin is at the In-Development stage of its maturity ladder (see the Roadmap) 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 Full 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 to sub, but because the username is IdP-mutable that migration is gated behind AllowExistingAccountLink — so enable that flag for the provider before your users log in again (a short supervised window), or link accounts with the admin endpoint. With the flag off, an OpenID login whose name still matches its account is refused until you migrate it. Keep a non-SSO admin with a password login so you cannot lock yourself out. Full runbook, break-glass, and the takeover-window caveat: the Security Model page and providers.md. 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