403 Client Error: Forbidden when trying to start playback using spotipy

81 views Asked by At

I am trying to make a little app that manages the spotify queue on parties using the spotipy library. However I am stuck on the OAuth when logging in to the Spotify API. Since all the questions regarding this topic are several years old, I thought I might as well give it a shot. I have followed a tutorial on how to set up OAuth for the Spotify API making use of flask, but whenever the user successfully authenticates my App and I make the API call to start/stop the playback, I get this error: requests.exceptions.HTTPError: 403 Client Error: Forbidden for url: https://api.spotify.com/v1/me/player/play

If I have understood the documentation correctly, I don't have to pass the access token whenever I make an API call when using spotipy, though please correct me if I misunderstood.

I have my code here:

import os
import time
from spotipy.oauth2 import SpotifyOAuth
from flask import Flask, request, url_for, session, redirect
import spotipy


app = Flask(__name__)

app.config['SESSION_COOKIE_NAME'] = 'Spotify Cookie'
app.secret_key = 'some random string'
TOKEN_INFO = 'token_info'


@app.route('/')
def login():
    auth_url = create_spotify_oauth2().get_authorize_url()
    return redirect(auth_url)


@app.route('/redirect')
def redirect_page():
    session.clear()
    code = request.args.get('code')
    token_info = create_spotify_oauth2().get_access_token(code)
    session[TOKEN_INFO] = token_info
    return redirect(url_for('main_app', external=True))


@app.route('/mainApp')
def main_app():
    try:
        token_info = get_token()
    except:
        print("User not logged in")
        return redirect('/')
    sp = spotipy.Spotify(auth=token_info['access_token'])
    sp.start_playback()

    return "Hi"


def get_token():
    token_info = session.get(TOKEN_INFO, None)
    if not token_info:
        redirect(url_for('login', external=False))

    now = int(time.time())

    is_expired = token_info['expires_at'] - now < 60
    if is_expired:
        spotify_oauth2 = create_spotify_oauth2()
        token_info = spotify_oauth2.refresh_access_token(token_info['refresh_token'])
    return token_info


def create_spotify_oauth2():
    return SpotifyOAuth(client_id=os.getenv('CLIENT_ID'),
                        client_secret=os.getenv('CLIENT_SECRET'),
                        redirect_uri=url_for('redirect_page', _external=True),
                        scope='user-read-playback-state user-modify-playback-state user-read-currently-playing '
                              'playlist-read-collaborative'
                        )


app.run(debug=True)

Whenever the user logs in, the playback does neither start or stop, but instead the HTML page saying "hi" gets displayed in the browser and the console displays the above mentioned error message. Opening the URL returned by the error message displays the error object with the status: 401 and the message: "No token provided"

Any help is greatly appreciated!

1

There are 1 answers

1
Dmitry On

Have a look at the actions object in a response on get playback state request. Unfortunately, there is some discrepancy between documentation and actual results. Maybe the documentation is trailing slightly behind and is to be updated soon. Anyway, actions may look like this:

"actions": {
  "disallows": {
    "resuming": true,
    "skipping_prev": true
  }
}

Requesting any of the corresponding actions (e.g. play) will fail with the very same error:

requests.exceptions.HTTPError: 403 Client Error: Forbidden for url: https://api.spotify.com/v1/me/player/play

So I suppose you are encountering a situation, when user's playback is already playing, and Spotify disallows you starting or resuming the playback. Which seems to be normal. And you should just catch and handle that exception:

def main_app():
    ...
    sp = spotipy.Spotify(auth=token_info['access_token'])
    try:
        sp.start_playback()
    except spotipy.exceptions.SpotifyException:
        # Didn't manage to start/resume the playback
        pass
    ...