28

By default, Flask uses volatile sessions, which means the session cookie is set to expire when browser closes. In order to use permanent sessions, which will use a cookie with a defined expiration date, one should set session.permanent = True, as is mentioned in this question., and the expiration date will be set based on config['PERMANENT_SESSION_LIFETIME'].

I am surprised that session lifetime is defined in config file, yet it is not possible to request the use of permanent sessions through configuration, such as a config['USE_PERMANENT_SESSION'] = True. But so be it.

My question is: if you do want permanent sessions, what is the best place to define them ? Is it in an @app.before_request function as proposed in mentioned question ? But that would mean setting it over again at each request ? It seems that once set, session.permanent remains true till end of session.

Permanent sessions are generally used after sign-in, so maybe the best place to request them is while processing login_user() ? So is the best policy to use volatile session cookies for all anonymous pages, and switch to permanent sessions by doing a session.permanent = True at sign-in ?

And one might want to set a different lifetime depending on whether it is the ordinary session cookie, or the remember_me cookie. What would be the best way to achieve this ?

Community
  • 1
  • 1
patb
  • 1,338
  • 1
  • 14
  • 19

3 Answers3

20

I'm surprised no on has answered this question. It seems like there should be some type of config variable SESSION_PERMANENT = True. But unfortunately there isn't. As you mentioned this is the best way to do it.

@app.before_request
def make_session_permanent():
    session.permanent = True
mikey8989
  • 314
  • 3
  • 13
  • is config['PERMANENT_SESSION_LIFETIME'] value in seconds or milliseconds? – Random COSMOS Apr 05 '20 at 18:17
  • `config['SESSION_PERMANENT'] = True` is in the [docs](https://pythonhosted.org/Flask-Session/#configuration) now. – dashesy May 01 '20 at 05:40
  • 4
    @dashesy, you're referring to a configuration in the [Flask-Session](https://pythonhosted.org/Flask-Session/) extension. In vanilla Flask session management, `config['SESSION_PERMANENT']` does not exist, not even in the master branch. – Hooloovoo13 May 15 '20 at 07:52
6

Should you use PERMANENT_SESSION_LIFETIME and session.permanent?

What you actually want to do is probably expiring users' sign-in status. However, this configuration expires the session object/cookie which contains the users' sign-in status as well as (potentially) some other data that you stored in session.

Do you need to set session.permanent?

According to Flask's doc:

Flask’s default cookie implementation validates that the cryptographic signature is not older than this value.

session.permanent is an add-on of PERMANENT_SESSION_LIFETIME. Sometimes it is okay if you do not set session.permanent to True.

If you do not set session.permanent, the session cookie's lifetime will not be affected by PERMANENT_SESSION_LIFETIME. But Flask will look at PERMANENT_SESSION_LIFETIME and a timestamp in the session cookie, to see if the session cookie is still valid. If the timestamp is too older than specified by PERMANENT_SESSION_LIFETIME, it will be ignored. But the cookie still exists.

This is how Flask ignores session cookie:

def open_session(self, app, request):
    s = self.get_signing_serializer(app)
    if s is None:
        return None
    val = request.cookies.get(app.session_cookie_name)
    if not val:
        return self.session_class()
    max_age = total_seconds(app.permanent_session_lifetime)
    try:
        data = s.loads(val, max_age=max_age)
        return self.session_class(data)
    except BadSignature:
        return self.session_class()

If you set session.permanent=True, the validation will still be done. And what's more, the session cookie will expire and be deleted from the browser after PERMANENT_SESSION_LIFETIME.

This is how PERMANENT_SESSION_LIFETIME control the expiration of the cookie:

def get_expiration_time(self, app, session):
    if session.permanent:
        return datetime.utcnow() + app.permanent_session_lifetime


def save_session(self, app, session, response):
    ...
    expires = self.get_expiration_time(app, session)
    val = self.get_signing_serializer(app).dumps(dict(session))
    response.set_cookie(
        app.session_cookie_name,
        val,
        expires=expires,
        httponly=httponly,
        domain=domain,
        path=path,
        secure=secure,
        samesite=samesite
    )

Do you need to set session.permanent for every request?

session.permanent by default is actually session['_permanent']. Its value will stay in session. But if you are going to assign it only when users sign in, keep alert by checking how users can by-pass the sign-in route to sign in. For example, by signing up.

Kaiwen Sun
  • 101
  • 2
  • 3
  • Very detailed and helpful answer, could you elaborate a little bit how users can bypass the sign-in route by signing up? – oeter May 12 '21 at 08:46
5

I choose what you said "login_user()"

@asset.route('/login', methods=['GET', 'POST'])
def login():
    #After Verify the validity of username and password
    session.permanent = True

if it set at app.before_request, This will lead to set them too may times.

tinyhare
  • 1,433
  • 16
  • 19