Skip to content

Apply provided patch to apps/nextjs-app/lib/api-auth.ts#515

Merged
fredrikburmester merged 2 commits into
fredrikburmester:mainfrom
enoch85:main
May 24, 2026
Merged

Apply provided patch to apps/nextjs-app/lib/api-auth.ts#515
fredrikburmester merged 2 commits into
fredrikburmester:mainfrom
enoch85:main

Conversation

@enoch85

@enoch85 enoch85 commented May 19, 2026

Copy link
Copy Markdown
Contributor

Why

authenticateMediaBrowser (lib/api-auth.ts) is the auth path for /api/recommendations, /api/watchlists, /api/watchlists/promoted and /api/search. It validates the supplied MediaBrowser token by calling /Users/Me, which requires a user access token. A Jellyfin server API key has no user context, so /Users/Me returns 401 even when the key is valid — locking out server-to-server callers that only hold an API key.

What

When /Users/Me returns 401, fall back to /System/Info (which API keys can hit) and surface the caller as the admin pseudo-user { id: "system-api-key", name: "System API Key", isAdmin: true } — the same shape and convention getUserFromEmbyToken (lib/jellyfin-auth.ts) already uses for this case. User access tokens keep their existing behaviour; only the 401-from-/Users/Me path changes.

Motivation

Unblocks server-to-server clients. Maintainerr has added a Streamystats integration but can only authenticate with a Jellyfin API key, so it currently can't reach these endpoints.

Summary by Sourcery

Allow Jellyfin API key authentication for media browser endpoints by falling back to /System/Info when /Users/Me cannot validate a token.

New Features:

  • Support authenticating Jellyfin server API keys for media browser API endpoints by treating them as a privileged pseudo-user.

Enhancements:

  • Refine Jellyfin token validation to distinguish between user access tokens and server API keys with a dedicated /System/Info-based fallback path.

@sourcery-ai

sourcery-ai Bot commented May 19, 2026

Copy link
Copy Markdown
Contributor

Reviewer's Guide

Adds support in Jellyfin token validation for authenticating server API keys by falling back from /Users/Me to /System/Info and surfacing them as a system pseudo-user, while preserving existing behavior for user access tokens.

Sequence diagram for updated Jellyfin token validation fallback

sequenceDiagram
  participant Caller
  participant validateJellyfinToken
  participant JellyfinUsersMe
  participant validateAsApiKey
  participant JellyfinSystemInfo

  Caller->>validateJellyfinToken: validateJellyfinToken(serverUrl, token)
  validateJellyfinToken->>JellyfinUsersMe: fetch(serverUrl + /Users/Me)
  alt [response.ok]
    JellyfinUsersMe-->>validateJellyfinToken: user JSON
    validateJellyfinToken-->>Caller: { userId, userName, isAdmin }
  else [response.status === 401]
    validateJellyfinToken->>validateAsApiKey: validateAsApiKey(serverUrl, token)
    validateAsApiKey->>JellyfinSystemInfo: fetch(serverUrl + /System/Info)
    alt [sysRes.ok]
      JellyfinSystemInfo-->>validateAsApiKey: system info
      validateAsApiKey-->>validateJellyfinToken: { userId: system-api-key, userName: System API Key, isAdmin: true }
      validateJellyfinToken-->>Caller: pseudo-user
    else [!sysRes.ok]
      validateAsApiKey-->>validateJellyfinToken: null
      validateJellyfinToken-->>Caller: null
    end
  else [other non-2xx]
    validateJellyfinToken-->>Caller: null
  end
  opt [network error or AbortError on /Users/Me]
    validateJellyfinToken->>validateAsApiKey: validateAsApiKey(serverUrl, token)
    validateAsApiKey->>JellyfinSystemInfo: fetch(serverUrl + /System/Info)
    alt [sysRes.ok]
      JellyfinSystemInfo-->>validateAsApiKey: system info
      validateAsApiKey-->>validateJellyfinToken: pseudo-user
      validateJellyfinToken-->>Caller: pseudo-user
    else [!sysRes.ok]
      validateAsApiKey-->>validateJellyfinToken: null
      validateJellyfinToken-->>Caller: null
    end
  end
Loading

File-Level Changes

Change Details Files
Extend Jellyfin token validation to distinguish between user access tokens and server API keys, adding a /System/Info-based fallback and shared pseudo-user representation for API-key callers.
  • Document in comments that validateJellyfinToken accepts both user access tokens and server API keys, describing the validation flow and pseudo-user behavior.
  • Change validateJellyfinToken to treat a successful /Users/Me response as the primary path, returning user identity and admin status directly from that payload.
  • Handle 401 responses from /Users/Me by invoking a new validateAsApiKey helper that validates server API keys via /System/Info and returns an admin pseudo-user when successful.
  • On network or timeout errors when calling /Users/Me, attempt the same /System/Info-based validation before failing.
  • Introduce validateAsApiKey helper that calls /System/Info with Jellyfin headers, enforces a 5s timeout, and returns the canonical "system-api-key" admin pseudo-user when the response is OK.
apps/nextjs-app/lib/api-auth.ts

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've left some high level feedback:

  • For non-401 non-OK responses from /Users/Me (e.g. 403, 500), validateJellyfinToken now returns null without attempting the /System/Info fallback; consider whether those status codes should also trigger validateAsApiKey for consistency with the intended API key support.
  • The "system-api-key" pseudo-user ID and name are now defined here as literals; if the same convention is used in getUserFromEmbyToken it may be worth centralizing these constants to avoid divergence between implementations.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- For non-401 non-OK responses from `/Users/Me` (e.g. 403, 500), `validateJellyfinToken` now returns `null` without attempting the `/System/Info` fallback; consider whether those status codes should also trigger `validateAsApiKey` for consistency with the intended API key support.
- The `"system-api-key"` pseudo-user ID and name are now defined here as literals; if the same convention is used in `getUserFromEmbyToken` it may be worth centralizing these constants to avoid divergence between implementations.

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Refactor token validation logic to streamline API key handling and improve error handling. Use constants for system API key user ID and name.
@fredrikburmester

Copy link
Copy Markdown
Owner

Reviewed locally — this is sound and does what it describes. Merging it now to unblock the Maintainerr integration. 🙏

Two small things I'd love a follow-up PR for (neither blocks this one):

  1. Gate the fallback on response.status === 401 rather than any non-OK response. Right now a transient non-401 from /Users/Me (e.g. 500/503/429) also triggers the /System/Info API-key check. It's safe today only because Jellyfin's /System/Info is admin-gated (Policies.RequiresElevation) — a non-admin user token gets 403 there. But gating on 401 specifically makes the intent explicit and lets transient errors stay retryable instead of attempting key validation. ~1 line.

  2. The "matches getUserFromEmbyToken" comment is slightly off. getUserFromEmbyToken (jellyfin-auth.ts) returns { ok: false } immediately on a non-OK /Users/Me and only falls back to /System/Info inside its catch block (thrown errors only) — so it wouldn't accept an API key that returns a clean 401. Your version (fall back on any non-OK) is actually the more correct behavior for the goal, but the two paths now diverge. Either tweak the comment, or — better — align getUserFromEmbyToken to do the same so both auth paths behave identically for API keys.

Any chance you'd be up for a quick follow-up PR with those? No pressure if not — happy to pick it up otherwise.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants