-1

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 """
Frederik
  • 33
  • 1
  • 3

1 Answers1

0

Not sure if this is your issue, but could cause some weird behaviour...

app.config['SECRET_KEY'] = os.urandom(64) This will result in a different secret key being set on each heroku dyno (if running multiple workers; the default is 2 for syncronous workers) as that random string is generated dynamically at worker boot time.

As a side note, os.urandom isn't for generating keys. Instead use the secrets module, and set the resulting string as a config var in heroku CLI and load it in your app with:

import os
app.config['SECRET_KEY'] = os.environ.get('SECRET_KEY')
v25
  • 7,096
  • 2
  • 20
  • 36
  • Thanks for the answer! I'll definitely keep it in mind. Although this doesn't seem to fix the issue. I'm starting to wonder it's something Heroku related – Frederik Aug 22 '20 at 14:39