thlucas1 / homeassistantcomponent_spotifyplus

Home Assistant integration for Spotify Player control, services, and soundtouchplus integration support.
MIT License
56 stars 4 forks source link

librespot: bad credentials #45

Closed meiser79 closed 1 month ago

meiser79 commented 1 month ago

System Health details

System Information

version core-2024.9.3
installation_type Home Assistant OS
dev false
hassio true
docker true
user root
virtualenv false
python_version 3.12.4
os_name Linux
os_version 6.6.46-haos
arch x86_64
timezone Europe/Berlin
config_dir /config
Home Assistant Community Store GitHub API | ok -- | -- GitHub Content | ok GitHub Web | ok HACS Data | ok GitHub API Calls Remaining | 5000 Installed Version | 2.0.1 Stage | running Available Repositories | 1424 Downloaded Repositories | 7
Home Assistant Cloud logged_in | false -- | -- can_reach_cert_server | ok can_reach_cloud_auth | ok can_reach_cloud | ok
Home Assistant Supervisor host_os | Home Assistant OS 13.1 -- | -- update_channel | stable supervisor_version | supervisor-2024.09.1 agent_version | 1.6.0 docker_version | 26.1.4 disk_total | 30.8 GB disk_used | 10.5 GB healthy | true supported | true host_connectivity | true supervisor_connectivity | true ntp_synchronized | true virtualization | kvm board | ova supervisor_api | ok version_api | ok installed_addons | Mosquitto broker (6.4.1), Samba share (12.3.2), Zigbee2MQTT (1.40.1-1), NGINX Home Assistant SSL proxy (3.10.1), Advanced SSH & Web Terminal (19.0.0), Matter Server (6.5.1)
Dashboards dashboards | 6 -- | -- resources | 1 views | 5 mode | storage
Recorder oldest_recorder_run | 19. September 2024 um 04:57 -- | -- current_recorder_run | 28. September 2024 um 08:19 estimated_db_size | 1263.86 MiB database_engine | sqlite database_version | 3.45.3
SpotifyPlus integration_version | v1.0.58 -- | -- clients_configured | 1: meiser79 (premium) api_endpoint_reachable | ok

Checklist

Describe the issue

I try to use SpotifyPlus together with a librespot instance (running latest 0.5.0-dev compiled today in a Docker container). The zeroconf authentication fails with [2024-09-28T09:16:31Z ERROR librespot] could not initialize spirc: Permission denied { Login failed with reason: Bad credentials }

I captured the zeroconf communication and posted it in the HA forum.

I do not see why it does not work. BTW, my loginID is not a canonical one, but is identical to my username.

Reproduction steps

none

Debug logs

none

Diagnostics dump

No response

thlucas1 commented 1 month ago

I have spent the last 3 days learning about spotifyd, and how it works.

I was finally able to get Spotifyd installed on my WSL Debian image, and running with PulseAudio. I am now in the process of testing.

A few things I have learned thus far:

1) as you said, it (and Librespot) does not support the zeroconf resetUsers endpoint. I have changes in the works for SpotifyPlus to account for this.

2) Spotifyd must be ran in “discovery” mode in order for it to register itself with zeroconf / mDNS. If you specify the “username” config option, then it will NOT register with zeroconf (even if you have the zeroconf_port config option set). SpotifyPlus uses zeroconf discovery to find Spotify Connect devices, and will not find the Spotifyd device if running in username mode.

3) The Librespot credentials.json file contents can be used directly as the username, password, and Authorization type when building the blob for the zeroconf addUser call. The credentials file can be generated by running Spotifyd service in discovery mode, and authenticating to it via one of the Spotify apps. It will create the credentials.json file in the cache folder (specified by cache_path config setting).

Will keep you posted as I learn more.

meiser79 commented 1 month ago

Thanks a lot for you work!!! I'm running librespot in discovery mode and don't use any credentials.json.

thlucas1 commented 1 month ago

@meiser79 Question for you - did librespot generate a credentials.json file for you in its cache location? This would be the same location it puts audio files, volume files, etc. If you are running spotifyd, it places the credentials file in the location specified by the cache_path configuration variable (e.g. home/user/.cache/spotifyd/credentials.json).

