3

I am trying to do the authorization code flow using Spotify's API to ultimately add songs to a playlist. I am building this from scratch, and not using any libraries such as Spotipy.

I am able to successfully hit the authorize endpoint, but I am having some issues with the token endpoint. Here is the code I have so far:

# URLS
AUTH_URL = 'https://accounts.spotify.com/authorize'
TOKEN_URL = 'https://accounts.spotify.com/api/token'
BASE_URL = 'https://api.spotify.com/v1/'


# Make a request to the /authorize endpoint to get an authorization code
auth_code = requests.get(AUTH_URL, {
    'client_id': CLIENT_ID,
    'response_type': 'code',
    'redirect_uri': 'https://open.spotify.com/collection/playlists',
    'scope': 'playlist-modify-private',
})
print(auth_code)

auth_header = base64.urlsafe_b64encode((CLIENT_ID + ':' + CLIENT_SECRET).encode('ascii'))
headers = {
    'Content-Type': 'application/x-www-form-urlencoded',
    'Authorization': 'Basic %s' % auth_header.decode('ascii')
}

payload = {
    'grant_type': 'authorization_code',
    'code': auth_code,
    'redirect_uri': 'https://open.spotify.com/collection/playlists',
    #'client_id': CLIENT_ID,
    #'client_secret': CLIENT_SECRET,
}

# Make a request to the /token endpoint to get an access token
access_token_request = requests.post(url=TOKEN_URL, data=payload, headers=headers)

# convert the response to JSON
access_token_response_data = access_token_request.json()

print(access_token_response_data)

# save the access token
access_token = access_token_response_data['access_token']

When I run my script, I get this output in Terminal:

{'error': 'invalid_grant', 'error_description': 'Invalid authorization code'}
Traceback (most recent call last):
  File "auth.py", line 48, in <module>
    access_token = access_token_response_data['access_token']
KeyError: 'access_token'```

Can anyone explain to me what I might be doing wrong here?
lux7
  • 1,600
  • 2
  • 18
  • 34

3 Answers3

3

By now, you probably have figure out what the problem was, but I am answering for future readers as well. When you encode the auth_header, you should encode it to bytes not ascii. The str.encode() does this by default, so you can call it without arguments. Your code changes to this:

auth_header = base64.urlsafe_b64encode((CLIENT_ID + ':' + CLIENT_SECRET).encode()).

Now you must have a working example.

exch_cmmnt_memb
  • 173
  • 1
  • 13
0

The code below worked for me to create a playlist and add a song.

The prerequisite is that you have a client_id and client_secret. Run the code below and browse to your base URL (in my case, that was localhost), then you will see an authorize hyperlink that forwards you to the spotify authorization page.

Note that the redirect_url needs to be whitelisted in the spotify developer dashboard.

from fastapi import FastAPI
from fastapi.responses import HTMLResponse
import requests
import uvicorn


# client_id = "YOUR_CLIENT_ID"
# client_secret = "YOUR_CLIENT_SECRET"
# redirect_uri = "YOUR_REDIRECT_URI" # e.g. http://localhost:8000/callback/ --> you will have to whitelist this url in the spotify developer dashboard 

app = FastAPI()

def get_access_token(auth_code: str):
    response = requests.post(
        "https://accounts.spotify.com/api/token",
        data={
            "grant_type": "authorization_code",
            "code": auth_code,
            "redirect_uri": redirect_uri,
        },
        auth=(client_id, client_secret),
    )
    access_token = response.json()["access_token"]
    return {"Authorization": "Bearer " + access_token}


@app.get("/")
async def auth():
    scope = ["playlist-modify-private", "playlist-modify-public"]
    auth_url = f"https://accounts.spotify.com/authorize?response_type=code&client_id={client_id}&redirect_uri={redirect_uri}&scope={' '.join(scope)}"
    return HTMLResponse(content=f'<a href="{auth_url}">Authorize</a>')


@app.get("/callback")
async def callback(code):

    headers = get_access_token(code)
    response = requests.get("https://api.spotify.com/v1/me", headers=headers)
    user_id = response.json()["id"]


    name = "Name of your playlist"
    description = "Description of your playlist"

    params = {
        "name": name,
        "description": description,
        "public": True,
    }

    url = f"https://api.spotify.com/v1/users/{user_id}/playlists"
    response = requests.post(url=url, headers=headers, json=params)
    playlist_id = response.json()["id"]

    track_uri = "spotify:track:319eU2WvplIHzjvogpnNc6"
    response = requests.post(
        f"https://api.spotify.com/v1/playlists/{playlist_id}/tracks",
        headers=headers,
        json={"uris": [track_uri]},
    )
    if response.status_code == 201:
        return {"message": "Track added successfully!"}
    else:
        return {"error": response.json()}


if __name__ == "__main__":
    uvicorn.run(app, debug=True)
lux7
  • 1,600
  • 2
  • 18
  • 34
-2

You're missing the CLIENT_ID and CLIENT_SECRET set within the code if I'm not mistaken.

This means Spotify will return invalid access token, which results in you not being able to continue.

You can also use Spotipy library for Python to make things easier. https://spotipy.readthedocs.io/en/2.16.1/

tomatoj
  • 32
  • 1