As @falsetru mentioned, you have to set a secret key.
Before sending the session cookie to the user's browser, Flask signs the cookies cryptographically, and that doesn't mean that you cannot decode the cookie. I presume that Flask keeps track of the signed cookies, so it can perform it's own 'magic', in order to determine if the cookie that was sent along with the request (request headers), is a valid cookie or not.
Some methods that you may use, all related with Flask class instance, generally defined as app:
defining the secret_key variable for app object
app.secret_key = b'6hc/_gsh,./;2ZZx3c6_s,1//'
using the config() method
app.config['SECRET_KEY'] = b'6hc/_gsh,./;2ZZx3c6_s,1//'
using an external configuration file for the entire Flask application
$ grep pyfile app.py
app.config.from_pyfile('flask_settings.cfg')
$ cat flask_settings.py
SECRET_KEY = b'6hc/_gsh,./;2ZZx3c6_s,1//'
Here's an example (an adaptation from this article), focused on providing a more clearer picture of Flask session cookie, considering the participation of both Client and Server sides:
from flask import Flask, request, session
import os
app = Flask(__name__)
@app.route('/')
def f_index():
# Request Headers, sent on every request
print("\n\n\n[Client-side]\n", request.headers)
if 'visits' in session:
# getting value from session dict (Server-side) and incrementing by 1
session['visits'] = session.get('visits') + 1
else:
# first visit, generates the key/value pair {"visits":1}
session['visits'] = 1
# 'session' cookie tracked from every request sent
print("[Server-side]\n", session)
return "Total visits:{0}".format(session.get('visits'))
if __name__ == "__main__":
app.secret_key = os.urandom(24)
app.run()
Here's the output:
$ python3 sessions.py
* Serving Flask app "sessions" (lazy loading)
* Environment: production
WARNING: Do not use the development server in a production environment.
Use a production WSGI server instead.
* Debug mode: off
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
[Client-side]
Upgrade-Insecure-Requests: 1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Connection: keep-alive
Host: 127.0.0.1:5000
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:62.0) Gecko/20100101 Firefox/62.0
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.5
[Server-side]
<SecureCookieSession {'visits': 1}>
127.0.0.1 - - [12/Oct/2018 14:27:05] "GET / HTTP/1.1" 200 -
[Client-side]
Upgrade-Insecure-Requests: 1
Cookie: session=eyJ2aXNpdHMiOjF9.DqKHCQ.MSZ7J-Zicehb6rr8qw43dCVXVNA # <--- session cookie
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Connection: keep-alive
Host: 127.0.0.1:5000
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:62.0) Gecko/20100101 Firefox/62.0
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.5
[Server-side]
<SecureCookieSession {'visits': 2}>
127.0.0.1 - - [12/Oct/2018 14:27:14] "GET / HTTP/1.1" 200 -
You may have noticed that in the example above, I'm using the os lib and the urandom() function, in order to generate Flask's secret key, right?
From the official doc:
How to generate good secret keys
A secret key should be as random as possible. Your operating system has ways to generate pretty random data based on a cryptographic random generator. Use the following command to quickly generate a value for Flask.secret_key (or SECRET_KEY):
$ python -c 'import os; print(os.urandom(16))'
b'_5#y2L"F4Q8z\n\xec]/'
PLUS NOTE
As you can see, the creators of Flask support the practice of using os.urandom() for building the Flask secret key, from older versions of the tool to its latest version. So: why @joshlsullivan's answer received downvotes (deserves an upvote) and why @MikhailKashkin writes that, using os.urandom() is terrible idea, are mysteries.