Here's what I am thinking ...

The Librespot credentials.json file contents can be used directly as the username, password, and Authorization type when building the blob for the zeroconf addUser call. I believe the contents of the credentials file do not change, as long as the password is not changed for the user. In order for SpotifyPlus to authenticate to Spotify using librespot, it needs to access the same credentials that librespot uses to authenticate. SpotifyPlus will not be able to access the librespot cache location to load the credentials file, so the user would have to copy the credentials file to a location that SpotifyPlus can access. For HA users, this would be the /config/.storage location.

Furthermore, it appears the librespot credentials.json file is structured for a single user's credentials. SpotifyPlus supports multiple users, so it would need to access different credential files based on the user that is authenticating. This could be accomplished by renaming the crednetials.json file to something like credentials_username.json in the SpotifyPlus location. Note that you would not rename the librespot cache location file.

Thoughts? I have most of this tested and working - just have to implement the multi-user support, which is just a file path formulation based on the user that is authenticating.

meiser79 commented 1 month ago

As I only run librespot in discovery mode, there's no credentials.json. I could create a credentials.json via librespot's OAuth option and then copy it to the right location. Your proposal is fine for me even though it's means to handle all this via SSH and not the HA UI. But that's also fine for me.

I for sure do not understand all details about librespot, but I would really like to understand why it works with the Spotify Android app or the Spotify Desktop app even though these apps also don't know the credentials.json. Do you know what is missing on the spotifyd/librespot side?

The librespot sourcecode includes this line in the src/main.rs file: error!("Credentials are required if discovery and oauth login are disabled.");

So it should be possible without credentials.json when using discovery mode, no?

thlucas1 commented 1 month ago

I am not sure why it works with Spotify Android App myself. I believe that the Spotify embedded client uses another method besides zeroconf to detect the presence of Spotify Connect devices on the network (SSDP / Simple Service Discovery Protocol maybe?), as well as the zeroconf / mDNS / Bonjour service.

As for the discovery mode, you should be able to enable discovery mode (like spotifyd does) on librespot, and it will generate the credentials.json once a Spotify App client (mobile, web, etc) connects up to it.

I am not sure if both discovery AND oauth login are required to do that or not. I would think just the discovery mode would be enough.

I would try just discovery mode first to see if it generates the credentials file; if it doesn't, then enable the oauth mode. Again, I am not overly familiar with librespot, so not sure.

meiser79 commented 1 month ago

This is the debug output if the Spotify Android app connects:

