michaelherger / librespot

Open Source Spotify client library
MIT License
18 stars 7 forks source link

Authentication Problem #20

Closed glk1001 closed 1 month ago

glk1001 commented 1 month ago

Hi, I've been using your 'Spotty' for a few years now in the Kodi 'plugin.audio.spotify' (https://github.com/glk1001/plugin.audio.spotify) but in the last couple of weeks it's been failing to authenticate. I've noticed this issue for librespot: https://github.com/librespot-org/librespot/issues/1308.

From the discussion I'm not quite sure how Spotty figures in this. Are you able to explain the issue for me?

Thanks, Greg

michaelherger commented 1 month ago

At first I thought I'd point you at the librespot thread. But you've already found it... I don't have much to add. All I know I've learnt from that discussion myself. But I don't know how the Kodi plugin is handling authentication. If it's trying to use username/password, then obviously it won't work any more. But Spotty with LMS still seems to be working just fine as long as you're using a Spotify app to authorize Spotty.

Just checked the Kodi reference you gave. And it's indeed using username/password https://github.com/glk1001/plugin.audio.spotify/blob/master/resources/lib/spotty.py#L73-L75 or https://github.com/glk1001/plugin.audio.spotify/blob/master/resources/lib/spotty.py#L49-L51. So that integration needs to be updated to allow authentication using a Spotify app, cache the returned token, and use that token. I can't help with that, as I'm not a Python guy (and am running out of spare time anyway...). But if the plugin's maintainer needs more info, they can certainly reach out to me.

michaelherger commented 1 month ago

Oh, you actually are the maintainer?... Here's what I'm doing in Spotty: https://github.com/michaelherger/Spotty-Plugin/blob/master/API/Token.pm#L80. Basically define a cache folder where to store the token, fire up the helper in auth mode. Once you select that instance as your playback target in the Spotify app, the helper would exit and store the token. Subsequent calls then point at the same cache folder from where the helper would pick up the token.

glk1001 commented 1 month ago

