-
Notifications
You must be signed in to change notification settings - Fork 954
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
Allow for total headless mode by instructing the user to open the URL in a browser. #528
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice one. Just left a comment about something I am not sure about.
Also can you please add a quick entry to the CHANGELOG?
if open_browser: | ||
self._open_auth_url() | ||
prompt = "Enter the URL you were redirected to: " | ||
else: | ||
url = self.get_authorize_url() | ||
prompt = ( | ||
"Go to the following URL: {}\n" | ||
"Enter the URL you were redirected to: ".format(url) | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why this condition? Aren't both sides doing the same thing?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the case where we want to open the browser, the method _open_auth_url
will launch the browser with the authorization URL. Otherwise, this authorization URL is printed out to stdout and the user needs to figure out how to open it by himself. In both cases we ask the user for the final URL she has been redirected to.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh sure, I just realised this not only adds an option to force pasting the resulting URL, but it also prints the initial URL 👍
I'm jumping on here because headless authentication with Spotify's API has been something I've been trying to get down for awhile... Is this PR really introducing total headless authentication? In both cases, user input is required. A truly headless authentication flow would be completely automated, and this is very difficult to do since Spotify's OAuth flow requires a log in with a browser. Thus, some sort of browser driver (like Selenium) is required to submit credentials and literally "click" the submit button on the page. As far as I know, all but the Client Credentials Authorization Flow require some sort of user interaction - which must be automated via browser driver to truly become headless |
@nleroy917 you are right, this is more of a "browserless" mode, or at least opening a browser on the same machine is not being forced |
I wonder if a headless mode could ever be implemented without compromising the scale of spotipy. It’s advertised as “A light weight Python library for the Spotify Web API”, but almost all browser drivers I see that have javascript capabilities require some external dependencies like chromium or webkit... they are usually heavy like Selenium. This isn’t really in the spirit of spotipy. I’ve found a few options:
Some are deprecated, though, and others are hard to work with. |
Well it all comes down to a matter of terminology anyway, but I still think that "headless" is a proper description whereas "browserless" is not. Headless merely means that it doesn't use a graphical interface, which is the case here since all the program uses is stdout and stdin. "Browserless" would misleading since the user still has to open the URL in a browser somehow. I've updated the changelog anyway to something more factual to resolve any ambiguity. |
@nleroy917 Even using a browser driver would still need to have either the username/password or an authentication cookie of a given user to load the authorization screen for this user. If one is willing to transfer such secrets to a remote machine beforehand, why not pass the authorization step on a local machine beforehand, and then transfer the OAuth token to the remote machine. |
You make a good point. But, I think it's more flexible (and scales better) to just type my username and password as environment variables and have Selenium do the work for me, rather than run a script locally and copy and paste a key into my PaaS dashboard every time I lose my authorization and refresh token |
The point of using OAuth is that there is no middleman between the user and Spotify. Since the user only gives the password to spotify.com, even the library (in this case spotipy) cannot see the password. It's definitely possible to hack something that allows direct password login, however it's highly disrecommended:
As a user I think being redirected to spotify.com in a browser at least once is fine, particularly if the user is already signed in:
However I understand the frustration as a developer who is trying to run a script remotely and continuously. I've overcome this issue by caching the spotify token into DynamoDB (code here). Basically:
Hopefully we can implement this into spotipy one day as part of #51. Someone also suggested Redis! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just one thing to remove
if open_browser: | ||
self._open_auth_url() | ||
prompt = "Enter the URL you were redirected to: " | ||
else: | ||
url = self.get_authorize_url() | ||
prompt = ( | ||
"Go to the following URL: {}\n" | ||
"Enter the URL you were redirected to: ".format(url) | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh sure, I just realised this not only adds an option to force pasting the resulting URL, but it also prints the initial URL 👍
spotipy/oauth2.py
Outdated
@@ -421,7 +433,7 @@ def get_auth_response(self): | |||
|
|||
logger.info('Paste that url you were directed to in order to ' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like we should remove this line, as we already print "Enter the URL you were redirected to: " in _get_auth_response_interactive
Thanks a lot for this @foobuzz, merging it now will close 3 issues at once! |
This adds a new option
open_browser
inget_auth_response
which, if False, will simply print the authorization URL and ask the user to visit it and paste the URL is has been redirected to (existing interactive way to get the authorization code). This allows the setup of Spotipy on a remote machine (e.g. Raspberry Pi or VPS) in a fully headless way.open_browser
defaults to True for backward compatibility.