1

So I've been using Flask to create an app that uses Spotify API, and the authorization code flow works perfectly fine when running on my localhost server. However, after deploying the app to Heroku, occasionally the app will crash and give me a 'token not provided' error in the logs. Sometimes it'll work flawlessly, but when I play around with it more it'll crash. I try to redo the process on my localhost but it doesn't seem to break. I'm storing the token in sessions, could it be that Heroku is having problem with retrieving session variables?

Here's the flask app code

#Home view
@app.route('/')
@app.route('/home')
def home():
    return render_template('home.html', title='Home')

#Login view
@app.route('/login', methods=['GET','POST'])
def login():

    AUTH_FIRST = req_auth()
    return redirect(AUTH_FIRST)

#Callback view for Spotify API
@app.route('/callback')
def callback():


    if request.args.get('code'):
        code = request.args.get('code')
        token = req_token(code)
        session['token'] = token

        return redirect(url_for('generate_playlist'))

    else:
        return redirect(url_for('home'))

#Generate playlist view
@app.route('/generate_playlist', methods=['GET', 'POST'])
def generate_playlist():

    if request.method == 'POST':
        levels = int(float(request.form['level']))
        token = session.get('token')
        generate(token, levels)

        return redirect(url_for('success'))

    else:
        return redirect(url_for('generate_playlist'))

This is the backend authorization code (I've commented out some parts to make it simpler, yet it still doesn't work):

client_id = os.environ.get("CLIENT_ID")
client_secret = os.environ.get("CLIENT_SECRET")
redirect_uri = os.environ.get('REDIRECT_URI')

state = ''.join(random.choice(string.ascii_lowercase + string.digits) for n in range(8))
scope = 'user-top-read user-library-read playlist-modify-public'

def req_auth():

    show_dialog = "false"

    AUTH_FIRST_URL = f'https://accounts.spotify.com/authorize?client_id={client_id}&response_type=code&redirect_uri={quote("https://surprisify-playlist-generator.herokuapp.com/callback")}&show_dialog={show_dialog}&state={state}&scope={scope}'
    return AUTH_FIRST_URL

def req_token(code):

    #B64 encode variables
    client_creds = f"{client_id}:{client_secret}"
    client_creds_b64 = base64.b64encode(client_creds.encode())

    #Token data
    token_data = {
        "grant_type": "authorization_code",
        "code": code,
        "redirect_uri": "https://surprisify-playlist-generator.herokuapp.com/callback"
    }

    #Token header
    token_header = {
        "Authorization": f"Basic {client_creds_b64.decode()}"
    }

    #Make request post for token info
    token_json = requests.post('https://accounts.spotify.com/api/token', data=token_data, headers=token_header)
    return token_json.json()['access_token']


    #Checking if token is still valid, otherwise, refresh
    # if token_json.json()['expires_in']:
    #   now = datetime.datetime.now()
    #   expires_in = token_json.json()['expires_in']
    #   expires = now + datetime.timedelta(seconds=expires_in)

    #   if now > expires:

    #       refresh_token_data = {
    #           "grant_type": "refresh_token",
    #           "refresh_token": token_json.json()['refresh_token']
    #       }

    #       refresh_token_json = requests.post('https://accounts.spotify.com/api/token', data=refresh_token_data, headers=token_header)
    #       token = refresh_token_json.json()['access_token']

    #       return token
    #   else:

    #       token = token_json.json()['access_token']

    #       return token
    # else:
    #   token = token_json.json()['access_token']

    #   return token

1 Answers1

0

Could the error happen after you restart the browser? Flask session cookies are stored (by default) until you close the browser. Then, if you don't authenticate again, calling session.get(token) will return None and is likely why you get the error. You could try checking if token is None in generate_playlist() and requiring re-authentication with a redirect.

Here is an implementation of the Spotify authorization code flow using Spotipy that I have used with success in my own project: https://stackoverflow.com/a/57929497/6538328 (method 2).

Atte
  • 309
  • 3
  • 12
  • Thanks for your response. I actually found out what the issue was; I was generating a unique secret session key every time the program ran, and I guess Heroku didn't really work with that so I changed the session key to a fixed string. – Stephen Chou Jun 07 '20 at 02:57