0
votes

I'm trying to implement a simple python client for Spotify api. According to the Spotify's Authorization Guide, the app can be authorized in two ways:

  • App Authorization: Spotify authorizes your app to access the Spotify Platform (APIs, SDKs and Widgets).
  • User Authorization: Spotify, as well as the user, grant your app permission to access and/or modify the user’s own data. For information about User Authentication, see User Authentication with OAuth 2.0. Calls to the Spotify Web API require authorization by your application user. To get that authorization, your application generates a call to the Spotify Accounts Service /authorize endpoint, passing along a list of the scopes for which access permission is sought.

CLIENT CREDENTIALS

My first attempt used the app authorization using the oauth2 module from Spotipy, because it requires no token passed, but only client id and client secret, which belong to the app developer.

client.py

import spotipy
from spotipy.oauth2 import SpotifyClientCredentials

class SpotifyWrapper(spotipy.Spotify):
    def category_playlists(self, category, limit=50, offset=0):
        return self._get('browse/categories/%s/playlists' % category,
                         limit=limit,
                         offset=offset)

def get_api_client():
    # create a client authentication request
    client_cred = SpotifyClientCredentials(
        client_id=DevelopmentConfig.SPOTIFY_CLIENT_ID,
        client_secret=DevelopmentConfig.SPOTIFY_CLIENT_SECRET
    )

    # create a spotify client with a bearer token,
    # dynamically re-created if necessary
    return SpotifyWrapper(auth=client_cred.get_access_token())

Then I would import and declare it here:

spotify_utilities.py

from app.resources.spotify.client import get_api_client

sp = get_api_client()

And in order to make requests and get user playlists, pass it like so:

def get_user_playlist(username, sp):
    ids=[]
    playlists = sp.user_playlists(username)
    for playlist in playlists['items']:
        ids.append(playlist['id'])
        print("Name: {}, Number of songs: {}, Playlist ID: {} ".
              format(playlist['name'].encode('utf8'),
                     playlist['tracks']['total'],
                     playlist['id']))
    return ids

This works and will get user content, where the user is the app developer.


IMPLICIT FLOW

Now I want to move on to Implicit Flow, whereby the app asks ANY user who uses for access and scopes, and for that a token will be required.

Once I fetch the token using Javascript, I know I can use it to get user data hitting the API with simple requests:

GET_USER_PROFILE_ENDPOINT = 'https://api.spotify.com/v1/users/{user_id}'
GET_USER_PLAYLISTS_ENDPOINT = 'https://api.spotify.com/v1/users/{user_id}/playlists'

def get_user_profile(token, user_id):
    url = GET_USER_PROFILE_ENDPOINT.format(id=user_id)
    resp = requests.get(url, headers={"Authorization": "Bearer {}".format(token)})
    print (len(resp.json()))
    return resp.json()

def get_user_playlists(token, user_id):
    url = GET_USER_PLAYLISTS_ENDPOINT..format(id=user_id)
    resp = requests.get(url, headers={"Authorization": "Bearer {}".format(token)})
    print (len(resp.json()))
    return resp.json()

but in order to get (and change) user data first I need to use this token to fetch user ID.


Also, by the following example form Spotipy docs, user must provide his username at terminal:

if __name__ == '__main__':
    if len(sys.argv) > 1:
        username = sys.argv[1]
    else:
        print("Whoops, need your username!")
        print("usage: python user_playlists.py [username]")
        sys.exit()

    token = util.prompt_for_user_token(username)

    if token:
        sp = spotipy.Spotify(auth=token)
        playlists = sp.user_playlists(username)

After reading the docs from Spotify and Spotify, some things that are still not clear:

  1. Is it possible to get this USER ID from passing the token only?

  2. Must the app user necessarily provide his Spotify username via a form in a browser, besides authorizing the app when authentication is prompted?

  3. Is it possible to tweak the wrapper above and implement a client which contemplates the parameters required for implicit flow? Would simply spotify = spotipy.Spotify(auth=token) work and get current usr data?

1

1 Answers

0
votes

Also, by the following example form Spotipy docs, user must provide his username at terminal:

That's because Spotipy caches tokens on disk. When no cache path is specified by the user the username simply gets appended to the files file extension as seen here. So the username specified is never being transmitted to any Spotify API endpoint.

1) Is it possible to get this USER ID from passing the token only?

Yes, using /v1/me instead of /v1/users/{user_id} will do exactly that assuming you are using an access token generated by Authorization Code flow or Implicit Grant flow.

2) Must the app user necessarily provide his Spotify username via a form in a browser, besides authorizing the app when authentication is prompted?

No, as seen in the first paragraph of my answer.

3) Is it possible to tweak the wrapper above and implement a client which contemplates the parameters required for implicit flow? Would simply spotify = spotipy.Spotify(auth=token) work and get current usr data?

Spotipy seems to only use Authorization Code Flow right now. Due to you said you are

trying to implement a simple python client for Spotify api.

you should just implement Implicit Grant flow in your application. This has examples for all three Spotify authorization flows.