auth_head = {"Authorization": "Bearer {}".format(response["access_token"])} KeyError: 'access_token'

Viewed 507

I made a Python program that transfers music from YouTube playlists to your Spotify account and I wanted to turn it into a web app with a simple UI so that people could log into their yt/spotify accounts without having to run the program from the command line. I used Flask to make the interface, and have it working when I manually input the login info in my YouTubetoSpotify file, and now I am working on implementing Oauth2 on top of the UI so that when a user clicks one of the login buttons, it'll direct them to the corresponding authentication page (right now I'm just working on the Spotify login).

After some debugging, it seems that the client id and secret are properly obtained, but when they are used to get the token (in the getToken function in flask_spotify_auth), the post request returns an error. Here is the full error message, as well as all of my files.

{'error': 'invalid_client'}
[2020-07-08 14:09:13,121] ERROR in app: Exception on /callback/ [GET]
Traceback (most recent call last):
  File "C:\Users\jared\AppData\Local\Programs\Python\Python37\lib\site-packages\flask\app.py", line 2292, in wsgi_app
    response = self.full_dispatch_request()
  File "C:\Users\jared\AppData\Local\Programs\Python\Python37\lib\site-packages\flask\app.py", line 1815, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "C:\Users\jared\AppData\Local\Programs\Python\Python37\lib\site-packages\flask\app.py", line 1718, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "C:\Users\jared\AppData\Local\Programs\Python\Python37\lib\site-packages\flask\_compat.py", line 35, in reraise
    raise value
  File "C:\Users\jared\AppData\Local\Programs\Python\Python37\lib\site-packages\flask\app.py", line 1813, in full_dispatch_request
    rv = self.dispatch_request()
  File "C:\Users\jared\AppData\Local\Programs\Python\Python37\lib\site-packages\flask\app.py", line 1799, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "C:/Users/jared/codingProjects/python_projects/Mixify/app.py", line 30, in upload
    startup.getUserToken(request.args['code'])
  File "C:\Users\jared\codingProjects\python_projects\Mixify\startup.py", line 29, in getUserToken
    TOKEN_DATA = getToken(code, CLIENT_ID, CLIENT_SECRET, "{}:{}/callback/".format(CALLBACK_URL, PORT))
  File "C:\Users\jared\codingProjects\python_projects\Mixify\flask_spotify_auth.py", line 33, in getToken
    return handleToken(json.loads(post.text))
  File "C:\Users\jared\codingProjects\python_projects\Mixify\flask_spotify_auth.py", line 38, in handleToken
    auth_head = {"Authorization": "Bearer {}".format(response["access_token"])}
KeyError: 'access_token'
127.0.0.1 - - [08/Jul/2020 14:09:13] "GET /callback/?code=AQA9preCSj1r87JMxXt5XUBwC6LT-ZQM_By2NYTcdhi7wgUIwQKO6Q5Cm7ChcKdJ_Rd3IkCxdTKw7RlI4EYZNIZrp9RpZfOd1rXeE8v_2tY3A0Q-RKqP21jmRHMFOdTV4z1Lj6lQ1WXcOmbL5eP614ps8TfDPOzBwOfHMvILr-y3HsB30RlYJ6X2XQLUb5p3347YIsx4lfcja9unWa1SjyXw7pbYdOA HTTP/1.1" 500 -

app.py

# Jared Tewodros
# jmt5rg

from flask import *
import YoutubeToSpotify
import startup

app = Flask(__name__)


# @app.errorhandler(404)
# def page_not_found(e):
#     return render_template('404.html'), 404


# home page
# @app.route("/")
# def upload():
#     return render_template("file_upload.html")


@app.route("/")
def index():
    response = startup.getUser()
    return redirect(response)


@app.route('/callback/', methods=["GET", "POST"])
def upload():
    startup.getUserToken(request.args['code'])
    return render_template("file_upload.html")


