jeffvli / feishin

A modern self-hosted music player.
https://feishin.vercel.app
GNU General Public License v3.0
2.46k stars 103 forks source link

Support Navidrome behind a OIDC protected reverse proxy #569

Closed enticedwanderer closed 5 months ago

enticedwanderer commented 6 months ago

Expected Behavior

Feishin can login/connect to a Navidrome instance that is OIDC protected.

Current Behavior

Feishin currently is unable to login at all to a OIDC protected Navidrome (sitting behind Traefik/Authentik). Sonixd on the other hand works fine with the same setup. This is similar to #16 except this deals with the OAuth/OIDC delegation which makes it slightly worse.

From the logs in the web console, Feishin will issue 2 requests:

  1. Post to https://navidrome.home.lan/auth/login. This is protected by the OIDC layer and gets bounced to Authentik.
  2. Feishin cannot finish the flow there of course and I believe it bails out.
  3. It then attempts to ping the subsonic ping endpoint but it never provides the u/p/t parameters for auth. Those are NOT protected by OIDC and rely on in protocol auth.

Calls from Feishin in web console:

POST https://navidrome.home.lan/auth/login => 302 Found
GET https://authentik.home.lan/application/o/authorize/?client_id=oqlu7Ew75YBLwnGk3owzqSxt3t0jeAk87YX9rEXZ&redirect_uri=https%3A%2F%2Fauthentik.home.lan%2Foutpost.goauthentik.io%2Fcallback%3FX-authentik-auth-callback%3Dtrue&response_type=code&scope=openid+email+profile+ak_proxy&state=oHnTidB1hMEtO17mksP7qycqC7P_7H4bglPunRiM4S4 => 302 Found
GET https://authentik.home.lan/flows/-/default/authentication/?next=/application/o/authorize/%3Fclient_id%3Doqlu7Ew75YBLwnGk3owzqSxt3t0jeAk87YX9rEXZ%26redirect_uri%3Dhttps%253A%252F%252Fauthentik.home.lan%252Foutpost.goauthentik.io%252Fcallback%253FX-authentik-auth-callback%253Dtrue%26response_type%3Dcode%26scope%3Dopenid%2Bemail%2Bprofile%2Bak_proxy%26state%3DoHnTidB1hMEtO17mksP7qycqC7P_7H4bglPunRiM4S4 => 302 Found
GET https://authentik.home.lan/if/flow/default-authentication-flow/?next=%2Fapplication%2Fo%2Fauthorize%2F%3Fclient_id%3Doqlu7Ew75YBLwnGk3owzqSxt3t0jeAk87YX9rEXZ%26redirect_uri%3Dhttps%253A%252F%252Fauthentik.home.lan%252Foutpost.goauthentik.io%252Fcallback%253FX-authentik-auth-callback%253Dtrue%26response_type%3Dcode%26scope%3Dopenid%2Bemail%2Bprofile%2Bak_proxy%26state%3DoHnTidB1hMEtO17mksP7qycqC7P_7H4bglPunRiM4S4 => 200 OK
GET https://navidrome.home.lan/rest/ping.view?c=Feishin&f=json&v=1.13.0&s=undefined&t=undefined => 200 OK
GET https://navidrome.home.lan/rest/getOpenSubsonicExtensions.view?c=Feishin&f=json&v=1.13.0&s=undefined&t=undefined => 200 OK

Logs from navidrome container:

navidrome  | time="2024-04-01T20:21:13Z" level=warning msg="missing parameter: 'u'" requestId=ad19e3d7519c/l98hQoKPvs-161619
navidrome  | time="2024-04-01T20:21:13Z" level=warning msg="API: Failed response" endpoint=/rest/ping.view error=10 message="missing parameter: 'u'" requestId=ad19e3d7519c/l98hQoKPvs-161619
navidrome  | time="2024-04-01T20:21:13Z" level=warning msg="missing parameter: 'u'" requestId=ad19e3d7519c/l98hQoKPvs-161620
navidrome  | time="2024-04-01T20:21:13Z" level=warning msg="API: Failed response" endpoint=/rest/getOpenSubsonicExtensions.view error=10 message="missing parameter: 'u'" requestId=ad19e3d7519c/l98hQoKPvs-161620

Navidrome expects url params u=username and t=jwttoken or p=password on its subsonic API calls. My guess is that unlike Sonixd, Feishin tries to call the auth/login entrypoint to get the jwt token instead of using the password directly. If so, it doesn't conform to what Navidrome expects when delegating auth to an BasicAuth or OAuth/OIDC 3rd party provider provider.

Steps to Reproduce

  1. Set up navidrome with any OIDC solution and delegate auth to it.
  2. Allowlist navidrome's rest/* endpoints for direct auth bypassing OIDC.
  3. Try to connect from Feishin.

Possible Solution (Not obligatory)

Simplest solution would be to remove the need to fetch a jwt token and use the password directly as a URL param, or make it optional/configurable through a flag.

Another potential workaround would be to allow auth/login endpoint in navidrome to be bypassed in OIDC but then other clients may break and a user might get presented with a native login screen from navidrome.

Context

Trying to migrate from Sonixd to Feishin. Blocker since it can't even connect.

Your Environment

kgarner7 commented 6 months ago

I was trying this a while ago, and it is unlikely to come about in the desktop app as there are a few annoying requirements:

  1. You need to detect (for every request) whether you are hitting a captive portal/other auth timeout (this could be 401 permission denied, or some redirect to new page). This is feasible, but not particularly clean
  2. You need to detect the redirect (if it exists) and actually go through the login. This requires opening a new tab to login to your reverse proxy service. This is also doable, but even less clean
  3. You need to save all the possible credentials from this authentication. Since different services may use cookie-based or header-based authentication, you would basically need to capture and intercept all of them (a prospect I'm not too fond of).

This can be bypassed in the browser (just host Feishin on the same domain on a subpath) without any extra work.

All in all, while I was able to get it (sort of) to work, I cannot endorse this as a practical solution. Unfortunately for the desktop it'll have to wait for #419.

If you have questions about how to setup the web version in the meantime to work with reverse proxy authentication, feel free to add on here, but otherwise I'll probably close this issue.

enticedwanderer commented 5 months ago

Oh I thought feishin already supported subsonic directly. I didn't realize you were using direct navidrome APIs. In that case yeah, I'll just wait until #419 is ready. Thanks! Yeah I agree it's likely not worth going through the hoops you mentioned above.

kgarner7 commented 5 months ago

Yeah, it's a pain point for me as well (I can't use the desktop app on my work device), but I know that to properly support Subsonic in the current scheme would require more rework (that I'm personally not comfortable taking over). If you like the webapp I would still suggest giving it a shot. I appreciate the understanding