Source code for spotipie.auth.utils
__all__ = ['get_user_authorization', 'prompt_for_user_authorization']
import logging
import time
import webbrowser
from queue import Empty, Queue
from threading import Thread
from typing import Optional, Union
import requests
from spotipie.auth import (
AuthorizationCodeSession,
Flow,
ImplicitGrantSession,
OAuth2Token
)
from spotipie.exceptions import (
AccessDenied,
AuthorizationException,
AuthorizationTimeout
)
from spotipie.utils import pretty
UserOAuth2Session = Union[AuthorizationCodeSession, ImplicitGrantSession]
logger = logging.getLogger(__name__)
def _open_in_browser(url):
try:
webbrowser.open(url)
print("Successfully opened the browser!")
except Exception as exc:
print("Couldn't open the web browser automatically: %s\n", str(exc))
print("Please, open the following link in your browser: %s" % url)
[docs]def get_user_authorization(session: UserOAuth2Session,
app_name: Optional[str] = None,
port: int = 1234, timeout: int = 120) -> 'OAuth2Token':
"""
Asks the user to authorize the authorize your app. The authorization flow depends
on the type of session to pass. As a side effect, the obtained token is stored
in the session.
This function launches a flask app listening to ``http://localhost:{port}/callback``
in a new thread, which once the authorization is completed, sends the received token
to the main thread through a messaging queue; in this way, this function does not require
the user to manually copy and paste the callback URL into your app.
**IMPORTANT:** to use this function
- you need to install optional dependencies through: ``pip install spotipie[auth-app]``
- you need to whitelist ``http://localhost:{port}/callback`` in your app callback URLs.
Args:
session:
OAuth2 session to authorize
app_name:
name of your application (used in the "success.html" page)
port:
TCP port the server listen to
timeout:
shutdown the server app after this time (in seconds)
Returns:
OAuth2Token
See Also:
"""
from spotipie.auth._app import start_authorization_app
messaging_queue: Queue = Queue()
app_url = 'http://localhost:%d' % port
server_thread = Thread(
target=start_authorization_app,
daemon=True,
kwargs=dict(
port=port, message_queue=messaging_queue,
scope=session.scope,
client_id=session.client_id,
client_secret=getattr(session, 'client_secret', None),
client_app_name=app_name, debug=False)
)
server_thread.start()
_open_in_browser(app_url + '/authorize')
try:
token = messaging_queue.get(block=True, timeout=timeout)
except Empty:
raise AuthorizationTimeout(timeout)
finally:
# delay the app shutdown a little bit so that it can reply to all the requests needed
# to display a web page (html + css)
time.sleep(1)
requests.post(app_url + '/shutdown')
server_thread.join()
logger.debug('Token: ' + pretty(token))
if 'error' in token:
if token['error'] == 'access_denied':
raise AccessDenied
raise AuthorizationException('Error during app authorization: ' + token['error'])
session.token = token
return session.token
[docs]def prompt_for_user_authorization(session: UserOAuth2Session) -> 'OAuth2Token':
"""
Useful for command-line apps, when you don't want to use :func:`get_user_authorization`.
Asks the user to authorize your app through the terminal. It requires the user to
manually copy and paste the callback URL into the terminal.
"""
auth_url, _ = session.authorization_url()
print(f"""
We need your authorization to continue. The authorization uses the OAuth2
protocol. We are going to open the Spotify authorization page in your browser:
{auth_url}
Once you authorize your app, Spotify will redirect you to localhost and
the redirection URL will contain the authorization token. You need to copy
that URL and paste it here.
""")
input('Press Enter to continue...')
_open_in_browser(auth_url)
callback_url = input('Copy the callback URL here: ')
if callback_url.startswith('http:'):
callback_url = 'https' + callback_url[4:]
if session.FLOW == Flow.AUTHORIZATION_CODE:
token = session.fetch_token(callback_url)
else:
token = session.read_token_from_callback_url(callback_url)
logger.debug('Token: ' + pretty(token))
return token
if __name__ == '__main__':
from spotipie.auth import AuthorizationCodeSession, Credentials
credentials = Credentials.from_environment()
session = AuthorizationCodeSession(*credentials, scope='user-library-read')
# token = prompt_for_user_authorization(session)
token = get_user_authorization(session, 'PippoApp')
print('Token:', token)