Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add OAuth token authentication #436

Closed

Conversation

dhenneke
Copy link

This PR adds an option to login with an Spotify OAuth token. Get a token and request the streaming scope.

Start with: librespot --username user --token YOUR_OAUTH_TOKEN

When I use AuthenticationType::AUTHENTICATION_SPOTIFY_TOKEN as authType, the API for some reason replies with an Authentication Type of 0x7. Since I don't know what this value means originally, I just added a placeholder type to the proto file.

@dhenneke dhenneke changed the title Add Oauth token authentication Add OAuth token authentication Feb 16, 2020
@@ -114,6 +114,7 @@ fn setup(args: &[String]) -> Setup {
.optflag("v", "verbose", "Enable verbose output")
.optopt("u", "username", "Username to sign in with", "USERNAME")
.optopt("p", "password", "Password", "PASSWORD")
.optopt("t", "token", "Spotify OAuth token with scope 'streaming'. Use 'user' as username.", "TOKEN")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure this feature warrants a shorthand option.

@@ -24,6 +24,8 @@ enum AuthenticationType {
AUTHENTICATION_STORED_FACEBOOK_CREDENTIALS = 0x2;
AUTHENTICATION_SPOTIFY_TOKEN = 0x3;
AUTHENTICATION_FACEBOOK_TOKEN = 0x4;
// this type is returned when requesting AUTHENTICATION_SPOTIFY_TOKEN
AUTHENTICATION_UNKNOWN = 0x7;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have you had a look at the proto definitions from the official client to see if there is an actual definition for the 0x7 response? I'm hesitant to just slap an unknown definition in, as it is messy and not very readable/maintainable long term if they start to stack up. I know we have (had) a couple in the library, but we generally try to replace them with the actual value from the client once it is available.

Copy link
Author

@dhenneke dhenneke Feb 27, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where can I find the official definitions? I was not aware that they are public.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sashahilton00 I think that those definition files cannot be extracted from the client anymore for some reason. They don't appear when dumping with HearthSim/proto-extractor.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe it should be along these lines - dumped from the client strings.
Also to note, I no longer see the kAuthenticationType mentioned anywhere, and only kAuthenticationTypeCount
credentials.auth_type() < auth::kAuthenticationTypeCount:

obfuscatedSecret
password
blobBase64
autologin
storedSpotifyCredentials
storedFacebookCredentials
spotifyToken
facebookToken
anonymousAccount
storedAnonymousCredentials
storedSpotifyRefreshToken
spotifyPassword
phoneNumber
oneTimeToken

@devgianlu
Copy link
Member

FYI, I tried to implement this in librespot-java with the new protocol and it cannot work because the subsystem needs to create tokens on its own: the server keeps responding with 403 because it hasn't sufficient permission.

@sashahilton00
Copy link
Member

@devgianlu are you saying that you can't use an oauth token with librespot even if it's requested with the streaming scope? I'm assuming there are issues with it being tied to a client_id...

@dhenneke
Copy link
Author

We are using this patch for over two years now and it works flawlessly. We use it for an internal music bot where you log in to a website to start playback. A tool receives a token from the oauth flow and starts librespot with it. The tool uses the token to get the currently playing song and displays it in the website. Playback is controlled by the Spotify app itself where you can select the bot as playback device.

I don’t know whether librespot also uses this token to get details about the playback or to control playback. We do this in our tool by calling the Spotify api where. There we also have a refresh token to rotate it automatically whenever it expires. But the initial librespot sessions stays open.

@devgianlu
Copy link
Member

@devgianlu are you saying that you can't use an oauth token with librespot even if it's requested with the streaming scope? I'm assuming there are issues with it being tied to a client_id...

Yeah, it's probably because of the client_id used. I am not able to request any token at all if authenticating with a token (which makes sense). Problem is that a token is needed to start the websocket connection

@michaelherger
Copy link
Contributor

michaelherger commented Mar 14, 2020

We are using this patch for over two years now and it works flawlessly. We use it for an internal music bot where you log in to a website to start playback. A tool receives a token from the oauth flow and starts librespot with it. The tool uses the token to get the currently playing song and displays it in the website. Playback is controlled by the Spotify app itself where you can select the bot as playback device.

If you're controlling playback using the Spotify app, why would you even need to authenticate librespot beforehand? I'm a bit confused as I'm doing the exact opposite: I'm using librespot to authenticate using the Spotify app, then get the token from librespot to use in my web app... Because authentication using the app is a no brainer and comes for free, where as implementing oauth is a lot of effort...

@dhenneke
Copy link
Author

We are using librespot as playback device and since we use it with multiple accounts we don’t want to know the Spotify account password of the user but use a token that was received via oauth where the user logged in to the official Spotify website

@michaelherger
Copy link
Contributor

michaelherger commented Mar 14, 2020

We are using librespot as playback device and since we use it with multiple accounts we don’t want to know the Spotify account password of the user but use a token that was received via oauth where the user logged in to the official Spotify website

But that's the point: you don't need to authenticate librespot itself. The Spotify app will do this for you! I simply run librespot only giving it a name and a cache folder where there was nothing before. Then I selected it in the Spotify app:

$ target/debug/librespot -n test -c /tmp
[2020-03-14T11:49:44Z INFO  librespot] librespot ef27b4b (2020-03-10). Built on 2020-03-12. Build ID: XpYPEnBm
[2020-03-14T11:49:59Z INFO  librespot_core::session] Connecting to AP "gew1-accesspoint-b-7q0z.ap.spotify.com:4070"
[2020-03-14T11:50:00Z INFO  librespot_core::session] Authenticated as "xxx" !
[2020-03-14T11:50:00Z INFO  librespot_core::session] Country: "xxx"
[2020-03-14T11:50:00Z INFO  librespot_playback::player] Loading <Hymn for the Weekend - Seeb Remix> with Spotify URI <spotify:track:6s3GEN8wK0OMzzzZbXj0fu>
[2020-03-14T11:50:01Z INFO  librespot_playback::player] <Hymn for the Weekend - Seeb Remix> (212647 ms) loaded

After that there would be a file called credentials.json in that cache folder. No need to give username/password anywhere. And yet it's accessible to all users in your network. It can't get any simpler.

@dhenneke
Copy link
Author

But librespot is running in a docker Container on our server where no one has a network connection to, so the Spotify app can‘t discover it and log in. We use it the other way around that librespot logs in the account so that is registered and available in all Spotify apps of the User from the internet

@michaelherger
Copy link
Contributor

michaelherger commented Mar 14, 2020

I might be wrong, but it looks as if you need to run a patched librespot in docker in order to have it configured by some authentication application which wouldn't be required in the first place if you run librespot on its own?

This is not my project, thus my opinion doesn't count at all. But this sounds like adding complexity to the application to make an overly complicated setup work. Just run librespot and you won't need docker nor an additional application to sign in.

@sashahilton00
Copy link
Member

sashahilton00 commented Mar 17, 2020

I’m with @michaelherger here. This functionality at a push might go in the daemon, but in general I don’t think we should add in this functionality as it’s not available on any of the official clients, @devgianlu mentioned that there are possible permission errors, and it feels like this is a workaround for an abnormal setup, in which case it would be more appropriate for OP to maintain a patch.

If no one objects I think we can close this as wontfix?

@dhenneke
Copy link
Author

Thanks for your feedback. I didn't know our setup is so unusual.

I'm also fine with maintaining a fork.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants