From 7a64863ead5ef47d042d04df6a0e8e6f35d20e1f Mon Sep 17 00:00:00 2001 From: Nik Afiq Date: Mon, 14 Sep 2026 16:05:22 +0900 Subject: [PATCH] fix: rewrite Filebar's malformed auth header to unblock login (temporary) Filebar sends its auth only on the legacy X-Emby-Authorization header, with unquoted values (Client=Filebar instead of Client="Filebar"), and never sends the Authorization header Jellyfin 12.0 requires to resolve request.App -- causing every login to 400. Switches the debug proxy to OpenResty and adds a Lua shim that rewrites just Filebar's requests into the header format Jellyfin expects (matching SenPlayer's working requests); everything else passes through unchanged. This is a workaround for a Filebar bug, not a permanent fix -- see the TODO in jellyfin-header-debug.yaml to remove it once Filebar ships a corrected release. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_016EQrGkfXFae4PZG9QfPRf4 --- manifests/media/jellyfin-header-debug.yaml | 51 ++++++++++++++++++---- 1 file changed, 43 insertions(+), 8 deletions(-) diff --git a/manifests/media/jellyfin-header-debug.yaml b/manifests/media/jellyfin-header-debug.yaml index 243b5c9..522847b 100644 --- a/manifests/media/jellyfin-header-debug.yaml +++ b/manifests/media/jellyfin-header-debug.yaml @@ -1,12 +1,19 @@ # Apply: kubectl apply -f manifests/media/jellyfin-header-debug.yaml # Delete: kubectl delete -f manifests/media/jellyfin-header-debug.yaml -# Description: TEMPORARY diagnostic proxy that transparently forwards to the -# real jellyfin Service while logging auth-related request headers to stdout. -# Used to capture what the Filebar iOS app sends on /Users/AuthenticateByName -# so we can see why Jellyfin 12.0 rejects it. Swap the jellyfin Ingress -# backend to jellyfin-debug-proxy to route traffic through this, capture -# logs, then swap back and delete this file/PR once done -- not meant to -# stay in the cluster long-term. +# Description: TEMPORARY compat shim + diagnostic proxy in front of the real +# jellyfin Service. The Filebar iOS app (<=1.4.13) sends its auth header only +# on the legacy X-Emby-Authorization header, unquoted (e.g. Client=Filebar +# instead of Client="Filebar"), and never sends the modern Authorization +# header Jellyfin 12.0 requires to identify the client -- so every login +# gets a 400 (ArgumentNullException on request.App). This proxy rewrites +# just Filebar's requests into the header format Jellyfin expects (matching +# what SenPlayer already sends correctly) and forwards everything else +# unchanged. All requests are also logged to stdout for visibility. +# +# TODO: DELETE this file and revert the jellyfin Ingress backend to +# `jellyfin` once Filebar ships a fixed release that sends a correct +# Authorization header on its own -- this is a workaround for their bug, +# not something to keep around permanently. apiVersion: v1 kind: ConfigMap metadata: @@ -28,6 +35,34 @@ data: server { listen 8080; access_log /dev/stdout jf_debug; + + # TEMPORARY Filebar compat shim -- see TODO in this file's header. + # Only touches requests from Filebar's broken auth header; everything + # else (SenPlayer, web UI, etc.) passes through untouched. + access_by_lua_block { + local ua = ngx.var.http_user_agent or "" + local authorization = ngx.var.http_authorization + local legacy = ngx.var.http_x_emby_authorization + + if ua:find("^Filebar") and (not authorization or authorization == "") and legacy then + local client = legacy:match("Client=([^,]+)") + local device = legacy:match("Device=([^,]+)") + local deviceid = legacy:match("DeviceId=([^,]+)") + local version = legacy:match("Version=([^,]+)") + local token = legacy:match("Token=([^,]+)") + + if client then + local fixed = string.format('MediaBrowser Client="%s", Device="%s", DeviceId="%s", Version="%s"', + client, device or "", deviceid or "", version or "") + if token and token ~= "" then + fixed = fixed .. string.format(', Token="%s"', token) + end + ngx.req.set_header("Authorization", fixed) + ngx.req.set_header("X-Emby-Authorization", fixed) + end + end + } + location / { proxy_pass http://jellyfin.jellyfin.svc.cluster.local:80; proxy_http_version 1.1; @@ -58,7 +93,7 @@ spec: spec: containers: - name: nginx - image: nginx:1.27-alpine + image: openresty/openresty:1.31.1.1-alpine ports: - containerPort: 8080 volumeMounts: