I'm currently building my very first own project, a web application with Flask which interacts with the Spotify API. The project is as good as ready after extensive testing locally and on a Heroku staging environment. However I'm currently experiencing a small login 'bug' I can't seem to wrap my head around.
When clicking a Login button, the application sends a request to the Spotify API, which sends back an authorization code upon confirmation of the user to read his data. This confirmation will result in the user being redirected to the '/profile route' of the web app. The flow of the login process so far on different environments:
- Locally: process has always ran smoothly (read: click the Login button once which redirects the user to /profile route)
- Staging (Heroku): clicking the login button generates the correct request to the Spotify API. However, when clicking it for the for the 1st time I get redirected to the login page (due to my login_required Flask decorator). When clicking it for the 2nd time it also generates the correct request and correctly sends the user to the '/profile route'.
I can see in the server logs clicking the login button for the 1st time generates the correct request. But it seems as if the validation by the login_required decorator of the '/profile route' goes 'too fast'? Or does this have something to do with caching? Because I'm also able to reproduce the bug (sometimes) by removing cache and hard refreshing the page.
I recently added a SECRET_KEY to session and changed the SESSION_PERMANENT from False to True but I don't think this is causing the issue? Some of the code I think might be causing this little bug:
# Ensure responses aren't cached
@app.after_request
def after_request(response):
response.headers["Cache-Control"] = "no-cache, no-store, must-revalidate"
response.headers["Expires"] = 0
response.headers["Pragma"] = "no-cache"
return response
# Configure session to use filesystem
app.config['SECRET_KEY'] = os.urandom(64)
app.config["SESSION_FILE_DIR"] = mkdtemp()
app.config["SESSION_PERMANENT"] = True
app.config["SESSION_TYPE"] = "filesystem"
Session(app)
def login_required(f):
"""
Decorate routes to require login:
http://flask.pocoo.org/docs/1.0/patterns/viewdecorators/
"""
@wraps(f)
def decorated_function(*args, **kwargs):
if session.get("authorization_header") is None:
return redirect(url_for('login'))
return f(*args, **kwargs)
return decorated_function
@app.route("/")
def index():
""" Shows landing page """
if session.get("authorization_header") is not None:
return redirect(url_for('profile'))
return render_template("index.html")
@app.route("/login")
def login():
""" Shows login page """
if session.get("authorization_header") is not None:
return redirect(url_for('profile'))
return render_template("login.html")
@app.route("/logout")
@helpers.login_required
def logout():
""" Logs user out """
# Forget any user_id
session.clear()
# Redirect user to login form
return redirect(url_for("index"))
@app.route("/profile")
@helpers.login_required
def profile():
""" Shows overview of user's Spotfy profile """