fix(jellyfin): support Jellyfin 12 authorization - #128
Merged
Merged
Conversation
Jellyfin 12.0 disables legacy authorization by default and a migration turns it off on existing installs too, so the X-MediaBrowser-Token header and the api_key query parameter no longer authenticate. Every Jellyfin request came back 401 after the upgrade. Switch to the standard Authorization header with the MediaBrowser scheme via a shared jellyfinAuthHeaders() helper, and move the WebSocket handshake to the ApiKey query parameter. Both are accepted by 10.10.x and 12.x, so no version switch is needed. The helper rejects a missing or malformed API key instead of sending a well-formed header with a wrong token, which would only surface as a generic 401. WebSocket auth rejections now log the actual reason rather than looping silently on reconnect. Also stop passing raw axios errors to the logger on the Jellyfin paths: the serialized error carries config.headers, which would write the Authorization header to disk in cleartext.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Jellyfin 12.0 disables legacy authorization by default, and a migration turns it off on existing installs as well.
AuthorizationContext.csnow gates the old paths behindEnableLegacyAuthorization:X-MediaBrowser-Tokenheader — gated, no longer readapi_keyquery parameter — gated, no longer readAuthorization: MediaBrowser …header — always readApiKeyquery parameter — always readAnchorr used the first two exclusively, so every Jellyfin request returned 401 after upgrading. Reported as:
The WebSocket handshake goes through the same
AuthorizationContext(WebSocketManager.WebSocketRequestHandlercalls_authService.Authenticate), so it was affected too.Fix
jellyfinAuthHeaders()helper inapi/jellyfin.jsemittingAuthorization: MediaBrowser Client="Anchorr", …, Token="…". All 11 call sites converted, plus the one inroutes/jellyfinRoutes.js. The poller, webhook, seeder, pruner, resolver and weekly roundup all route throughapi/jellyfin.jsand inherit the change.?api_key=to?ApiKey=, with the key URL-encoded. An unencoded key containing&or#could previously truncate or append query parameters.Hardening picked up while reviewing the change:
config.headers, which wrote theAuthorizationheader tologs/in cleartext. This predates the change (it leakedX-MediaBrowser-Tokenthe same way) but is fixed here since this PR introduces the new header. Affected:routes/jellyfinRoutes.js(2x),jellyfinPoller.js.Verification
Authorizationheader is emitted correctly and noX-MediaBrowser-Tokenis sent.undefined, whitespace-padded, quote, comma, backslash, NUL, tab, DEL, CRLF.logs/after the logger change.Not tested against a live Jellyfin 12 instance.
Out of scope
CollectionIdfallback infetchLibrariescan route items to the wrong Discord channel when Jellyfin rejects/Items. Pre-existing, worth its own issue.logger.error("...", err)pattern exists at roughly 20 other call sites. Only the Jellyfin paths were touched, since only those carry an auth header.