Skip to content

Instantly share code, notes, and snippets.

@nielsvanvelzen
Last active September 8, 2026 18:01
Show Gist options
  • Select an option

  • Save nielsvanvelzen/ea047d9028f676185832e51ffaf12a6f to your computer and use it in GitHub Desktop.

Select an option

Save nielsvanvelzen/ea047d9028f676185832e51ffaf12a6f to your computer and use it in GitHub Desktop.
Jellyfin API Authorization

Jellyfin API Authorization

To start using the Jellyfin API, authorization is probably the first thing you'll need to do. Jellyfin's authorization options can be a bit confusing because there are a lot of deprecated options.

Generally there are three ways to authenticate: no authorization, user authorization with an access token or authorization with an API key. The first way is easy, just do nothing. But most often you'll need to use either the access token or API key.

Sending authorization values

There are two methods to send authorization values to the server. The preferred method is by using the Authorization header with the custom MediaBrowser scheme. When a header value is not possible (e.g. URLs send to external applications or due to other constraints) the ApiKey query parameter can be used. The query parameter just takes an access token or API key. We strongly recommend to always use the Authorization header when possible. Sending secure values over query parameters is considered insecure, as they will often show up in reverse proxy logs or in locations where a user could easily copy the URL with the secret included. Only use this method as a last resort. Avoid sending multiple tokens in one request as it's uncertain which value will be used.

Deprecated methods

Before Jellyfin 12.0 a few different headers and query parameters existed. These options have been discouraged for multiple years and have subsequently been removed in Jellyfin 12.0. These were the following options:

Type Name Method
Query api_key Token only
Header X-Emby-Token Token only
Header X-MediaBrowser-Token Token only
Header X-Emby-Authorization Schema

Any client relying on any of these options is not supported in Jellyfin 12.0.

The Jellyfin authorization scheme

The Authorization header uses the format Authorization: <scheme> <parameters>. The Jellyfin scheme is named MediaBrowser and it uses named values separated by commas. There is no specific order for parameters. All keys are case sensitive and only allow alphanumeric characters. Unknown keys are ignored by the server. Values must be wrapped in double quotes (") and should use url encoding.

MediaBrowser key="value", key2="value2", key3="value3"

Parameters

Key Description
Token The access token or API key
Client The name of the client
Version The version of the client
DeviceId A unique id for the device generated by the client
Device The device name

The token parameter is required to use authenticated endpoints. The client and version properties are used to identify the client in the dashboard.

Device identifiers

When it comes to device identifiers in the Jellyfin API, it's important to understand the nuances involved. While generating a random string for the deviceId might seem like a straightforward solution, there are certain limitations to consider. Currently, the server permits only a single access token for each deviceId. This means that you cannot have multiple users signed into your client with a single randomized string. To work around this limitation, you'll need to use a unique identifier for each combination of a device-specific identifier and user-specific identifier.

Since it's often not possible to know the user identifier before signing in at least once, we recommend including the username as user-specific identifier. It is advisable to hash the username because it is user-input that could include double quotes (escaping the header value format) or special characters that your HTTP library might not allow.

Examples

Here are a couple of examples for the authorization header:

  • Authorize with API key

    Authorization: MediaBrowser Token="8ac3a7abaff943ba9adea7f8754da7f8"
  • Authorize with access token

    Authorization: MediaBrowser Token="0381cf931f9e42d79fb9c89f729167df", Client="Android TV", Device="Nvidia Shield", DeviceId="ZQ9YQHHrUzk24vV", Version="0.15.3"
  • Authorize with client information only

    Authorization: MediaBrowser Client="Android TV", Device="Nvidia Shield", DeviceId="ZQ9YQHHrUzk24vV", Version="0.15.3"

The ApiKey query parameter

Use the ApiKey query parameter when the Authorization header can't be used. The value of the query parameter is the access token or API key. Avoid using this option if possible. Never use the ApiKey query parameter and the Authorization header at the same time.

@anultravioletaurora

Copy link
Copy Markdown

Niels you're my hero! 🙏

@Daniel-Byrne

Copy link
Copy Markdown

Thanks for this, I was about to give up!

@McNairy

McNairy commented Oct 17, 2025

Copy link
Copy Markdown

Thank you, I really appreciate it!

@rmalchow

rmalchow commented Nov 1, 2025

Copy link
Copy Markdown

great to see this clean-up across the board. one big question i still have is if we can hope for native SSO (specifically OIDC) support. this would be a really great addition i think!

@dmdeller

Copy link
Copy Markdown

Sounds like the legacy options are being removed in Jellyfin 10.12 (not yet released at time of writing). At least, that's my understanding from reading this: jellyfin/jellyfin#15730

From what I can tell, "deprecated" seems to mean the same thing as "legacy", although both terms are used.

This Gist ranks fairly highly on Google, but it would probably be helpful if it were made part of the main Jellyfin documentation.

@dmdeller

dmdeller commented Jan 20, 2026

Copy link
Copy Markdown

A note about Apple platforms:

I was initially reluctant to use the Authorization header on macOS and iOS because Apple's API docs state that this header is reserved for exclusive use by the operating system and is discouraged for use by app developers.

With the apparently imminent removal of all of Jellyfin's deprecated options, that only leaves ApiKey as an option, which does not support the full schema. That said, Jellyfin is far from the only server API that requires use of a custom Authorization header, and as such it is a very common problem faced by iOS app developers.

Since launching my app several months ago, I have been using Authorization, in accordance with Jellyfin's advice and against Apple's advice, and have not observed any problems so far. Even so, I wish Jellyfin would consider offering an alternative header like the deprecated X-Emby-Authorization, in case it becomes apparent that it may be causing problems on Apple platforms.

I acknowledge that it should not be the job of the Jellyfin project to work around Apple's unusual and frankly ill-conceived API design choices. Unfortunately, as app developers, we are simply caught in the middle between two situations we can't do much of anything about.

@nielsvanvelzen

Copy link
Copy Markdown
Author

Sounds like the legacy options are being removed in Jellyfin 10.12 (not yet released at time of writing). At least, that's my understanding from reading this: jellyfin/jellyfin#15730

Correct, we're planning to disable the deprecated authorization options starting with the 12.0 release.

From what I can tell, "deprecated" seems to mean the same thing as "legacy", although both terms are used.

Yes, we use both words but they generally mean the same thing.

This Gist ranks fairly highly on Google, but it would probably be helpful if it were made part of the main Jellyfin documentation.

We're working on a developer site, this is one of the documents written for it.

A note about Apple platforms:

I was initially reluctant to use the Authorization header on macOS and iOS because Apple's API docs state that this header is reserved for exclusive use by the operating system and is discouraged for use by app developers.

The authorization header is a standardized header from the HTTP specification. You (client) are a user agent that needs to authorize access to a origin server (Jellyfin). This is normal behavior and literally all API's use this header, including Jellyfin. The only thing we're changing now is removing support for non-standard headers.

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