Working with spotipy library and a React frontend. Used the Flask Spotipy example code as a basis and changed it for testing purposes to see if my idea works. Currently stuck on a bug that I can't seem to understand. I am able to authenticate the user just fine however I can only send ONE api request. After that I get an error similar to this
raise SpotifyOauthError(spotipy.oauth2.SpotifyOauthError: error: invalid_grant, error_description: Invalid authorization code
Not sure if it has to do with refresh tokens but I can never send multiple requests when I authroize a user.
Here is my python code and react code
import os
from flask import Flask, session, request, redirect, jsonify
from flask_cors import CORS, cross_origin
from flask_session import Session
import spotipy
app = Flask(__name__)
app.config['SECRET_KEY'] = os.urandom(64)
app.config['SESSION_TYPE'] = 'filesystem'
app.config['SESSION_FILE_DIR'] = './.flask_session/'
CORS(app, resources={r"/*": {"origins": "*"}})
Session(app)
client_id = os.getenv("SPOTIPY_CLIENT_ID")
client_secret = os.getenv("SPOTIPY_CLIENT_SECRET")
redirect_uri = os.getenv("SPOTIPY_REDIRECT_URI")
scope = 'user-read-currently-playing playlist-modify-private user-read-recently-played'
@app.route('/')
def index():
cache_handler = spotipy.cache_handler.FlaskSessionCacheHandler(session)
auth_manager = spotipy.oauth2.SpotifyOAuth(scope=scope,
cache_handler=cache_handler,
show_dialog=True)
if request.args.get("code"):
# Step 2. Being redirected from Spotify auth page
auth_manager.get_access_token(request.args.get("code"))
session['access_token'] = auth_manager.get_access_token(request.args.get("code"))
return redirect('http://localhost:3000/?code=' + request.args.get("code"))
if not auth_manager.validate_token(cache_handler.get_cached_token()):
# Step 1. Display sign in link when no token
auth_url = auth_manager.get_authorize_url()
# let react grab the url
return jsonify({'url': auth_url})
# Step 3. Signed in, display data
spotify = spotipy.Spotify(auth_manager=auth_manager)
return f'<small><a href="/sign_out">[sign out]<a/></small></h2>' \
f'<a href="/playlists">my playlists</a> | ' \
f'<a href="/currently_playing">currently playing</a> | ' \
f'<a href="/current_user">me</a>' \
@app.route('/sign_out')
def sign_out():
session.pop("token_info", None)
return redirect('/')
@app.route('/recently-played')
def recently_played():
code = request.args.get('code')
cache_handler = spotipy.cache_handler.FlaskSessionCacheHandler(session)
auth = spotipy.oauth2.SpotifyOAuth(cache_handler=cache_handler)
if not auth.validate_token(cache_handler.get_cached_token()):
token_info = auth.get_access_token(code)
else:
token_info = cache_handler.get_cached_token()
spotify = spotipy.Spotify(auth=token_info['access_token'])
return spotify.current_user_recently_played(limit=10)
@app.route('/currently_playing')
def currently_playing():
cache_handler = spotipy.cache_handler.FlaskSessionCacheHandler(session)
auth_manager = spotipy.oauth2.SpotifyOAuth(cache_handler=cache_handler)
if not auth_manager.validate_token(cache_handler.get_cached_token()):
return redirect('/')
spotify = spotipy.Spotify(auth_manager=auth_manager)
track = spotify.current_user_playing_track()
if not track is None:
return track
return "No track currently playing."
@app.route('/current_user')
def current_user():
code = request.args.get('code')
cache_handler = spotipy.cache_handler.FlaskSessionCacheHandler(session)
auth = spotipy.oauth2.SpotifyOAuth(cache_handler=cache_handler)
if not auth.validate_token(cache_handler.get_cached_token()):
token_info = auth.get_access_token(code)
else:
token_info = cache_handler.get_cached_token()
spotify = spotipy.Spotify(auth=token_info['access_token'])
return spotify.current_user()
'''
Following lines allow application to be run more conveniently with
`python app.py` (Make sure you're using python3)
(Also includes directive to leverage pythons threading capacity.)
'''
if __name__ == '__main__':
app.run(threaded=True, port=int(os.environ.get("PORT",
os.environ.get("SPOTIPY_REDIRECT_URI", "8080").split(":")[-1])))
import React, { useState, useEffect } from "react";
import axios from "axios";
const CurrentUser = () => {
const [currentUser, setCurrentUser] = useState(null);
const getCurrentUser = () => {
const urlParams = new URLSearchParams(window.location.search);
const code = urlParams.get("code");
axios.get(`http://127.0.0.1:8080/current_user?code=${code}`).then((response) => {
setCurrentUser(response.data.display_name);
}
);
};
return (
<div>
<button onClick={getCurrentUser} style={{"margin": "5px"}}>Get Current User</button>
<div>
{currentUser}
</div>
</div>
);
};
export default CurrentUser;
import React, { useState, useEffect } from "react";
import axios from "axios";
const RecentPlay = () => {
const [recentPlay, setRecentPlay] = useState(null);
const getRecentPlay = () => {
const urlParams = new URLSearchParams(window.location.search);
const code = urlParams.get("code");
axios.get(`http://127.0.0.1:8080/recently-played?code=${code}`).then((response) => {
setRecentPlay(response.data.items);
}
);
};
return (
<div>
<button onClick={getRecentPlay}>Get Recent Play</button>
<div>
{recentPlay &&
recentPlay.map((item,index) => {
return (
<div key={index}>
<img src={item.track.album.images[0].url} alt="album cover" />
<p>{item.track.name}</p>
<p>{item.track.artists[0].name}</p>
</div>
);
})}
</div>
</div>
);
};
export default RecentPlay;