[API Request] New proper secure authentification #25
Replies: 12 comments 19 replies
-
Just an idea: a revokable key could be used without changing anything on the API if you feed it on the |
Beta Was this translation helpful? Give feedback.
-
I think servers should at least support passing auth info in the Authorization header instead of the URL as this will prevent common leakage issues with browser clients. However, the main blocker currently is that streaming URLs and image URL must be constructed by the client and include auth parameters. These will be have to be returned by the server instead such that they can be loaded directly by the browser. After this, extending support for e.g. OIDC should be possible |
Beta Was this translation helpful? Give feedback.
-
So since there's movement, let's restart the discussion about this major difficulty for OpenSubsonic. This is the most complex change but it's wanted and welcome by many, so let's try to figure out a solution that covers most case and solve current issues. |
Beta Was this translation helpful? Give feedback.
-
The only request I have for this right now is that whatever scheme we choose must be able to pass the auth token as a URL param and not require the Authorization header, since some clients use a 3rd party library (like libmpv) that actually handles the HTTP request to stream the file, and we can only pass it the URL, not headers. |
Beta Was this translation helpful? Give feedback.
-
Another bump, this is not something I will design on my own, security is complex, different servers may have different needs and requirements, I'm not expert enough in this field to be able to recommend something that I know will be the best solution that covers all the needs. |
Beta Was this translation helpful? Give feedback.
-
Quick (not extremely well thought out) suggestion based on oauth:
This is the simplest solution I can think of and shouldn't be hard for severs that already support login to implement. This can later be extended with Authorization Code grant, passing access token i header etc. Using OIDC Discovery also allows servers optionally to delegate authorization to a different server entirely. |
Beta Was this translation helpful? Give feedback.
-
Another possibility: https://indieauth.net/ |
Beta Was this translation helpful? Give feedback.
-
@Tolriq what are the authentication methods of the other servers you support? |
Beta Was this translation helpful? Give feedback.
-
Hello, I want to add a perspective to the discussion: as developer of neither a subsonic client nor server, I recently wrote a Traefik plugin to convert the subsonicauth parameter to a basicauth header, with the goal of being able to transparently delegate authentication to a 3rd-party (at the reverse proxy level) and ultimately get rid of the need for reversibly encrypted credentials in my Subsonic backend. Following this, here are my thoughts on the integration issue (I have additional remarks on the security/confidentiality aspects, but they might be the topic of a separate comment). The subsonicauth scheme expects proper subsonic responses in case of authentication failures, and specifically a response with an HTTP 200 status and a This means in turn that I had to add some required/expected fields in the response, that make the process not entirely transparent to the client, and leads to ambiguity about how to properly handle the Subsonic/OpenSubsonic protocol. In particular:
The issues are compounded if you want to host several Subsonic servers behind the same reverse proxy (not my case, and it would be kind of insane anyway). And for clients that already support alternative authentication schemes, like Symfonium and DSub that support basicauth, it is not entirely clear whether they expect a subsonic or a protocol-approriate response in case of authentication error with the alternative scheme. Ideally, from an integration perspective and specifically to simplify delegating authentication to specialized services, alternative authentication schemes should be decoupled a bit from the rest of the OpenSubsonic API:
Additionally, from my perspective as an integrator, I see authentication as mostly a client issue: If a subsonic server does not support any authentication scheme, but does support a way provide the information about which user has made the request, I can work with it by implementing the authentication myself. On the other hand, if the server supports only specific authentication schemes (that require the server to handle user credentials), I'm screwed, and most likely will need to resort to hacks to make it work (like a hardcoded dummy credential for all users, which can be forwarded from my reverse proxy after the user has been properly authenticated). I hope this helps =) |
Beta Was this translation helpful? Give feedback.
-
For Ampache passwords the hash is sha256. i don't really care what is chosen but at a minimum a hash of at least sha256 would be a start. (I'll just add a column for additional implementations.) So if we set a standard hash then the token auth will be able to use a hashed password. For alternative auth. Ampache uses a Bearer Authorization token which allows removing the auth parameter from the url Setting a standard hash and then allowing for a token in the header would solve a lot of the problems with auth. For additional token/app access for individual clients, a separate column (or table for multiple entries) following the same encryption/header style. Ampache only has a single api key field for users but could be expanded into per-client tokens. but that's what i'd do, header auth and a standard hash encryption |
Beta Was this translation helpful? Give feedback.
-
Hey! I was reading through this thread, and having implemented a few auth solutions at $DAY_JOB I thought I could maybe help out with some ideas, also summarizing some ideas from earlier in the thread. To reiterate from what I've read: There are two main security issues we would like to resolve with an iteration on the authentication. We also have the following client types (or let me know if I missed something)
Proposal sequenceDiagram
Client->>Server: POST /login
Server->>Client: {"token": "<token>"}
Client->>Server: GET /stream
Note left of Server: Authorization: Bearer <token>
Server->>Client: 200 OK
Client->>Server: POST /playbackToken
Server->>Client: {"playbackToken": "<playback-token>", "expiresIn": 600 }
Client->>Device: Play media at /stream?t=<playback-token>
Device->>Server: GET /stream?t=<playback-token>
Server->>Device: 200 OK
In brief:
This solves the plaintext password issue for servers, and additionally allows them to delegate login, for example to LDAP or other solutions to not have to store credentials. I would deliberately leave the format of the token opaque in the protocol, leaving it up to server implementations to decide based on their needs and be flexible for the future. For clients that don't implement Casting/DLNA, they also won't need to take on the extra complexity of managing multiple tokens and the whole flow is kept rather simple. A possible downside is confusion around "which token to use where", so naming and documentation is quite important. And I'm not sure if this would be an issue in practice, but servers could try to skip implementing the endpoint and token handling. There is another step for the clients and servers to implement, and browser based clients need to be careful with token storage to prevent XSS vulnerabilities. But overall the user flow remains the same, and implementation is simple. AlternativesA1. Refresh TokenThis is alternative is a variation of the proposal, where the core flow is the same and it still uses two tokens, but differently.
sequenceDiagram
Client->>Server: POST /login
Server->>Client: {"token": "<token>", "expiresIn": 600, "refreshToken": "<refresh-token>"}
Client->>Server: GET /stream
Note left of Server: Authorization: Bearer <token>
Server->>Client: 200 OK
Client->>Device: Play media at /stream?t=<token>
Device->>Server: GET /stream?t=<token>
Server->>Device: 200 OK
Note right of Client: Time passes
Client->>Server: POST /refreshToken
Server->>Client: {"token": "<token>", "expiresIn": 600}
This approach mainly mitigates server API fragmentation, since authentication for all endpoints are the same. Passing the token as a query parameter could still be restricted to the stream/image endpoints to make it more secure. In that case servers need special handling of the tokens for those endpoints anyway, and the clients need logic to pass a token to the device anyway, so implementation effort would be roughly the same. A1. OAuth2/OIDCUsing OAuth2/OIDC would allow servers to completely delegate authentication to a third party, and a lot of self-hosters are already running a Identity Provider with support for those protocols. Using OAuth2 between the client and server directly, without a third party makes less sense to me. That is what those protocols are designed for after all, and in other cases add a lot of complexity without clear advantages. I see a few reasons why I would caution against this:
Overall, I'd be the most worried about the change-management of clients/severs/users upgrading though, as while it's more complicated there are plenty of examples and libraries. Defining a protocol extension for OAuth2 authentication could be a nice middle ground as it would be very useful to have. |
Beta Was this translation helpful? Give feedback.
-
Is this a good place to bring up "proper" two factor authentication too? |
Beta Was this translation helpful? Give feedback.
-
Type of change
API extension
Proposal description
This is again a template issue to gather feedback and ideas from clients and servers.
Current v1.13 authentification system is a mess as force servers to store the credential in clear.
The need is to offer a new authentication system that allows servers to properly store hashed passwords, and probably also support some kind of revokable API keys to allows users to disable app access without having to change their main password.
Backward compatibility impact
No response
Backward compatibility
API details
TBD
Security impacts
No response
Potential issues
No response
Alternative solutions
No response
Beta Was this translation helpful? Give feedback.
All reactions