Problem Description
Hello, I have been working on a backend server that I would like to be able to use to handle Spotify sessions for users. I am using Flask, and I found a very helpful example from the Spotipy documentation here.
The problem that I am running into is that the sessions from Flask don't seem to maintain their state in between API calls and I have been going nowhere in my efforts to fix it. Here is my setup:
api.py
from flask import Flask
from flask_session import Session
from flask_restful import Api
app = Flask(__name__)
app.config['SECRET_KEY'] = os.urandom(64)
app.config['SESSION_TYPE'] = 'filesystem'
app.config['SESSION_FILE_DIR'] = './.flask_session_test/'
api = Api(app)
Session(app)
#the following adds CORS headers to request responses in the app
@app.after_request
def after_request(response):
response.headers.add('Access-Control-Allow-Origin', 'http://localhost:3000')
response.headers.add('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE')
response.headers.add('Access-Control-Allow-Credentials', 'true')
response.headers.add('Access-Control-Allow-Headers', "Origin, X-Requested-With, Content-Type, Accept, x-auth")
return response
api.add_resource(Spotify, '/Spotify/')
if __name__ == '__main__':
app.run(debug=True, threaded=True)
Spotify.py
from flask import session, request, redirect
from flask_restful import Resource
import spotipy
import os
import uuid
SCOPE = "user-read-currently-playing playlist-modify-private"
#Cache logic follows in order to create sessions for spotify
caches_folder = '../.spotify_caches/'
if not os.path.exists(caches_folder):
#Ensure cache folder exists
os.makedirs(caches_folder)
def session_cache_path():
return caches_folder + session.get('uuid')
class Spotify(Resource):
def get(self):
if not session.get('uuid'):
#Visitor is unknown
session['uuid'] = str(uuid.uuid4())
cache_handler = spotipy.cache_handler.CacheFileHandler(cache_path=session_cache_path())
auth_manager = spotipy.oauth2.SpotifyOAuth(scope=SCOPE, cache_handler=cache_handler, show_dialog=True)
if request.args.get("code"):
auth_manager.get_access_token(request.args.get("code"))
return redirect('http://localhost:3000/spotify')
if not auth_manager.validate_token(cache_handler.get_cached_token()):
#Display sign in link when there is no token or token is not valid
auth_url = auth_manager.get_authorize_url()
return {"link_url":f"{auth_url}"}
def delete(self):
try:
#Problem becomes apparent here when the session_cache_path method cannot get the uuid from the session
os.remove(session_cache_path())
session.clear()
except OSError as e:
return {f'Error {e.strerror} in {e.filename}'}, 404
return {"msg":"Sign out successfull"}
Everything within the get method works just fine! I can sign in to spotify and it even generates a uuid and saves it to the session during that method, but every subsequent call to the API after the redirect creates a new session within the session folder. What it boils down to is that I am not sure how to get flask to recognize that it should use the session that was already created.
Fetch Requests from frontend
fetch('http://127.0.0.1:5000/Spotify/',
{method: 'GET',
credentials:'include'})
.then(response => response.json())
.then(
data => {
setSignInLink(data["link_url"])
}
)
This one works just fine. The link is generated and set in React.
fetch('http://127.0.0.1:5000/Spotify/',
{
method: 'DELETE',
credentials:'include'
})
This is the request which makes it clear that the session uuid has not been maintained as the flask server throws an error.
What I have tried to fix this
Ensuring proper CORS management Following the solution given here I set the fetch request from the frontend to enable credentials, but it still was unable to recognize that the request was coming from the same place for the same session.
I really have been struggling here, so any help would be appreciated thank you so much for your time!