logo
Published on

Using the Spotify Web API in a Python application

python
Authors

Pre-requisites

Spotify provides different ways to authenticated and/or authorize users in order to access resources on their accounts. In this tutorial, we will look at the Authorization Code Flow method.

NB: This method is NOT suitable for public clients(i.e. Client-side Javascript or single page applications). Only use this for server applications which are not exposed to the public

  • Here is a full working example on github

i. Step 1 - Create a flask application running on localhost

import os

import flask
import requests



HOST_IP_ADDRESS = '127.0.0.1'
HOST_PORT = 9000


# Create a flask application
app = flask.Flask('YOUR_APP_NAME')


# Create a default route
@app.route('/')
def index():
    return 'It works!'



"""
$ This route will redirect the user to the spotify login page

$ Once the user is authenticated, spotify will send an Authorization Code to the specified REDIRECT_URI

$ NB: Make sure to specify all the required SCOPES for the services you intend to use

$ Reference: https://developer.spotify.com/documentation/web-api/tutorials/code-flow
"""
@app.route('/login')
def login():
    authentication_request_params = {
        'response_type': 'code',
        'client_id': os.getenv('CLIENT_ID'),
        'redirect_uri': os.getenv('REDIRECT_URI'),  # In this case we set it to http://localhost:9000/callback
        'scope': 'user-read-email user-read-private user-top-read',
        'state': str(uuid.uuid4()),
        'show_dialog': 'true'
        }

    auth_url = 'https://accounts.spotify.com/authorize/?' + urllib.urlencode(authentication_request_params)

    # Opens the spotify login page using the default browser
    webbrowser.open_new_tab(auth_url)



if __name__ == '__main__':
    app.run(HOST_IP_ADDRESS, HOST_PORT)

ii. Step 2 - Add the authorization callback handler


# .....

def _get_access_token(authorization_code:str):
    spotify_request_access_token_url = 'https://accounts.spotify.com/api/token/?'
    body = {'grant_type': 'authorization_code',
            'code': authorization_code,
            'client_id': os.getenv('CLIENT_ID'), 
            'client_secret': os.getenv('CLIENT_SECRET'),
            'redirect_uri': os.getenv('REDIRECT_URI')
             } 
    response: requests.Response = requests.post(spotify_request_access_token_url, data=body)
    if response.status_code == 200:
        return response.json()

    raise Exception(f'Failed to obtain Access token.Response: {response.text}')



"""Callback route

$ This is the url that the user will be REDIRECTED to after the spotify login screen

$ The URL must match the REDIRECT_URL setting on your spotify developer dashboard

$ Spotify will send back a code which is then used to request an access token through a 'back-chanel'
""" 
@app.route('/callback')
def callback():

    code = flask.request.args.get('code')
    credentials = _get_access_token(authorization_code=code)

    os.environ['token'] = credentials['access_token']

    return f"Authentication successful. Access token: {credentials['access_token']}"


# ....

Step 3 - Test the API (Get Current User's top tracks)


# ....
 
 
 @app.route('/top-tracks')
 def top_tracks():
    root_url = 'https://api.spotify.com/v1/me/top/{tracks}'

    # NB: Add the access token to the request header
    headers = {
        'Authorization': f'Bearer {os.getenv("token")}'
    }
 
    request_params = {
            'time_range': 'medium_term',
            'limit': 20,
            'offset': 0
        }

    # NOTE: This requires the scope 'user-top-read'
    full_url = root_url + urllib.urlencode(request_params)
    response = requests.get(full_url,
                            headers=headers,
                            params=request_params)

    if response.status_code == 200:
        return response.json()
        
    raise Exception(f'API Call to {full_url} failed. {response.text}')
# .....

Conclusion

  • Here is a full working example on github
  • Suggested improvements:
    • Verify the state value on the authentication callback handler
    • Add a token refresh handler
    • Check if token is expired before making a request
    • etc.

Further reading