119

Right now I am using a flask 3rd party library Flask-Session and I am having no luck getting a session working.

When I connect to my site, I get the following error:

RuntimeError: the session is unavailable because no secret key was set. Set the secret_key on the application to something unique and secret.

Below is my server code.

from flask import Flask, session
from flask.ext.session import Session

SESSION_TYPE = 'memcache'
    
app = Flask(__name__)
sess = Session()

nextId = 0

def verifySessionId():
    global nextId

    if not 'userId' in session:
        session['userId'] = nextId
        nextId += 1
        sessionId = session['userId']
        print ("set userid[" + str(session['userId']) + "]")
    else:
        print ("using already set userid[" + str(session['userId']) + "]")
    sessionId = session.get('userId', None)
    return sessionId

@app.route("/")
def hello():
    userId = verifySessionId()
    print("User id[" + str(userId) + "]")
    return str(userId)

if __name__ == "__main__":
    app.secret_key = 'super secret key'

    sess.init_app(app)

    app.debug = True
    app.run()

As you can see, I do set the app secret key. What am I doing wrong?

Are there other session options?

Other info: Running Python 2.7 on Linux Mint

Full paste:

Traceback (most recent call last):
  File "/home/sean/code/misc/hangman/venv/lib/python2.7/site-packages/flask/app.py", line 1836, in __call__
    return self.wsgi_app(environ, start_response)
  File "/home/sean/code/misc/hangman/venv/lib/python2.7/site-packages/flask/app.py", line 1820, in wsgi_app
    response = self.make_response(self.handle_exception(e))
  File "/home/sean/code/misc/hangman/venv/lib/python2.7/site-packages/flask/app.py", line 1403, in handle_exception
    reraise(exc_type, exc_value, tb)
  File "/home/sean/code/misc/hangman/venv/lib/python2.7/site-packages/flask/app.py", line 1817, in wsgi_app
    response = self.full_dispatch_request()
  File "/home/sean/code/misc/hangman/venv/lib/python2.7/site-packages/flask/app.py", line 1477, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/home/sean/code/misc/hangman/venv/lib/python2.7/site-packages/flask/app.py", line 1381, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "/home/sean/code/misc/hangman/venv/lib/python2.7/site-packages/flask/app.py", line 1475, in full_dispatch_request
    rv = self.dispatch_request()
  File "/home/sean/code/misc/hangman/venv/lib/python2.7/site-packages/flask/app.py", line 1461, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "/home/sean/code/misc/session/sessiontest.py", line 27, in hello
    userId = verifySessionId()
  File "/home/sean/code/misc/session/sessiontest.py", line 16, in verifySessionId
    session['userId'] = nextId
  File "/home/sean/code/misc/hangman/venv/lib/python2.7/site-packages/werkzeug/local.py", line 341, in __setitem__
    self._get_current_object()[key] = value
  File "/home/sean/code/misc/hangman/venv/lib/python2.7/site-packages/flask/sessions.py", line 126, in _fail
    raise RuntimeError('the session is unavailable because no secret '
RuntimeError: the session is unavailable because no secret key was set.  Set the secret_key on the application to something unique and secret.
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
MintyAnt
  • 2,978
  • 7
  • 25
  • 37

3 Answers3

141

In your case the exception is raised by the NullSessionInterface session implementation, which is the default session type when you use Flask-Session. That's because you don't ever actually give the SESSION_TYPE configuration to Flask; it is not enough to set it as a global in your module. The Flask-Session quickstart example code does set a global, but then uses the current module as a configuration object by calling app.config.from_object(__name__).

This default doesn't make much sense with Flask 0.10 or newer; NullSession may have made sense with Flask 0.8 or 0.9, but in current version the flask.session.NullSession class is used as an error signal. In your case it gives you the wrong error message now.

Set the SESSION_TYPE configuration option to something else. Pick one of redis, memcached, filesystem or mongodb, and make sure to set it in app.config (directly or via the various Config.from_* methods).

For a quick test, setting it to filesystem is easiest; there is enough default configuration there to have that work without additional dependencies:

if __name__ == "__main__":
    # Quick test configuration. Please use proper Flask configuration options
    # in production settings, and use a separate file or environment variables
    # to manage the secret key!
    app.secret_key = 'super secret key'
    app.config['SESSION_TYPE'] = 'filesystem'

    sess.init_app(app)

    app.debug = True
    app.run()

If you see this error and you are not using Flask-Session, then something has gone wrong with setting the secret. If you are setting app.config['SECRET_KEY'] or app.secret_key in a if __name__ == "__main__": guard like above and you get this error, then you are probably running your Flask app via a WSGI server that imports your Flask project as a module, and the __name__ == "__main__" block is never run.

It is always better to manage configuration for Flask apps in a separate file, anyway.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
  • @martijin Pieters: where does this session variables gets stored? For example, if it is 'mongodb' where does the database that stores these session variables lives? – iamai Oct 25 '19 at 23:47
  • 1
    @iamai: that's documented the [Flask-Session *Configuration* section](https://pythonhosted.org/Flask-Session/#configuration); for mongodb, the default database name is `flask_session`, and the default collection is called `sessions`. – Martijn Pieters Oct 26 '19 at 20:05
  • Something seems very wrong with this answer at least as of flask 1.1.2 (most likely earlier). It states that you must set SESSION_TYPE and only lists options where the session is stored server-side. But that is not [currently] correct. If you succeed in setting a SECRET_KEY then the default session type will store the session in an encrypted cookie (not server side). IE: you **don't need to** set SESSION_TYPE to get this working, you can set the SECRET_KEY as the error message suggests. – Philip Couling Feb 22 '21 at 12:03
  • @PhilipCouling This answer is **specific to the `Flask-Session` extension**. You are thinking about base Flask. Yes, for the base Flask setup, `SECRET_KEY` is used to *cryptographically sign* the cookie (the cookie is *not encrypted*, the content can trivially be decoded, but not altered). – Martijn Pieters Feb 22 '21 at 13:49
  • @PhilipCouling: the question makes this quite clear; the title contains *using the Flask-Session extension*, and starts with *Right now I am using a flask 3rd party library Flask-Session and I am having no luck getting a session working.*. If you came here looking for information on the base Flask setup for sessions, you'll need to refer to the [Flask API documentation](https://flask.palletsprojects.com/en/1.1.x/api/#sessions) and the [section on sessions in the Flask tutorial](https://flask.palletsprojects.com/en/1.1.x/quickstart/#sessions). – Martijn Pieters Feb 22 '21 at 13:56
  • Just in case sombody is wondering about how to import Session the right way in 2022, it's: `from flask_session import Session` . Also warning for beginners: make your application reasonably secure from the start and use enviromental varioables: `app.secret_key = os.environ.get('YOUR_SECRET_KEY')` (ideally generate random hash and store it to your enviromental variables in your system). – Banik Jul 20 '22 at 10:30
77

Set the secret key outside of if __name__ == '__main__':

app.py:

from flask import Flask, session

app = Flask(__name__)
app.secret_key = "super secret key"

@app.route("/")
...

if __name__ == '__main__':
    app.debug = True
    app.run()

When you start your app by running flask run the if __name__ == '__main__': block gets skipped. If you don't want to skip it, run with python app.py.

hayden
  • 2,643
  • 17
  • 21
  • I'm running a flask app on an amazon ec2 apache2 Ubuntu server, using oauth2.0 to access google calendar information. This answer is the simple modification that made it work. Thank you! – jas Feb 16 '16 at 05:17
  • This is an answer to a *different question*, one where the session type has been configured correctly or you are not using Flask-Session at all, but no secret has been set because a the WSGI server has loaded the module with import and not as the main script. **In production environments you want to store secrets outside of your codebase, in a separate configuration file anyway**. – Martijn Pieters Nov 11 '18 at 18:41
21

Try this:

app = Flask(__name__)
app.config['SESSION_TYPE'] = 'memcached'
app.config['SECRET_KEY'] = 'super secret key'
sess = Session()

And remove your app.secret_key assignment at the bottom.

Miguel Grinberg
  • 65,299
  • 14
  • 133
  • 152