# and that's all folks
@app.route("/convert", methods=["POST"])
def success():
    global yt_list
    global sp_list
    global desc
    yt_list = request.form['ytPL']
    sp_list = request.form['spPL']
    desc = request.form['desc']
    cp = YoutubeToSpotify.YouTubePlaylist()
    cp.add_song_to_playlist(yt_list, sp_list, desc)
    return render_template("success.html")


if __name__ == "__main__":
    app.run()

startup.py

# Jared Tewodros
# jmt5rg

from flask_spotify_auth import getAuth, refreshAuth, getToken

# Add your client ID
CLIENT_ID = "53754c6314ec4175b8dc3d23c864cb5a"

# aDD YOUR CLIENT SECRET FROM SPOTIFY
CLIENT_SECRET = "6677e13f615b4cfda88371b233b9ae08"

# Port and callback url can be changed or ledt to localhost:5000
PORT = "5000"
CALLBACK_URL = "http://localhost"

# Add needed scope from spotify user
# SCOPE = "streaming user-read-birthdate user-read-email user-read-private"
SCOPE = "user-read-email user-read-private"
# token_data will hold authentication header with access code, the allowed scopes, and the refresh countdown
TOKEN_DATA = []


def getUser():
    return getAuth(CLIENT_ID, "{}:{}/callback/".format(CALLBACK_URL, PORT), SCOPE)


def getUserToken(code):
    global TOKEN_DATA
    TOKEN_DATA = getToken(code, CLIENT_ID, CLIENT_SECRET, "{}:{}/callback/".format(CALLBACK_URL, PORT))


def refreshToken(time):
    time.sleep(time)
    TOKEN_DATA = refreshAuth()


def getAccessToken():
    return TOKEN

flask_spotify_auth.py

# Jared Tewodros
# jmt5rg

import base64, json, requests

SPOTIFY_URL_AUTH = 'https://accounts.spotify.com/authorize/?'
SPOTIFY_URL_TOKEN = 'https://accounts.spotify.com/api/token/'
RESPONSE_TYPE = 'code'
HEADER = 'application/x-www-form-urlencoded'
REFRESH_TOKEN = ''


def getAuth(client_id, redirect_uri, scope):
    data = "{}client_id={}&response_type=code&redirect_uri={}&scope={}".format(SPOTIFY_URL_AUTH, client_id,
                                                                               redirect_uri, scope)
    return data


def getToken(code, client_id, client_secret, redirect_uri):
    body = {
        "grant_type": 'authorization_code',
        "code": code,
        "redirect_uri": redirect_uri,
        "client_id": client_id,
        "client_secret": client_secret
    }
    iden = "{}:{}".format(client_id, client_secret)
    iden_bytes = iden.encode('ascii')
    encoded = base64.b64encode(iden_bytes)
    headers = {"Content-Type": HEADER, "Authorization": "Basic {}".format(encoded)}

    post = requests.post(SPOTIFY_URL_TOKEN, params=body, headers=headers)
    return handleToken(json.loads(post.text))


def handleToken(response):
    print(response)
    auth_head = {"Authorization": "Bearer {}".format(response["access_token"])}
    REFRESH_TOKEN = response["refresh_token"]
    return [response["access_token"], auth_head, response["scope"], response["expires_in"]]


def refreshAuth():
    body = {
        "grant_type": "refresh_token",
        "refresh_token": REFRESH_TOKEN
    }

    post_refresh = requests.post(SPOTIFY_URL_TOKEN, data=body, headers=HEADER)
    p_back = json.dumps(post_refresh.text)

    return handleToken(p_back)
1 Answers

The response that you print is

{'error': 'invalid_client'}

It seems that you have an error when authenticating to the spotify API. Your error KeyError: 'access_token', comes from that. There is indeed no access_token key in the response.

You have to adapt your handleToken method to handle the different errors codes.

They are all described here


Here is a description of the error invalid_client

Since it's a post request. Your body variable should be passed in the data attribute instead params

Because params will send your body as URL’s query string

post = requests.post(SPOTIFY_URL_TOKEN, data=body, headers=headers)

PS : don't post your CLIENT_ID or CLIENT_SECRETon SO these are private information.

Related