[GH-ISSUE #1532] Authorization request to keymaster returns 403. #691

Open
opened 2026-02-27 19:31:58 +03:00 by kerem · 36 comments
Owner

Originally created by @juliusdelta on GitHub (Aug 12, 2025).
Original GitHub issue: https://github.com/librespot-org/librespot/issues/1532

Look for similar bugs

This just started happening within the past 24 hours but I didn't see any other bugs like it :)

Description

403 Status code is returned from a Mercury request

Version

librespot-connect = { version = "0.6.0", optional = true }
librespot-core = "0.6.0"
librespot-oauth = "0.6.0"
librespot-playback = { version = "0.6.0", optional = true }

This is taken from the spotify-player repo for the version I am on.

How to reproduce

I'm just using spotify-player and sifting through the logs

Log

2025-08-12T18:35:50.330189Z ERROR librespot_core::mercury: error 403 for uri hm://keymaster/token/authenticated?scope=user-read-recently-played,user-top-read,user-read-playback-position,user-read-playback-state,user-modify-playback-state,user-read-currently-playing,streaming,playlist-read-private,playlist-modify-private,playlist-modify-public,playlist-read-collaborative,user-follow-read,user-follow-modify,user-library-read,user-library-modify&client_id=65b708073fc0480ea92a077233ca87bd&device_id=40cd3147-a4c0-4757-8ecb-5875bd3aaa25


2025-08-12T18:35:50.330228Z DEBUG librespot_core::session: could not dispatch command: Service unavailable { error handling Mercury response: MercuryResponse { uri: "hm://keymaster/token/authenticated?scope=user-read-recently-played,user-top-read,user-read-playback-position,user-read-playback-state,user-modify-playback-state,user-read-currently-playing,streaming,playlist-read-private,playlist-modify-private,playlist-modify-public,playlist-read-collaborative,user-follow-read,user-follow-modify,user-library-read,user-library-modify&client_id=xxxxxxx", status_code: 403, payload: [[123, 34, 99, 111, 100, 101, 34, 58, 52, 44, 34, 101, 114, 114, 111, 114, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 58, 34, 73, 110, 118, 97, 108, 105, 100, 32, 114, 101, 113, 117, 101, 115, 116, 34, 125]] } }    

Host (what you are running librespot on):

  • OS: Arch Linux
  • Platform: AMD Ryzen 9
  • Kernal: Linux 6.12.41-1-lts

Additional context

This issue is coming from the spotify-player program. Apologies if this isn't the right place but it seems the error is in the underlying PKCE Authentication flow which seems to be handled exclusively by Librespot.

I checked the Spotify api documentation to ensure that all those scopes being requested still exist and they seem to, however I'm no expert on how flaky they are.

I can provide more info if needed.

Originally created by @juliusdelta on GitHub (Aug 12, 2025). Original GitHub issue: https://github.com/librespot-org/librespot/issues/1532 ### Look for similar bugs This just started happening within the past 24 hours but I didn't see any other bugs like it :) ### Description 403 Status code is returned from a Mercury request ### Version ```toml librespot-connect = { version = "0.6.0", optional = true } librespot-core = "0.6.0" librespot-oauth = "0.6.0" librespot-playback = { version = "0.6.0", optional = true } ``` This is taken from the [spotify-player](https://github.com/aome510/spotify-player/blob/v0.20.6/spotify_player/Cargo.toml#L18) repo for the version I am on. ### How to reproduce I'm just using spotify-player and sifting through the logs ### Log ```log 2025-08-12T18:35:50.330189Z ERROR librespot_core::mercury: error 403 for uri hm://keymaster/token/authenticated?scope=user-read-recently-played,user-top-read,user-read-playback-position,user-read-playback-state,user-modify-playback-state,user-read-currently-playing,streaming,playlist-read-private,playlist-modify-private,playlist-modify-public,playlist-read-collaborative,user-follow-read,user-follow-modify,user-library-read,user-library-modify&client_id=65b708073fc0480ea92a077233ca87bd&device_id=40cd3147-a4c0-4757-8ecb-5875bd3aaa25 2025-08-12T18:35:50.330228Z DEBUG librespot_core::session: could not dispatch command: Service unavailable { error handling Mercury response: MercuryResponse { uri: "hm://keymaster/token/authenticated?scope=user-read-recently-played,user-top-read,user-read-playback-position,user-read-playback-state,user-modify-playback-state,user-read-currently-playing,streaming,playlist-read-private,playlist-modify-private,playlist-modify-public,playlist-read-collaborative,user-follow-read,user-follow-modify,user-library-read,user-library-modify&client_id=xxxxxxx", status_code: 403, payload: [[123, 34, 99, 111, 100, 101, 34, 58, 52, 44, 34, 101, 114, 114, 111, 114, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 58, 34, 73, 110, 118, 97, 108, 105, 100, 32, 114, 101, 113, 117, 101, 115, 116, 34, 125]] } } ``` ### Host (what you are running `librespot` on): - OS: Arch Linux - Platform: AMD Ryzen 9 - Kernal: Linux 6.12.41-1-lts ### Additional context This issue is coming from the spotify-player program. Apologies if this isn't the right place but it seems the error is in the underlying PKCE Authentication flow which seems to be handled exclusively by Librespot. I checked the Spotify api documentation to ensure that all those scopes being requested still exist and they seem to, however I'm no expert on how flaky they are. I can provide more info if needed.
Author
Owner

@juliusdelta commented on GitHub (Aug 12, 2025):

Related issue in spotify-player repo: https://github.com/aome510/spotify-player/issues/802

<!-- gh-comment-id:3180639594 --> @juliusdelta commented on GitHub (Aug 12, 2025): Related issue in spotify-player repo: https://github.com/aome510/spotify-player/issues/802
Author
Owner

@photovoltex commented on GitHub (Aug 12, 2025):

Just a quick info, don't just blur out the client_id as this is a public info that is required to debug the issue :). I found out through the other issues that the keymaster/offical client_id (65b708073fc0480ea92a077233ca87bd) was used.

<!-- gh-comment-id:3180646376 --> @photovoltex commented on GitHub (Aug 12, 2025): Just a quick info, don't just blur out the `client_id` as this is a public info that is required to debug the issue :). I found out through the other issues that the keymaster/offical `client_id` (`65b708073fc0480ea92a077233ca87bd`) was used.
Author
Owner

@photovoltex commented on GitHub (Aug 12, 2025):

For now if you just need an access_token you can acquire one via login5 (available on the Session instance). The token retrieved via login5 has full scope access and is used internally by librespot.

<!-- gh-comment-id:3180696720 --> @photovoltex commented on GitHub (Aug 12, 2025): For now if you just need an `access_token` you can acquire one via `login5` (available on the `Session` instance). The token retrieved via `login5` has full scope access and is used internally by librespot.
Author
Owner

@Googolplexed0 commented on GitHub (Aug 13, 2025):

Experiencing the same exact same issue on a Python implementation of this repo. Creating a new set of credentials works but attempting to reuse them leads to a MercuryClient.MercuryException: status: 403. I've looked across several other implementations (Python or otherwise) and they all are reporting similar issues.

<!-- gh-comment-id:3182064366 --> @Googolplexed0 commented on GitHub (Aug 13, 2025): Experiencing the same exact same issue on a [Python implementation of this repo](https://github.com/kokarare1212/librespot-python). Creating a new set of credentials works but attempting to reuse them leads to a `MercuryClient.MercuryException: status: 403`. I've looked across several other implementations (Python or otherwise) and they all are reporting similar issues.
Author
Owner

@michaelherger commented on GitHub (Aug 13, 2025):

Trying to use login5 in my case fails with some "Service unavailable" error:

[2025-08-13T06:41:56Z DEBUG librespot::component] new MercuryManager
[2025-08-13T06:41:56Z DEBUG librespot::component] new DealerManager
[2025-08-13T06:41:56Z DEBUG librespot_core::mercury] unknown subscription uri=hm://pusher/v1/connections/NmQwM2FjZjVhYjg2MTBmMmM3ZmRiZWZkNGJiZDQwYmUxNmI4MGE5MitBUCt0Y3A6Ly8wYWIxNTA4Yi5pcC5nZXc0LnNwb3RpZnkubmV0OjUwMDIrRDhGMDE4RUM0NEJCOThGRjVEODg2Mjg3N0Y3NDIxMTFBOTM5N0JDRjJCNjZEM0VBNDhENDNEMEE4OEEwOTZCMg%3D%3D
[2025-08-13T06:41:56Z TRACE librespot_core::mercury] response pushed over Mercury: MercuryResponse { uri: "hm://pusher/v1/connections/NmQwM2FjZjVhYjg2MTBmMmM3ZmRiZWZkNGJiZDQwYmUxNmI4MGE5MitBUCt0Y3A6Ly8wYWIxNTA4Yi5pcC5nZXc0LnNwb3RpZnkubmV0OjUwMDIrRDhGMDE4RUM0NEJCOThGRjVEODg2Mjg3N0Y3NDIxMTFBOTM5N0JDRjJCNjZEM0VBNDhENDNEMEE4OEEwOTZCMg%3D%3D", status_code: 200, payload: [] }
[2025-08-13T06:41:56Z DEBUG librespot_core::session] could not dispatch command: Service unavailable { error handling Mercury response: MercuryResponse { uri: "hm://pusher/v1/connections/NmQwM2FjZjVhYjg2MTBmMmM3ZmRiZWZkNGJiZDQwYmUxNmI4MGE5MitBUCt0Y3A6Ly8wYWIxNTA4Yi5pcC5nZXc0LnNwb3RpZnkubmV0OjUwMDIrRDhGMDE4RUM0NEJCOThGRjVEODg2Mjg3N0Y3NDIxMTFBOTM5N0JDRjJCNjZEM0VBNDhENDNEMEE4OEEwOTZCMg%3D%3D", status_code: 200, payload: [] } }

What other information can I provide to help investigating?

<!-- gh-comment-id:3182386172 --> @michaelherger commented on GitHub (Aug 13, 2025): Trying to use `login5` in my case fails with some "Service unavailable" error: ``` [2025-08-13T06:41:56Z DEBUG librespot::component] new MercuryManager [2025-08-13T06:41:56Z DEBUG librespot::component] new DealerManager [2025-08-13T06:41:56Z DEBUG librespot_core::mercury] unknown subscription uri=hm://pusher/v1/connections/NmQwM2FjZjVhYjg2MTBmMmM3ZmRiZWZkNGJiZDQwYmUxNmI4MGE5MitBUCt0Y3A6Ly8wYWIxNTA4Yi5pcC5nZXc0LnNwb3RpZnkubmV0OjUwMDIrRDhGMDE4RUM0NEJCOThGRjVEODg2Mjg3N0Y3NDIxMTFBOTM5N0JDRjJCNjZEM0VBNDhENDNEMEE4OEEwOTZCMg%3D%3D [2025-08-13T06:41:56Z TRACE librespot_core::mercury] response pushed over Mercury: MercuryResponse { uri: "hm://pusher/v1/connections/NmQwM2FjZjVhYjg2MTBmMmM3ZmRiZWZkNGJiZDQwYmUxNmI4MGE5MitBUCt0Y3A6Ly8wYWIxNTA4Yi5pcC5nZXc0LnNwb3RpZnkubmV0OjUwMDIrRDhGMDE4RUM0NEJCOThGRjVEODg2Mjg3N0Y3NDIxMTFBOTM5N0JDRjJCNjZEM0VBNDhENDNEMEE4OEEwOTZCMg%3D%3D", status_code: 200, payload: [] } [2025-08-13T06:41:56Z DEBUG librespot_core::session] could not dispatch command: Service unavailable { error handling Mercury response: MercuryResponse { uri: "hm://pusher/v1/connections/NmQwM2FjZjVhYjg2MTBmMmM3ZmRiZWZkNGJiZDQwYmUxNmI4MGE5MitBUCt0Y3A6Ly8wYWIxNTA4Yi5pcC5nZXc0LnNwb3RpZnkubmV0OjUwMDIrRDhGMDE4RUM0NEJCOThGRjVEODg2Mjg3N0Y3NDIxMTFBOTM5N0JDRjJCNjZEM0VBNDhENDNEMEE4OEEwOTZCMg%3D%3D", status_code: 200, payload: [] } } ``` What other information can I provide to help investigating?
Author
Owner

@michaelherger commented on GitHub (Aug 13, 2025):

Could someone please come up with an updated examples/get_token.rs using login5 as a POC?

<!-- gh-comment-id:3182389340 --> @michaelherger commented on GitHub (Aug 13, 2025): Could someone please come up with an updated `examples/get_token.rs` using `login5` as a POC?
Author
Owner

@ltcmdrkeen commented on GitHub (Aug 13, 2025):

I did a PoC for integrating Login5 in librespot-java here: https://github.com/librespot-org/librespot-java/issues/1099

<!-- gh-comment-id:3182579561 --> @ltcmdrkeen commented on GitHub (Aug 13, 2025): I did a PoC for integrating Login5 in librespot-java here: https://github.com/librespot-org/librespot-java/issues/1099
Author
Owner

@photovoltex commented on GitHub (Aug 13, 2025):

@michaelherger, this (github.com/photovoltex/librespot@59d0228a65) should already do the trick. But I didn't tested it and can only do that in around 12h

<!-- gh-comment-id:3182630616 --> @photovoltex commented on GitHub (Aug 13, 2025): @michaelherger, this (https://github.com/photovoltex/librespot/commit/59d0228a6508f1a3eaf3332948b02b56787881f6) should already do the trick. But I didn't tested it and can only do that in around 12h
Author
Owner

@kingosticks commented on GitHub (Aug 13, 2025):

Is it worth investigating keymaster issues? What does it provide that login5 doesn't? I'm not keen unless there's a good reason.

If we are going to investigate them please provide the full log we explicitly ask for.

If we are not going to investigate we should deprecate keymaster.

<!-- gh-comment-id:3182704432 --> @kingosticks commented on GitHub (Aug 13, 2025): Is it worth investigating keymaster issues? What does it provide that login5 doesn't? I'm not keen unless there's a good reason. If we are going to investigate them please provide the full log we explicitly ask for. If we are not going to investigate we should deprecate keymaster.
Author
Owner

@photovoltex commented on GitHub (Aug 13, 2025):

I looked a bit into it yesterday but didn't get too far. What I got from the quick investigation was that we use the ap for way more than the current official desktop client does. So I wouldn't be surprised if the keymaster isn't used anymore, but I couldn't find that out yet.

<!-- gh-comment-id:3183531956 --> @photovoltex commented on GitHub (Aug 13, 2025): I looked a bit into it yesterday but didn't get too far. What I got from the quick investigation was that we use the ap for way more than the current official desktop client does. So I wouldn't be surprised if the keymaster isn't used anymore, but I couldn't find that out yet.
Author
Owner

@urknall commented on GitHub (Aug 13, 2025):

Is it worth investigating keymaster issues? What does it provide that login5 doesn't? I'm not keen unless there's a good reason.

If we are going to investigate them please provide the full log we explicitly ask for.

If we are not going to investigate we should deprecate keymaster.

Question from a beginner: [core] Add get_token_with_client_id() to get a token for a specific client ID:

get_token_with_client_id() and get_token() are still using keymaster?
so how can i get a token for a specific client ID with login5?

or does librespot provide another way to get a token with a client_id that i set as parameter via oauth maybe?

<!-- gh-comment-id:3186173027 --> @urknall commented on GitHub (Aug 13, 2025): > Is it worth investigating keymaster issues? What does it provide that login5 doesn't? I'm not keen unless there's a good reason. > > If we are going to investigate them please provide the full log we explicitly ask for. > > If we are not going to investigate we should deprecate keymaster. Question from a beginner: [core] Add get_token_with_client_id() to get a token for a specific client ID: get_token_with_client_id() and get_token() are still using keymaster? so how can i get a token for a specific client ID with login5? or does librespot provide another way to get a token with a client_id that i set as parameter via oauth maybe?
Author
Owner

@photovoltex commented on GitHub (Aug 14, 2025):

In a previous comment I explain the changes necessary. One of them has a commit attached where you can see the changes in action.

<!-- gh-comment-id:3187063647 --> @photovoltex commented on GitHub (Aug 14, 2025): In a previous comment I explain the changes necessary. One of them has a commit attached where you can see the changes in action.
Author
Owner

@kingosticks commented on GitHub (Aug 14, 2025):

You can see the login5 code uses the client id from the session. There are also session methods to change the client id. Does that work? I can't remember. Go try it and tell us.

<!-- gh-comment-id:3187121149 --> @kingosticks commented on GitHub (Aug 14, 2025): You can see the login5 code uses the client id from the session. There are also session methods to change the client id. Does that work? I can't remember. Go try it and tell us.
Author
Owner

@photovoltex commented on GitHub (Aug 14, 2025):

Oh I missunderstood the question. I think I never tested it with other client_id's. But working with login5 is quite pin pointing, one wrong variable and it would report a generalized error, so I would be supprised if custom id's work.

<!-- gh-comment-id:3187211639 --> @photovoltex commented on GitHub (Aug 14, 2025): Oh I missunderstood the question. I think I never tested it with other client_id's. But working with login5 is quite pin pointing, one wrong variable and it would report a generalized error, so I would be supprised if custom id's work.
Author
Owner

@kingosticks commented on GitHub (Aug 14, 2025):

Oh I missunderstood the question. I think I never tested it with other client_id's. But working with login5 is quite pin pointing, one wrong variable and it would report a generalized error, so I would be supprised if custom id's work.

Me too. I thought it was locked down to Spotify's IDs but might be remembering wrong. Worth trying.

<!-- gh-comment-id:3187350272 --> @kingosticks commented on GitHub (Aug 14, 2025): > Oh I missunderstood the question. I think I never tested it with other client_id's. But working with login5 is quite pin pointing, one wrong variable and it would report a generalized error, so I would be supprised if custom id's work. Me too. I thought it was locked down to Spotify's IDs but might be remembering wrong. Worth trying.
Author
Owner

@urknall commented on GitHub (Aug 14, 2025):

i tried yesterday to manually set the client_id for the session, but i got an error. so i guess only "official" ids are supported.

<!-- gh-comment-id:3187383619 --> @urknall commented on GitHub (Aug 14, 2025): i tried yesterday to manually set the client_id for the session, but i got an error. so i guess only "official" ids are supported.
Author
Owner

@urknall commented on GitHub (Aug 14, 2025):

so right now that keymaster isn't working any more (probably depecreated) librespot is not able to get a token for a specific client, that the user has generated in the spotify dashboard?

<!-- gh-comment-id:3187452377 --> @urknall commented on GitHub (Aug 14, 2025): so right now that keymaster isn't working any more (probably depecreated) librespot is not able to get a token for a specific client, that the user has generated in the spotify dashboard?
Author
Owner

@kingosticks commented on GitHub (Aug 14, 2025):

That's annoying if true. But you can just use their client ID for everything you do.... Given how hell-bent they are on screwing over legit devs I see no reason to play by their rules w.r.t this.

<!-- gh-comment-id:3187871478 --> @kingosticks commented on GitHub (Aug 14, 2025): That's annoying if true. But you can just use their client ID for everything you do.... Given how hell-bent they are on screwing over legit devs I see no reason to play by their rules w.r.t this.
Author
Owner

@urknall commented on GitHub (Aug 14, 2025):

you could be running in quota or rate limit problems without your own client_id when doing alot of web api requests.

this could be a way to get a token for your own client_id:

https://developer.spotify.com/documentation/web-api/tutorials/code-pkce-flow

<!-- gh-comment-id:3187912017 --> @urknall commented on GitHub (Aug 14, 2025): you could be running in quota or rate limit problems without your own client_id when doing alot of web api requests. this could be a way to get a token for your own client_id: https://developer.spotify.com/documentation/web-api/tutorials/code-pkce-flow
Author
Owner

@kingosticks commented on GitHub (Aug 14, 2025):

I don't understand what you are saying there, but yes, anyone is free to implement the regular Spotify OAuth flow themselves. We are not going to provide a wrapper around that.

Just remember that any client_id obtained from Spotify in the last few months is restricted in terms of endpoint access and quota.

you could be running in quota or rate limit problems without your own client_id when doing alot of web api requests.

I find it extremely doubtful you would hit quota limits using Spotify's special client ID. It's used by millions of people.

<!-- gh-comment-id:3187943782 --> @kingosticks commented on GitHub (Aug 14, 2025): I don't understand what you are saying there, but yes, anyone is free to implement the regular Spotify OAuth flow themselves. We are not going to provide a wrapper around that. Just remember that any client_id obtained from Spotify in the last few months is restricted in terms of endpoint access and quota. > you could be running in quota or rate limit problems without your own client_id when doing alot of web api requests. I find it extremely doubtful you would hit quota limits using Spotify's special client ID. It's used by millions of people.
Author
Owner

@urknall commented on GitHub (Aug 14, 2025):

i am only refering to the quota modes and rate limits in the spotify api documentation

<!-- gh-comment-id:3188014137 --> @urknall commented on GitHub (Aug 14, 2025): i am only refering to the quota modes and rate limits in the spotify api documentation
Author
Owner

@michaelherger commented on GitHub (Aug 14, 2025):

i am only refering to the quota modes and rate limits in the spotify api documentation

This likely has nothing to do with Librespot's interaction with Spotify's servers. Let's see what the next weeks will bring.

<!-- gh-comment-id:3188051859 --> @michaelherger commented on GitHub (Aug 14, 2025): > i am only refering to the quota modes and rate limits in the spotify api documentation This likely has nothing to do with Librespot's interaction with Spotify's servers. Let's see what the next weeks will bring.
Author
Owner

@urknall commented on GitHub (Aug 14, 2025):

after reading the quota and rate limit parts of the api documentation again, you both might be right.

when librespot is using official clients spotify client ids, that should not be a problem.

<!-- gh-comment-id:3188063273 --> @urknall commented on GitHub (Aug 14, 2025): after reading the quota and rate limit parts of the api documentation again, you both might be right. when librespot is using official clients spotify client ids, that should not be a problem.
Author
Owner

@kingosticks commented on GitHub (Aug 14, 2025):

The only thing left to do here is to deprecate keymaster or not. Ideally someone needs to have a quick play and decide if it really is entirely broken now (thanks Spotify) or did the usage requirements change. I don't think any of the Mercury endpoints get any love from Spotify so I'd imagine it's the former. Dumping the official client Mercury traffic might help answer this.

<!-- gh-comment-id:3188123661 --> @kingosticks commented on GitHub (Aug 14, 2025): The only thing left to do here is to deprecate keymaster or not. Ideally someone needs to have a quick play and decide if it really is entirely broken now (thanks Spotify) or did the usage requirements change. I don't think any of the Mercury endpoints get any love from Spotify so I'd imagine it's the former. Dumping the official client Mercury traffic might help answer this.
Author
Owner

@roderickvd commented on GitHub (Aug 15, 2025):

Don’t we still need Mercury to get the track encryption keys? Until we’ve got a clean implementation of the HTTP endpoint for it.

<!-- gh-comment-id:3190815496 --> @roderickvd commented on GitHub (Aug 15, 2025): Don’t we still need Mercury to get the track encryption keys? Until we’ve got a clean implementation of the HTTP endpoint for it.
Author
Owner

@kingosticks commented on GitHub (Aug 15, 2025):

I only meant we could switch out hm://keymaster/token with login5 in TokenProvider. Am I forgetting why that would impact getting track encryption keys?

Although, you raise a good point that working on using the HTTP endpoint for encryption keys would be a good thing to do.

<!-- gh-comment-id:3191671684 --> @kingosticks commented on GitHub (Aug 15, 2025): I only meant we could switch out `hm://keymaster/token` with login5 in `TokenProvider`. Am I forgetting why that would impact getting track encryption keys? Although, you raise a good point that working on using the HTTP endpoint for encryption keys would be a good thing to do.
Author
Owner

@roderickvd commented on GitHub (Aug 15, 2025):

I only meant we could switch out hm://keymaster/token with login5 in TokenProvider. Am I forgetting why that would impact getting track encryption keys?

No, probably my mix-up.

<!-- gh-comment-id:3191684051 --> @roderickvd commented on GitHub (Aug 15, 2025): > I only meant we could switch out `hm://keymaster/token` with login5 in `TokenProvider`. Am I forgetting why that would impact getting track encryption keys? No, probably my mix-up.
Author
Owner

@photovoltex commented on GitHub (Aug 15, 2025):

Isn't the HTTP encryption the playplay endpoint, if so... that might be hard to get working as some related project that did revers it got taken down already, see es3n1n/re-unplayplay for example.

<!-- gh-comment-id:3191700086 --> @photovoltex commented on GitHub (Aug 15, 2025): Isn't the HTTP encryption the `playplay` endpoint, if so... that might be hard to get working as some related project that did revers it got taken down already, see es3n1n/re-unplayplay for example.
Author
Owner

@brzaz228 commented on GitHub (Aug 15, 2025):

after reading the quota and rate limit parts of the api documentation again, you both might be right.

when librespot is using official clients spotify client ids, that should not be a problem.

It is not rate limits spotify is blocking some part of the process but not rate limits. I always use in realtime and have the script set have 5 seconds at least between downloads. Spotify also reached out to my personal email when rates got crazy and put a temp ban on my account.

<!-- gh-comment-id:3192130444 --> @brzaz228 commented on GitHub (Aug 15, 2025): > after reading the quota and rate limit parts of the api documentation again, you both might be right. > > when librespot is using official clients spotify client ids, that should not be a problem. It is not rate limits spotify is blocking some part of the process but not rate limits. I always use in realtime and have the script set have 5 seconds at least between downloads. Spotify also reached out to my personal email when rates got crazy and put a temp ban on my account.
Author
Owner

@brzaz228 commented on GitHub (Aug 21, 2025):

Anyone make any progress or any failed attempts they want to update? I tried to alternatively route authentication to web each time for every song but it still didn't work

<!-- gh-comment-id:3211066414 --> @brzaz228 commented on GitHub (Aug 21, 2025): Anyone make any progress or any failed attempts they want to update? I tried to alternatively route authentication to web each time for every song but it still didn't work
Author
Owner

@kingosticks commented on GitHub (Aug 21, 2025):

Can you clarify why the login5 alternative isn't sufficient for you?

<!-- gh-comment-id:3211156088 --> @kingosticks commented on GitHub (Aug 21, 2025): Can you clarify why the login5 alternative isn't sufficient for you?
Author
Owner

@SuisChan commented on GitHub (Sep 21, 2025):

The only thing left to do here is to deprecate keymaster or not. Ideally someone needs to have a quick play and decide if it really is entirely broken now (thanks Spotify) or did the usage requirements change. I don't think any of the Mercury endpoints get any love from Spotify so I'd imagine it's the former. Dumping the official client Mercury traffic might help answer this.

Funny enough, yesterday I was disassembling one of the recent versions of the tv app, and it seems to still rely heavily on hermes and still use keymaster.

So far, I haven't seen any http/s stuff, and everything works over hm://?. From what I've seen, it's compiled using esdk (a newer version than what we see on the official development pages). I can't say for sure, since this was just a static analysis, but in any case, everything I've seen likely confirms my suspicions.
It even seems to be fetching audio files via hermes (not like the old protocol(channels)), but like it's sort of a wrapper around http via hermes connection.

Until I can do dynamic analysis, there's not much more to add

<!-- gh-comment-id:3316060626 --> @SuisChan commented on GitHub (Sep 21, 2025): > The only thing left to do here is to deprecate keymaster or not. Ideally someone needs to have a quick play and decide if it really is entirely broken now (thanks Spotify) or did the usage requirements change. I don't think any of the Mercury endpoints get any love from Spotify so I'd imagine it's the former. Dumping the official client Mercury traffic might help answer this. Funny enough, yesterday I was disassembling one of the recent versions of the tv app, and it seems to still rely heavily on hermes and still use keymaster. So far, I haven't seen any http/s stuff, and everything works over hm://?. From what I've seen, it's compiled using esdk (a newer version than what we see on the official development pages). I can't say for sure, since this was just a static analysis, but in any case, everything I've seen likely confirms my suspicions. It even seems to be fetching audio files via hermes (not like the old protocol(channels)), but like it's sort of a wrapper around http via hermes connection. Until I can do dynamic analysis, there's not much more to add
Author
Owner

@SuisChan commented on GitHub (Sep 23, 2025):

Well, can confirm what I said before, it even fetches the audio URL (storage-resolve) via hm://hwptp/v2/resolve, as well as the keys (still playplay) hm://hwptp/v1/content_encryption_key, and it looks like hm://keymaster/token/authenticated? is still working fine for them.

<!-- gh-comment-id:3324659840 --> @SuisChan commented on GitHub (Sep 23, 2025): Well, can confirm what I said before, it even fetches the audio URL (storage-resolve) via `hm://hwptp/v2/resolve`, as well as the keys (still playplay) `hm://hwptp/v1/content_encryption_key`, and it looks like `hm://keymaster/token/authenticated?` is still working fine for them.
Author
Owner

@photovoltex commented on GitHub (Sep 25, 2025):

So probably our implementation isn't what Spotify expects and blocks it in response then? I saw a similar behaviors with login5 where it was quite picky what it accepted.

<!-- gh-comment-id:3332299428 --> @photovoltex commented on GitHub (Sep 25, 2025): So probably our implementation isn't what Spotify expects and blocks it in response then? I saw a similar behaviors with login5 where it was quite picky what it accepted.
Author
Owner

@SuisChan commented on GitHub (Sep 25, 2025):

So probably our implementation isn't what Spotify expects and blocks it in response then?

I don't know what to think. Everything seems to be working, but the response shows an empty permissions list. Does that change anything? I have no idea.
One more thing: the client gets all the necessary info via the hm:// destination and doesn't seem to use http at all, but receives encrypted blobs, keys, events - basically, everything it needs. So why get a bearer token at all? That's the question.
I might be wrong, but... I didn't intercept the http traffic (if there is any at all), only the encrypted stream, so who knows.

I'm not sure if this is worth investigating, but anyway

hexdump (keymaster & storage-resolve)
request (cmd+length & body)
00000000  b2 00 71                                         |².q|

00000000  00 04 00 04 00 00 01 00 01 00 66 0a 5f 68 6d 3a  |..........f._hm:|
00000010  2f 2f 6b 65 79 6d 61 73 74 65 72 2f 74 6f 6b 65  |//keymaster/toke|
00000020  6e 2f 61 75 74 68 65 6e 74 69 63 61 74 65 64 3f  |n/authenticated?|
00000030  63 6c 69 65 6e 74 5f 69 64 3d 37 35 36 61 35 32  |client_id=756a52|
00000040  32 64 39 66 31 36 34 38 62 38 39 65 37 36 65 38  |2d9f1648b89e76e8|
00000050  30 62 65 36 35 34 34 35 36 61 26 73 63 6f 70 65  |0be654456a&scope|
00000060  3d 75 6d 62 72 65 6c 6c 61 2d 74 76 1a 03 47 45  |=umbrella-tv..GE|
00000070  54                                               |T|

response
00000000  b2 02 91                                         |²..|

00000000  00 04 00 01 00 02 01 00 02 00 7d 0a 5f 68 6d 3a  |..........}._hm:|
00000010  2f 2f 6b 65 79 6d 61 73 74 65 72 2f 74 6f 6b 65  |//keymaster/toke|
00000020  6e 2f 61 75 74 68 65 6e 74 69 63 61 74 65 64 3f  |n/authenticated?|
00000030  63 6c 69 65 6e 74 5f 69 64 3d 37 35 36 61 35 32  |client_id=756a52|
00000040  32 64 39 66 31 36 34 38 62 38 39 65 37 36 65 38  |2d9f1648b89e76e8|
00000050  30 62 65 36 35 34 34 35 36 61 26 73 63 6f 70 65  |0be654456a&scope|
00000060  3d 75 6d 62 72 65 6c 6c 61 2d 74 76 12 00 20 90  |=umbrella-tv.. .|
00000070  03 32 15 0a 0e 43 6f 6e 74 65 6e 74 2d 4c 65 6e  |.2...Content-Len|
00000080  67 74 68 12 03 35 32 33 02 0b 7b 22 61 63 63 65  |gth..523..{"acce|
00000090  73 73 54 6f 6b 65 6e 22 3a 22 54 4f 4b 45 4e 5f  |ssToken":"TOKEN_|
000000a0  52 45 44 41 43 54 45 44 22 2c 22 65 78 70 69 72  |REDACTED","expir|
000000b0  65 73 49 6e 22 3a 33 36 30 30 2c 22 74 6f 6b 65  |esIn":3600,"toke|
000000c0  6e 54 79 70 65 22 3a 22 42 65 61 72 65 72 22 2c  |nType":"Bearer",|
000000d0  22 73 63 6f 70 65 22 3a 5b 22 75 6d 62 72 65 6c  |"scope":["umbrel|
000000e0  6c 61 2d 74 76 22 5d 2c 22 70 65 72 6d 69 73 73  |la-tv"],"permiss|
000000f0  69 6f 6e 73 22 3a 5b 5d 2c 22 73 65 73 73 69 6f  |ions":[],"sessio|
00000100  6e 49 64 22 3a 22 33 36 65 36 64 31 32 33 2d 64  |nId":"36e6d123-d|
00000110  34 38 35 2d 34 32 39 35 2d 38 39 31 31 2d 32 33  |485-4295-8911-23|
00000120  34 35 39 31 32 64 62 32 33 39 22 7d              |45912db239"}|


storage-resolve 

request
00000000  b2 00 53                                         |².S|

00000000  00 04 00 0a 00 02 01 00 01 00 48 0a 41 68 6d 3a  |..........H.Ahm:|
00000010  2f 2f 68 77 70 74 70 2f 76 32 2f 72 65 73 6f 6c  |//hwptp/v2/resol|
00000020  76 65 2f 33 65 39 63 33 34 64 36 37 66 35 63 35  |ve/3e9c34d67f5c5|
00000030  35 64 33 62 63 65 65 30 30 30 61 31 31 63 61 66  |5d3bcee000a11caf|
00000040  61 39 63 37 31 64 38 35 37 36 65 2f 31 2f 1a 03  |a9c71d8576e/1/..|
00000050  47 45 54                                         |GET|

response
00000000  b2 01 b9                                         |².¹|

00000000  00 04 00 0a 00 02 01 00 02 00 5f 0a 41 68 6d 3a  |.........._.Ahm:|
00000010  2f 2f 68 77 70 74 70 2f 76 32 2f 72 65 73 6f 6c  |//hwptp/v2/resol|
00000020  76 65 2f 33 65 39 63 33 34 64 36 37 66 35 63 35  |ve/3e9c34d67f5c5|
00000030  35 64 33 62 63 65 65 30 30 30 61 31 31 63 61 66  |5d3bcee000a11caf|
00000040  61 39 63 37 31 64 38 35 37 36 65 2f 31 2f 12 00  |a9c71d8576e/1/..|
00000050  20 90 03 32 15 0a 0e 43 6f 6e 74 65 6e 74 2d 4c  | ..2...Content-L|
00000060  65 6e 67 74 68 12 03 33 33 33 01 4d 08 00 12 7f  |ength..333.M....|
00000070  68 74 74 70 73 3a 2f 2f 61 75 64 69 6f 2d 66 61  |https://audio-fa|
00000080  2e 73 63 64 6e 2e 63 6f 2f 61 75 64 69 6f 2f 33  |.scdn.co/audio/3|
00000090  65 39 63 33 34 64 36 37 66 35 63 35 35 64 33 62  |e9c34d67f5c55d3b|
000000a0  63 65 65 30 30 30 61 31 31 63 61 66 61 39 63 37  |cee000a11cafa9c7|
000000b0  31 64 38 35 37 36 65 3f 31 37 35 38 37 32 39 31  |1d8576e?17587291|
000000c0  35 38 5f 52 46 69 47 63 6e 67 58 67 46 78 51 69  |58_RFiGcngXgFxQi|
000000d0  62 42 47 6f 6d 4c 48 64 74 51 49 45 5f 41 6f 6d  |bBGomLHdtQIE_Aom|
000000e0  4c 75 6e 66 72 43 56 49 30 43 57 55 6e 30 3d 12  |LunfrCVI0CWUn0=.|
000000f0  ad 01 68 74 74 70 73 3a 2f 2f 61 75 64 69 6f 2d  |..https://audio-|
00000100  61 6b 2e 73 70 6f 74 69 66 79 63 64 6e 2e 63 6f  |ak.spotifycdn.co|
00000110  6d 2f 61 75 64 69 6f 2f 33 65 39 63 33 34 64 36  |m/audio/3e9c34d6|
00000120  37 66 35 63 35 35 64 33 62 63 65 65 30 30 30 61  |7f5c55d3bcee000a|
00000130  31 31 63 61 66 61 39 63 37 31 64 38 35 37 36 65  |11cafa9c71d8576e|
00000140  3f 5f 5f 74 6f 6b 65 6e 5f 5f 3d 65 78 70 3d 31  |?__token__=exp=1|
00000150  37 35 38 37 32 39 31 35 38 7e 68 6d 61 63 3d 34  |758729158~hmac=4|
00000160  62 64 61 62 65 33 62 30 33 64 35 32 38 38 39 65  |bdabe3b03d52889e|
00000170  64 38 36 38 64 65 35 30 65 61 33 31 33 34 32 30  |d868de50ea313420|
00000180  61 30 65 31 32 64 35 66 38 66 34 36 36 33 38 35  |a0e12d5f8f466385|
00000190  36 31 36 64 39 64 37 36 38 33 36 35 34 30 34 22  |616d9d768365404"|
000001a0  14 3e 9c 34 d6 7f 5c 55 d3 bc ee 00 0a 11 ca fa  |.>.4Ö.\UÓ¼î...Êú|
000001b0  9c 71 d8 57 6e 28 80 a3 05                       |.qØWn(.£.|




<!-- gh-comment-id:3334747308 --> @SuisChan commented on GitHub (Sep 25, 2025): > So probably our implementation isn't what Spotify expects and blocks it in response then? I don't know what to think. Everything seems to be working, but the response shows an empty permissions list. Does that change anything? I have no idea. One more thing: the client gets all the necessary info via the `hm://` destination and doesn't seem to use http at all, but receives encrypted blobs, keys, events - basically, everything it needs. So why get a bearer token at all? That's the question. I might be wrong, but... I didn't intercept the http traffic (if there is any at all), only the encrypted stream, so who knows. I'm not sure if this is worth investigating, but anyway <details> <summary>hexdump (keymaster & storage-resolve)</summary> ```text request (cmd+length & body) 00000000 b2 00 71 |².q| 00000000 00 04 00 04 00 00 01 00 01 00 66 0a 5f 68 6d 3a |..........f._hm:| 00000010 2f 2f 6b 65 79 6d 61 73 74 65 72 2f 74 6f 6b 65 |//keymaster/toke| 00000020 6e 2f 61 75 74 68 65 6e 74 69 63 61 74 65 64 3f |n/authenticated?| 00000030 63 6c 69 65 6e 74 5f 69 64 3d 37 35 36 61 35 32 |client_id=756a52| 00000040 32 64 39 66 31 36 34 38 62 38 39 65 37 36 65 38 |2d9f1648b89e76e8| 00000050 30 62 65 36 35 34 34 35 36 61 26 73 63 6f 70 65 |0be654456a&scope| 00000060 3d 75 6d 62 72 65 6c 6c 61 2d 74 76 1a 03 47 45 |=umbrella-tv..GE| 00000070 54 |T| response 00000000 b2 02 91 |²..| 00000000 00 04 00 01 00 02 01 00 02 00 7d 0a 5f 68 6d 3a |..........}._hm:| 00000010 2f 2f 6b 65 79 6d 61 73 74 65 72 2f 74 6f 6b 65 |//keymaster/toke| 00000020 6e 2f 61 75 74 68 65 6e 74 69 63 61 74 65 64 3f |n/authenticated?| 00000030 63 6c 69 65 6e 74 5f 69 64 3d 37 35 36 61 35 32 |client_id=756a52| 00000040 32 64 39 66 31 36 34 38 62 38 39 65 37 36 65 38 |2d9f1648b89e76e8| 00000050 30 62 65 36 35 34 34 35 36 61 26 73 63 6f 70 65 |0be654456a&scope| 00000060 3d 75 6d 62 72 65 6c 6c 61 2d 74 76 12 00 20 90 |=umbrella-tv.. .| 00000070 03 32 15 0a 0e 43 6f 6e 74 65 6e 74 2d 4c 65 6e |.2...Content-Len| 00000080 67 74 68 12 03 35 32 33 02 0b 7b 22 61 63 63 65 |gth..523..{"acce| 00000090 73 73 54 6f 6b 65 6e 22 3a 22 54 4f 4b 45 4e 5f |ssToken":"TOKEN_| 000000a0 52 45 44 41 43 54 45 44 22 2c 22 65 78 70 69 72 |REDACTED","expir| 000000b0 65 73 49 6e 22 3a 33 36 30 30 2c 22 74 6f 6b 65 |esIn":3600,"toke| 000000c0 6e 54 79 70 65 22 3a 22 42 65 61 72 65 72 22 2c |nType":"Bearer",| 000000d0 22 73 63 6f 70 65 22 3a 5b 22 75 6d 62 72 65 6c |"scope":["umbrel| 000000e0 6c 61 2d 74 76 22 5d 2c 22 70 65 72 6d 69 73 73 |la-tv"],"permiss| 000000f0 69 6f 6e 73 22 3a 5b 5d 2c 22 73 65 73 73 69 6f |ions":[],"sessio| 00000100 6e 49 64 22 3a 22 33 36 65 36 64 31 32 33 2d 64 |nId":"36e6d123-d| 00000110 34 38 35 2d 34 32 39 35 2d 38 39 31 31 2d 32 33 |485-4295-8911-23| 00000120 34 35 39 31 32 64 62 32 33 39 22 7d |45912db239"}| storage-resolve request 00000000 b2 00 53 |².S| 00000000 00 04 00 0a 00 02 01 00 01 00 48 0a 41 68 6d 3a |..........H.Ahm:| 00000010 2f 2f 68 77 70 74 70 2f 76 32 2f 72 65 73 6f 6c |//hwptp/v2/resol| 00000020 76 65 2f 33 65 39 63 33 34 64 36 37 66 35 63 35 |ve/3e9c34d67f5c5| 00000030 35 64 33 62 63 65 65 30 30 30 61 31 31 63 61 66 |5d3bcee000a11caf| 00000040 61 39 63 37 31 64 38 35 37 36 65 2f 31 2f 1a 03 |a9c71d8576e/1/..| 00000050 47 45 54 |GET| response 00000000 b2 01 b9 |².¹| 00000000 00 04 00 0a 00 02 01 00 02 00 5f 0a 41 68 6d 3a |.........._.Ahm:| 00000010 2f 2f 68 77 70 74 70 2f 76 32 2f 72 65 73 6f 6c |//hwptp/v2/resol| 00000020 76 65 2f 33 65 39 63 33 34 64 36 37 66 35 63 35 |ve/3e9c34d67f5c5| 00000030 35 64 33 62 63 65 65 30 30 30 61 31 31 63 61 66 |5d3bcee000a11caf| 00000040 61 39 63 37 31 64 38 35 37 36 65 2f 31 2f 12 00 |a9c71d8576e/1/..| 00000050 20 90 03 32 15 0a 0e 43 6f 6e 74 65 6e 74 2d 4c | ..2...Content-L| 00000060 65 6e 67 74 68 12 03 33 33 33 01 4d 08 00 12 7f |ength..333.M....| 00000070 68 74 74 70 73 3a 2f 2f 61 75 64 69 6f 2d 66 61 |https://audio-fa| 00000080 2e 73 63 64 6e 2e 63 6f 2f 61 75 64 69 6f 2f 33 |.scdn.co/audio/3| 00000090 65 39 63 33 34 64 36 37 66 35 63 35 35 64 33 62 |e9c34d67f5c55d3b| 000000a0 63 65 65 30 30 30 61 31 31 63 61 66 61 39 63 37 |cee000a11cafa9c7| 000000b0 31 64 38 35 37 36 65 3f 31 37 35 38 37 32 39 31 |1d8576e?17587291| 000000c0 35 38 5f 52 46 69 47 63 6e 67 58 67 46 78 51 69 |58_RFiGcngXgFxQi| 000000d0 62 42 47 6f 6d 4c 48 64 74 51 49 45 5f 41 6f 6d |bBGomLHdtQIE_Aom| 000000e0 4c 75 6e 66 72 43 56 49 30 43 57 55 6e 30 3d 12 |LunfrCVI0CWUn0=.| 000000f0 ad 01 68 74 74 70 73 3a 2f 2f 61 75 64 69 6f 2d |..https://audio-| 00000100 61 6b 2e 73 70 6f 74 69 66 79 63 64 6e 2e 63 6f |ak.spotifycdn.co| 00000110 6d 2f 61 75 64 69 6f 2f 33 65 39 63 33 34 64 36 |m/audio/3e9c34d6| 00000120 37 66 35 63 35 35 64 33 62 63 65 65 30 30 30 61 |7f5c55d3bcee000a| 00000130 31 31 63 61 66 61 39 63 37 31 64 38 35 37 36 65 |11cafa9c71d8576e| 00000140 3f 5f 5f 74 6f 6b 65 6e 5f 5f 3d 65 78 70 3d 31 |?__token__=exp=1| 00000150 37 35 38 37 32 39 31 35 38 7e 68 6d 61 63 3d 34 |758729158~hmac=4| 00000160 62 64 61 62 65 33 62 30 33 64 35 32 38 38 39 65 |bdabe3b03d52889e| 00000170 64 38 36 38 64 65 35 30 65 61 33 31 33 34 32 30 |d868de50ea313420| 00000180 61 30 65 31 32 64 35 66 38 66 34 36 36 33 38 35 |a0e12d5f8f466385| 00000190 36 31 36 64 39 64 37 36 38 33 36 35 34 30 34 22 |616d9d768365404"| 000001a0 14 3e 9c 34 d6 7f 5c 55 d3 bc ee 00 0a 11 ca fa |.>.4Ö.\UÓ¼î...Êú| 000001b0 9c 71 d8 57 6e 28 80 a3 05 |.qØWn(.£.|
Author
Owner

@brzaz228 commented on GitHub (Oct 21, 2025):

Anyone make any progress?

<!-- gh-comment-id:3428963646 --> @brzaz228 commented on GitHub (Oct 21, 2025): Anyone make any progress?
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/librespot#691
No description provided.