Thanks for the quick response. Yes I'm the maintainer. I took over a while back and cleaned up the code and kept it working but I'm a bit weak in understanding the auth stuff. The Kodi plugin getting the token from a cache sounds good. Roughly what does the auth helper look like and how does Spotify know about it. (I'm not a perl guy so if you can give a quick explanation of the helper that would be great.)

glk1001 commented 1 month ago

OK, As proof of concept I can get a token and cache it to a file that the plugin reads. (Just using the popup web browser approach.) This allows the spotipy parts of the plugin to work (building all the playlists, albums, etc.). But when it comes to playing a track I currently have this spotty code:

/x86-linux/spotty-x86_64 --cache /spotty-cache --ap-port 54443 --verbose --enable-audio-cache --name temp-spotty --bitrate 320 --initial-volume 50 --enable-volume-normalisation --normalisation-gain-type track --single-track spotify:track:1ypzyOTKMWIR3XNBB3iDTZ -u gregg.kay@gmail.com -p **** How can I get around needing username and password here? Thanks, Greg
michaelherger commented 1 month ago

Roughly what does the auth helper look like and how does Spotify know about it.

The "auth helper" is the same spotty binary. It's just using a few other command line parameters.

spotty -a -c /path/to/cache -n "auth helper"

Would store a file credentials.json with a token in the cache folder. If you use -c in any other command it'll pick up those credentials.

Then to get an access token for the web API, do the following:

spotty -c . -n "spotty helper" --get-token

You can add more parameters to define the scope etc. This will spit out a JSON with the access token and an expiresIn value (which usually is 1h). So cache the token for the given duration, refresh with the above call when needed, and use it to access the web API.

If your helper is up to date, it would support --save-token, too. Check with spotty -x. In that case instead of piping the token out to the console (or some file) you can have it stored in a file directly.

For the playback just don't provide credentials. Remove all references to -u and -p. Spotty will pick up the credentials stored in the cache folder. See the basic command line in https://github.com/michaelherger/Spotty-Plugin/blob/master/custom-convert.conf#L3.

glk1001 commented 1 month ago

Hi, Thanks for your reply. Sorry I'm still somewhat confused about the helper stuff. If you can spare some more help that would be much appreciated.

Using the Spotipy example app (https://github.com/spotipy-dev/spotipy/blob/master/examples/app.py), together with my client_id, client_secret, and redirect_url I can get a token:

{"access_token": "BQBg8IGzKA96-....-JExAlu-....", "token_type": "Bearer", "expires_in": 3600, "refresh_token": "....-...", "scope": "playlist-modify-private playlist-modify-public playlist-read-collaborative playlist-read-private ugc-image-upload user-follow-modify user-follow-read user-library-modify user-library-read user-modify-playback-state user-read-currently-playing user-read-email user-read-playback-state user-read-private user-top-read", "expires_at": 1723548696}

If I put this in a file that the Kodi Spotify plugin can read, then it uses the token to successfully get playlists, albums, etc. This I can understand. I don't quite understand what I need to do with Spotty. spotty -x gives

spotty-x86_64 -x ok spotty v1.3.1 - using librespot 0.4.2 d197824 (Built on 2023-08-06, Build ID: 1Z1svdWl, Profile: release) {"autoplay":true,"debug":false,"lms-auth":true,"ogg-direct":true,"podcasts":true,"save-token":true,"version":"1.3.1","volume-normalisation":true,"zeroconf-port":true}

Do I have to do something special to use the helpers you mention. Running the commands you showed give no output. Can I put the above token in a 'credentials.json' for spotty to use? Or am I completely misunderstanding the auth and spotty helpers?

michaelherger commented 1 month ago

You should stick to one method. I've described the one I'm using. What Spotipy does, I don't know. If you have questions about their process, ask them. If you have specific questions about the process I described I'll be happy to dig deeper with you. But from what you've showed you have all you need: there's the access token (and you should never post an access or refresh token, as it would allow anyone to access your account!), even a refresh token (which I don't know how to use, as I never use that).

glk1001 commented 1 month ago

Thanks for the tip on not showing access tokens. One thing that will help me get going in the short term. Using the access token I get from Spotipy how do I use that with

/x86-linux/spotty-x86_64 --cache /spotty-cache --ap-port 54443 --verbose --disable-audio-cache --disable-discovery --name temp-spotty --bitrate 320 --initial-volume 50 --enable-volume-normalisation --normalisation-gain-type track --single-track spotify:track:1ypzyOTKMWIR3XNBB3iDTZ

Can I just put the token in 'credentials.json' in the cache directory?

michaelherger commented 1 month ago

Please see my previous response...

Or give it a try and tell me about the outcome. I do NOT know Spotipy. I can't tell you what they're doing.

glk1001 commented 1 month ago

I was confused about the 'credentials.json' content. So after a fair bit of work today I know a bit more. In summary, I have two Kodi plugin problems with Spotify's removal of the username/password authentication mode:

1) How to get a token that Spotipy needs to build the Kodi playlist, albums, etc. menus 2) How to get the credentials that Spotty needs to run the "single-track" command that provides a stream for the Kodi music player

With some experimenting I found that the Spotty zeroconf option outputs a cacheable 'credentials.json' file that can satisfy the 'single-track' command. (The auth_data in 'credentials.json' seems to be some sort of encrypted blob which I don't know much about.) Then, by using the Spotty 'save-token' option, I could use the cached 'credentials.json' to get an access token that Spotipy could use. So this approach, for me, is good because it roughly fits with the current Kodi spotify plugin model.

But the overall downside with the Spotify change is that now there is an extra user interaction step outside of Kodi to authenticate the zeroconf server request in order to get 'credentials.json'. Prior to this everything was kept in config files and the user was not affected.

Does your approach with the Spotty helper avoid the extra user interaction step?

Thanks, Greg

michaelherger commented 1 month ago

If by "extra user interaction" you refer to the authentication process, then no, it has to be done. Authentication (and security in general) often comes with UX drawbacks. But it's a necessity.

glk1001 commented 1 month ago

OK, thanks a lot for your help.