sysadmin@server:~$ ./librespot -v
[2024-09-28T16:14:42Z INFO  librespot] librespot 0.5.0-dev 118a9e1 (Built on 2024-09-28, Build ID: FvANduSm, Profile: release)
[2024-09-28T16:14:42Z TRACE librespot] Command line argument(s):
[2024-09-28T16:14:42Z TRACE librespot]      v
[2024-09-28T16:14:42Z DEBUG librespot_core::session] new Session
[2024-09-28T16:14:42Z DEBUG librespot_discovery::server] Zeroconf server listening on 0.0.0.0:41769
[2024-09-28T16:14:42Z INFO  librespot_playback::mixer::softmixer] Mixing with softvol and volume control: Log(60.0)
[2024-09-28T16:14:42Z DEBUG librespot_playback::player] new Player [0]
[2024-09-28T16:14:42Z INFO  librespot_playback::convert] Converting with ditherer: tpdf
[2024-09-28T16:14:42Z INFO  librespot_playback::audio_backend::pulseaudio] Using PulseAudioSink with format: S16
[2024-09-28T16:14:44Z WARN  libmdns::fsm] error sending packet Os { code: 99, kind: AddrNotAvailable, message: "Cannot assign requested address" }
[2024-09-28T16:14:46Z WARN  libmdns::fsm] error sending packet Os { code: 99, kind: AddrNotAvailable, message: "Cannot assign requested address" }
[2024-09-28T16:14:49Z WARN  libmdns::fsm] error sending packet Os { code: 99, kind: AddrNotAvailable, message: "Cannot assign requested address" }
[2024-09-28T16:14:50Z WARN  libmdns::fsm] error sending packet Os { code: 99, kind: AddrNotAvailable, message: "Cannot assign requested address" }
[2024-09-28T16:14:52Z WARN  libmdns::fsm] error sending packet Os { code: 99, kind: AddrNotAvailable, message: "Cannot assign requested address" }
[2024-09-28T16:14:55Z WARN  libmdns::fsm] error sending packet Os { code: 99, kind: AddrNotAvailable, message: "Cannot assign requested address" }
[2024-09-28T16:14:57Z WARN  libmdns::fsm] error sending packet Os { code: 99, kind: AddrNotAvailable, message: "Cannot assign requested address" }
[2024-09-28T16:14:57Z DEBUG librespot_discovery::server] POST "/" {}
[2024-09-28T16:14:57Z DEBUG librespot_core::session] Shutdown: Invalidating session
[2024-09-28T16:14:57Z DEBUG librespot::component] new MercuryManager
[2024-09-28T16:14:57Z DEBUG librespot::component] new ChannelManager
[2024-09-28T16:14:57Z DEBUG librespot_core::session] new Session
[2024-09-28T16:14:57Z DEBUG librespot_connect::spirc] new Spirc[0]
[2024-09-28T16:14:57Z DEBUG librespot::component] new MercuryManager
[2024-09-28T16:14:57Z DEBUG librespot::component] new ApResolver
[2024-09-28T16:14:57Z DEBUG librespot_core::http_client] Requesting https://apresolve.spotify.com/?type=accesspoint&type=dealer&type=spclient
[2024-09-28T16:14:57Z DEBUG librespot_playback::player] command=SetSession
[2024-09-28T16:14:57Z DEBUG librespot_core::session] drop Session
[2024-09-28T16:14:57Z DEBUG librespot::component] drop ChannelManager
[2024-09-28T16:14:57Z DEBUG librespot::component] drop MercuryManager
[2024-09-28T16:14:57Z INFO  librespot_core::session] Connecting to AP "ap-gew4.spotify.com:4070"
[2024-09-28T16:14:58Z DEBUG librespot_core::connection] Authenticating with AP using AUTHENTICATION_STORED_SPOTIFY_CREDENTIALS
[2024-09-28T16:14:58Z INFO  librespot_core::session] Authenticated as 'meiser79' !
[2024-09-28T16:14:58Z DEBUG librespot_connect::spirc] canonical_username: meiser79
[2024-09-28T16:14:58Z DEBUG librespot_playback::player] command=AddEventSender

This is when SpotifyPlus tries to connect:

sysadmin@server:~$ ./librespot -v
[2024-09-28T16:21:36Z INFO  librespot] librespot 0.5.0-dev 118a9e1 (Built on 2024-09-28, Build ID: FvANduSm, Profile: release)
[2024-09-28T16:21:36Z TRACE librespot] Command line argument(s):
[2024-09-28T16:21:36Z TRACE librespot]      v
[2024-09-28T16:21:36Z DEBUG librespot_core::session] new Session
[2024-09-28T16:21:36Z DEBUG librespot_discovery::server] Zeroconf server listening on 0.0.0.0:38159
[2024-09-28T16:21:36Z INFO  librespot_playback::mixer::softmixer] Mixing with softvol and volume control: Log(60.0)
[2024-09-28T16:21:36Z DEBUG librespot_playback::player] new Player [0]
[2024-09-28T16:21:36Z INFO  librespot_playback::convert] Converting with ditherer: tpdf
[2024-09-28T16:21:36Z INFO  librespot_playback::audio_backend::pulseaudio] Using PulseAudioSink with format: S16
[2024-09-28T16:22:03Z DEBUG librespot_core::session] Shutdown: Invalidating session
[2024-09-28T16:22:03Z DEBUG librespot::component] new MercuryManager
[2024-09-28T16:22:03Z DEBUG librespot::component] new ChannelManager
[2024-09-28T16:22:03Z DEBUG librespot_core::session] new Session
[2024-09-28T16:22:03Z DEBUG librespot_connect::spirc] new Spirc[0]
[2024-09-28T16:22:03Z DEBUG librespot::component] new MercuryManager
[2024-09-28T16:22:03Z DEBUG librespot::component] new ApResolver
[2024-09-28T16:22:03Z DEBUG librespot_core::http_client] Requesting https://apresolve.spotify.com/?type=accesspoint&type=dealer&type=spclient
[2024-09-28T16:22:03Z DEBUG librespot_playback::player] command=SetSession
[2024-09-28T16:22:03Z DEBUG librespot_core::session] drop Session
[2024-09-28T16:22:03Z DEBUG librespot::component] drop ChannelManager
[2024-09-28T16:22:03Z DEBUG librespot::component] drop MercuryManager
[2024-09-28T16:22:04Z INFO  librespot_core::session] Connecting to AP "ap-gew4.spotify.com:4070"
[2024-09-28T16:22:04Z DEBUG librespot_core::connection] Authenticating with AP using AUTHENTICATION_USER_PASS
[2024-09-28T16:22:04Z ERROR librespot] could not initialize spirc: Permission denied { Login failed with reason: Bad credentials }

