-
-
Notifications
You must be signed in to change notification settings - Fork 4
Linked Accounts
On the 5.0 line (Jellyfin 12), the settings are five tabs. This page describes the build Latest points at, where every setting is on one page. On the 5.0 line the plugin's entry in the plugin list opens Overview, which shows a card per provider, the SSO-only state and what to do next, and carries no setting of its own; the other four tabs are Providers (both provider workspaces, their editors, the login-button fields and the Configuration check), Accounts (the linked-accounts panel and the account-link export and import), Policies (the provisioning-profile editor) and Server (the configuration export and import, the login-page buttons switch and single logout). So the panel this page is about is the Accounts tab.
Linked Accounts is the panel on the plugin's admin configuration page that answers "which Jellyfin accounts can sign in through SSO, and through what", and lets an administrator cut one of them off. It sits above the provider lists, between Config transfer and Login Page Buttons, and it is collapsed until you open it.
Everything it shows is read from this server's stored account links. It contacts no identity provider, and opening it changes nothing.
Press Refresh Linked Accounts to load the roster. It is one row per account, not one per link, so an account linked to two providers reads as one account with two links.
| Column | What it holds |
|---|---|
| Account | The Jellyfin username, or Deleted account (<user id>) when no account with that id exists any more. |
| SSO links | One line per link: provider (protocol) - canonical name - last SSO login: …. |
| Action | Revoke for an account that still exists; a sentence instead of a button for one that does not. |
The canonical name is the identity provider's stable subject for that user - the
OpenID sub or the SAML NameID - which is what a login actually resolves against. On a
link made before subjects were required it is the username the link fell back to.
The protocol is on the line because the two protocols keep separate provider
namespaces: an OpenID provider and a SAML provider may both be called keycloak, and the
provider name alone would not say which link you are looking at.
An account that holds no SSO link is not listed at all. The panel answers "who is linked", and listing the whole user table would bury that answer. When nothing is linked it says so in a sentence rather than showing an empty table, because a blank panel reads as a failed load.
last SSO login is the last successful SSO login through that one link, in your
browser's local time. Read it as "not later than", and do not build a session
timeline on it: the stamp is only rewritten once the stored value has aged past an hour,
so that an ordinary repeat login costs no configuration write. A login that happened
forty minutes after the stamp leaves the stamp where it is.
never means exactly "no successful SSO login has been recorded through this link since
the stamp existed" - a link older than the field, or an account that has not signed in
since. It never means a login at an unknown time.
Revoke removes that account's links from every configured provider, ends every
session it holds on every device, and switches it back to Jellyfin's built-in password
provider. It drives the same administrator endpoint as POST /sso/Unregister/<username>
(see Security Model) - the panel
adds no second revoke path of its own. The confirmation dialog names the consequences
before it proceeds.
Three properties of that action are the sort an operator meets at the wrong moment if they have not read them first.
A revoke re-opens native password login for the account it touches. Switching the account back to the built-in password provider is what stops SSO resolving to it - and it is also what makes Jellyfin's own password form work for that account again, even on a server you otherwise run SSO-only. The server-wide SSO-only setting is not changed and no other account is affected; this one account is now a password account. If that is not what you want, disable the account rather than only revoking it.
A revoke is not durable where the provider allows existing-account linking. With
AllowExistingAccountLink switched on for a provider, a login whose name matches an
existing account adopts it - so the same-named account can be linked again at the next SSO
login, and the cut you just made is undone by the user simply signing in. Where a cut has
to hold on such a provider, disable or rename the local account as well. Under the
fail-closed default, where adoption is off, the revoke is durable on its own.
A row whose account no longer exists carries no Revoke. The revoke resolves the account by its username, and an orphaned link has no account and therefore no username left - so the button would answer "not found" on exactly the rows the panel was opened for. The row carries a sentence saying so instead of a control that always fails.
Such a row is rare now: an account deleted while this plugin is loaded takes its links
with it the moment the server reports the deletion, and the audit log carries the fact
instead ([SSO Audit] Jellyfin user <id> was deleted; removed its N SSO link(s) from …).
A row still appears for an account deleted while the plugin was not loaded, or whose
removal could not be written to disk. It is reported deliberately rather than dropped,
because such a link is invisible from every other surface, and the user id on the row is
what you need to find it; the next SSO login for the same subject treats the link as
absent and links the account it creates or adopts instead.
On the 5.0 line (Jellyfin 12), from
5.0.0-JF12-beta.87onward, Revoke on your own row can be refused. Where your own account has no password anybody can sign in with, holds a link on an enabled provider, and no other enabled administrator holds a link on an enabled provider, the revoke is refused and nothing is changed, because it could leave the server with no administrator able to reach it. Another administrator revoking for you, linking another administrator account to a provider first, or setting a password on an administrator account from the Jellyfin dashboard each ends it. What counts as a way in is on Self-service linking. On the 4.3 line the revoke is not refused.
Directly below the roster sits Waiting for Approval: the accounts this plugin created
disabled because their provider has ProvisionNewUsersDisabled on, and that are still
waiting. Refresh Linked Accounts re-reads both panels from one roster read, so the two
never disagree about a link.
A row appears only while three things hold at once: this plugin's own record says it
provisioned the account inert; that record still names the account the link points at, so
a link rebound to another account carries no record over; and the account is still
disabled. Each row names the identity the link was made under
(provider (protocol) - canonical name), the instant the wait began, and an Approve
button.
What it does not list, and why: an account an administrator disabled has no record here, whatever its state, and is enabled in the Jellyfin dashboard, never from this panel. The panel offers only what this plugin itself put on hold. An account that has since been enabled by hand leaves the list on the next read.
Approve enables the account and changes nothing else. Its permissions stay as the provisioning set them (the starting policy or profile the provider names), and the next SSO login mints a session. An administrator account is refused with a sentence pointing at the dashboard, so administrator access never comes from here. The action is bound to the link on the row: if the account is gone or no longer waiting when you press it, nothing is enabled and the list is re-read. Every approval is written to the audit log, naming who approved, the provider and the account id.
The panel shows the first hundred rows and says how many were cut (Showing the first 100 of N accounts waiting for approval), so a broad identity-provider audience cannot turn the page into an unbounded list; approve or revoke some to see the rest.
All three routes behind these panels - the roster read, the revoke and the approve -
require administrator privileges, so the panels are empty and their actions refused
for anyone else. The revoke is additionally rate-limited, in its own unregister budget,
so it neither starves nor is starved by the login flows, and the approve shares the budget
of the link routes; a burst of either can be throttled and retried.
Every value on a row is rendered as literal text. A canonical name is whatever the identity provider put in its subject claim and a username is user-influenced, so nothing on this panel is ever interpreted as markup.
- Security Model - what the revoke does at the endpoint, and how account links are bound to their issuer.
- Hardening & Options Reference - the rest of the admin surface on this page: configuration check, test connection, and configuration export / import.
- Login Flow - how a link is created in the first place, including self-service linking.
Repository · Issues · Releases · Security policy - report vulnerabilities privately, never in a public issue. Pages describe what is implemented today; if the wiki disagrees with the code, the code wins.
Getting started
- Installation
- Provider Setup
- Hardening & Options Reference
- Linked Accounts
- Config as code
- Migrating from 9p4
- Troubleshooting
- Rollback
- Server Migration
How it works
Security
- Security Model
- Security Conformance (ASVS / RFC 9700)
- SSO-Only Login - design record
- Single Logout - design record
Standards & process (internal / maintainer)