Use standard auth headers for Jellyfin 12

This commit is contained in:
ajp_anton
2026-07-16 00:50:12 +00:00
parent a6acccfa66
commit 8c79cfd3e6
5 changed files with 7 additions and 35 deletions
@@ -309,6 +309,7 @@ public sealed class MultilangController : ControllerBase
var upstreamSw = Stopwatch.StartNew(); var upstreamSw = Stopwatch.StartNew();
var http = _httpClientFactory.CreateClient(); var http = _httpClientFactory.CreateClient();
using var request = new HttpRequestMessage(HttpMethod.Get, proxyRequest.Upstream); using var request = new HttpRequestMessage(HttpMethod.Get, proxyRequest.Upstream);
request.Headers.TryAddWithoutValidation("Authorization", $"MediaBrowser Token=\"{token}\"");
request.Headers.TryAddWithoutValidation("X-Emby-Token", token); request.Headers.TryAddWithoutValidation("X-Emby-Token", token);
request.Headers.TryAddWithoutValidation("X-MediaBrowser-Token", token); request.Headers.TryAddWithoutValidation("X-MediaBrowser-Token", token);
using var response = await http.SendAsync(request, cancellationToken).ConfigureAwait(false); using var response = await http.SendAsync(request, cancellationToken).ConfigureAwait(false);
@@ -1250,10 +1251,6 @@ public sealed class MultilangController : ControllerBase
if (string.IsNullOrWhiteSpace(token)) if (string.IsNullOrWhiteSpace(token))
return null; return null;
var tokenUserId = await GetUserIdFromJellyfinApiAsync(token).ConfigureAwait(false);
if (!string.IsNullOrWhiteSpace(tokenUserId))
return tokenUserId;
var remoteEndpoint = HttpContext.Connection.RemoteIpAddress?.ToString() ?? string.Empty; var remoteEndpoint = HttpContext.Connection.RemoteIpAddress?.ToString() ?? string.Empty;
var deviceId = info?.DeviceId ?? string.Empty; var deviceId = info?.DeviceId ?? string.Empty;
var session = await _sessionManager.GetSessionByAuthenticationToken(token, deviceId, remoteEndpoint).ConfigureAwait(false); var session = await _sessionManager.GetSessionByAuthenticationToken(token, deviceId, remoteEndpoint).ConfigureAwait(false);
@@ -1274,34 +1271,6 @@ public sealed class MultilangController : ControllerBase
: null; : null;
} }
private async Task<string?> GetUserIdFromJellyfinApiAsync(string token)
{
var baseUri = $"{Request.Scheme}://{Request.Host}{Request.PathBase}";
var usersMe = new UriBuilder(new Uri(new Uri(baseUri), "/Users/Me"));
usersMe.Query = Microsoft.AspNetCore.WebUtilities.QueryHelpers.AddQueryString(
string.Empty,
"api_key",
token).TrimStart('?');
var http = _httpClientFactory.CreateClient();
using var request = new HttpRequestMessage(HttpMethod.Get, usersMe.Uri);
request.Headers.TryAddWithoutValidation("X-Emby-Token", token);
request.Headers.TryAddWithoutValidation("X-MediaBrowser-Token", token);
using var response = await http.SendAsync(request, HttpContext.RequestAborted).ConfigureAwait(false);
if (!response.IsSuccessStatusCode)
return null;
await using var stream = await response.Content.ReadAsStreamAsync(HttpContext.RequestAborted).ConfigureAwait(false);
using var doc = await JsonDocument.ParseAsync(stream, cancellationToken: HttpContext.RequestAborted).ConfigureAwait(false);
if (!doc.RootElement.TryGetProperty("Id", out var idProperty))
return null;
var raw = idProperty.GetString();
return Guid.TryParse(raw, out var guid)
? guid.ToString("N")
: raw?.Length == 32 && raw.All(Uri.IsHexDigit) ? raw.ToLowerInvariant() : null;
}
private async Task<bool> IsRequesterAdminAsync() private async Task<bool> IsRequesterAdminAsync()
{ {
var info = await _authorizationContext.GetAuthorizationInfo(HttpContext).ConfigureAwait(false); var info = await _authorizationContext.GetAuthorizationInfo(HttpContext).ConfigureAwait(false);
@@ -19,6 +19,7 @@
const t = token() || qs.get("token") || qs.get("api_key") || ""; const t = token() || qs.get("token") || qs.get("api_key") || "";
const h = { "Content-Type": "application/json" }; const h = { "Content-Type": "application/json" };
if (t) { if (t) {
h.Authorization = `MediaBrowser Token="${t}"`;
h["X-Emby-Token"] = t; h["X-Emby-Token"] = t;
h["X-MediaBrowser-Token"] = t; h["X-MediaBrowser-Token"] = t;
} }
@@ -31,6 +32,7 @@
const h = {}; const h = {};
if (contentType) h["Content-Type"] = contentType; if (contentType) h["Content-Type"] = contentType;
if (t) { if (t) {
h.Authorization = `MediaBrowser Token="${t}"`;
h["X-Emby-Token"] = t; h["X-Emby-Token"] = t;
h["X-MediaBrowser-Token"] = t; h["X-MediaBrowser-Token"] = t;
} }
@@ -71,7 +71,6 @@ public static class ItemsProxyRequestBuilder
} }
var cacheQuery = QueryHelpers.AddQueryString(string.Empty, pairs).TrimStart('?'); var cacheQuery = QueryHelpers.AddQueryString(string.Empty, pairs).TrimStart('?');
pairs.Add(KeyValuePair.Create<string, string?>("api_key", token));
builder.Query = QueryHelpers.AddQueryString(string.Empty, pairs).TrimStart('?'); builder.Query = QueryHelpers.AddQueryString(string.Empty, pairs).TrimStart('?');
var normalizedForCache = builder.Path + (cacheQuery.Length > 0 ? "?" + cacheQuery : string.Empty); var normalizedForCache = builder.Path + (cacheQuery.Length > 0 ? "?" + cacheQuery : string.Empty);
return new ItemsProxyRequest( return new ItemsProxyRequest(
@@ -311,7 +311,9 @@
function refreshItems(itemIds) { function refreshItems(itemIds) {
const token = getClientToken(); const token = getClientToken();
const headers = token ? { "X-Emby-Token": token, "X-MediaBrowser-Token": token } : {}; const headers = token
? { Authorization: `MediaBrowser Token="${token}"`, "X-Emby-Token": token, "X-MediaBrowser-Token": token }
: {};
itemIds.forEach((itemId) => { itemIds.forEach((itemId) => {
fetch(`${BASE_PATH}/Multilang/RefreshItem/${itemId}?includeChildren=true${token ? `&token=${encodeURIComponent(token)}` : ""}`, { method: "POST", headers }); fetch(`${BASE_PATH}/Multilang/RefreshItem/${itemId}?includeChildren=true${token ? `&token=${encodeURIComponent(token)}` : ""}`, { method: "POST", headers });
}); });
@@ -22,8 +22,8 @@ public sealed class ItemsProxyRequestBuilderTests
Assert.NotNull(result); Assert.NotNull(result);
Assert.Equal($"/Users/{UserId}/Items", result.Upstream.AbsolutePath); Assert.Equal($"/Users/{UserId}/Items", result.Upstream.AbsolutePath);
Assert.Contains("api_key=token", result.Upstream.Query);
Assert.DoesNotContain("api_key=old", result.Upstream.Query); Assert.DoesNotContain("api_key=old", result.Upstream.Query);
Assert.DoesNotContain("api_key", result.Upstream.Query, StringComparison.OrdinalIgnoreCase);
Assert.DoesNotContain("api_key", result.NormalizedUrlForCache, StringComparison.OrdinalIgnoreCase); Assert.DoesNotContain("api_key", result.NormalizedUrlForCache, StringComparison.OrdinalIgnoreCase);
Assert.Contains("userId=" + UserId, result.NormalizedUrlForCache); Assert.Contains("userId=" + UserId, result.NormalizedUrlForCache);
} }