So there's the difference regarding the _AUTHENTICATION_STORED_SPOTIFYCREDENTIALS vs. _AUTHENTICATION_USERPASS.

thlucas1 commented 1 month ago

Yeppers - the SpotifyPlus app currently uses USER_PASS. That will change (for librespot clients anyway) with the new release.

Also, do you know how librespot handles multiple users? So if you had another Spotify account and you tried to connect up to spotifyd or your app that uses librespot, how it would handle it? Does it create a separate credentials.json file? Does it add both accounts to the same credentials.json?

thlucas1 commented 1 month ago

FYI - just released a new version of the SpotifyPlus integration

[ 1.0.59 ] - 2024/09/28

Requirements

I think this will fix your problem. Be sure to follow the wiki documentation for how to configure the access to librespot credentials.json file.

Reach out if you have any questions or problems with it.

meiser79 commented 1 month ago

Hi, I cannot update the integration in HA. Do you need to make a release as version 1.0.59 is not shown in the Releaases tab.

I'll check with multiple accounts, we have a family account with 2 accounts, let's see how librespot handles it in the credentials.json.

thlucas1 commented 1 month ago

@meiser79 DOH! Sorry about that - I was in such a rush to get this out there, I forgot to publish the release. Thanks for letting me know. It is now published.

meiser79 commented 1 month ago

One remark; wiki says /config/.storage/spotifywebapiPython_librespot_credentials.json, but the file needs to be /config/.storage/SpotifyWebApiPython_librespot_credentials.json

thlucas1 commented 1 month ago

btw, check out the spotifywebapipython librespot credentials file format wiki docs on adding multiple accounts to the copy of the librespot credentials file. Be sure to NOT modify the original credentials.json file that librespot uses - it won't recognize multiple accounts in the file.

Instead of looking like this:

{"username":"31l77xxxxxxxxxxxxxxxxx","auth_type":1,"auth_data":"QVFBOW ... AydVY="}

it will look like this:

[
{"username":"31l77xxxxxxxxxxxxxxxxx","auth_type":1,"auth_data":"QVFBOW ... AydVY="},
{"username":"3222xxxxxxxxxxxxxxxxx","auth_type":1,"auth_data":"QVFBOW ... AydVY="}
]

Let me know how it goes. Thanks

meiser79 commented 1 month ago

So with one user, it works fine. Thanks a lot!! Testing with multiple accounts later.

thlucas1 commented 1 month ago

Thanks for your help in testing. I updated the wiki docs for the file name case.

meiser79 commented 1 month ago

I checked with 2 accounts which belong to the same family account. The content of librespot's credentials.json is replaced with the respective account token, so it just handles the last connected account. I just have my "meiser79" account configured in HA. I can still start a playlist with this account if the other account is connected to the librespot device (it gets kicked out).

So from my point of view, everything works fine and as expected!!! Very well done! Therefore, I close this bug report.