flask Set Cookie for every response

Question:

I use flask session in my app. In one of my handler I set session value and no session set in other handlers. But I found that in every response there is a http header: Set Cookie exists. Why does that happen?

app = Flask(__name__)
app.secret_key = r"A0Zr98j/3yX R~XHH!jmN'LWX/,?RT"

@app.route('/auth/login', methods=['POST'])
@crossdomain(origin='*')
def authlogin():
    user = User(username=username, registered_at=sqlnow())
    user.accounts = [Account(provider='weibo', access_token=access_token, uid=uid)]
    account = user.accounts[0]

    session['user_id'] = account.user_id
    return jsonify({
        'status': 'success',
        'data': {
            'user_id': account.user_id,
            'uid': account.uid
        }
    })

@app.route('/api/movies/<movie_type>')
def moviescoming(movie_type):
    if movie_type == 'coming':
        return getmovies(MOVIE_TYPE_PLAYING, offset, limit)
    else:
        return getmovies(MOVIE_TYPE_COMING, offset, limit)

app.run(host='0.0.0.0', debug=True)

Code shows here:
https://github.com/aisensiy/dianying/blob/master/index.py

Asked By: aisensiy

||

Answers:

The Short Answer:

This is by design, but a recent change in Flask allows you to change this behavior through use of the SESSION_REFRESH_EACH_REQUEST option. As of the posting of this answer, that option is not yet in a stable release of Flask.

The Long Answer

Let’s back up and discuss how cookies are supposed to work to begin with:

Cookies as a Standard

RFC 6265 defines that a cookie should expire when the agent (the browser) declares the session closed (typically, when the browser is closed), unless there was provided some mechanism to tell the browser when the cookie should actually expire:

Unless the cookie’s attributes indicate otherwise, the cookie […]
expires at the end of the current session (as defined by the user
agent).

[…]

If a cookie has neither the Max-Age nor the Expires attribute, the
user agent will retain the cookie until "the current session is over"
(as defined by the user agent).

If the server wishes a cookie to survive an agent restart, they need to set an expiration. Note that the Expires attribute is typically preferred due to the fact that Internet Explorer has a history of poor support for max-age.

Creating Permanent Cookies

So, it’s impossible to say that a cookie should be "permanent". When people talk about a "permanent" cookie, what they really are talking about is a cookie that survives a browser restart. There are two strategies that I know of for creating this "permanent" cookie:

  • Set the cookie’s expiration to something that is good enough to be considered permanent (such as the year 9999).
  • Set the cookie’s expiration to something relatively recent in the future (e.g., 31 days), but every time the cookie is used update the expiration again. For example, on January 1st we will set the cookie to expire on February 1st, but then when the user uses the cookie on January 2nd we are updating the cookie (by using Set-Cookie) to have it expire on February 2nd.

The first method requires the Set-Cookie header to only be set to the client once (unless the cookie contents need to change).

The second method would require the Set-Cookie header to be sent with every update so that the expiration is constantly "pushed off" as the user continues to use the service. Note that it also isn’t really "permanent", as a user that does not use your site for over 31 days will have their cookie expire.

RFC 6265 does have a bit to say on defining the expiration date:

Although servers can set the expiration date for cookies to the
distant future, most user agents do not actually retain cookies for
multiple decades. Rather than choosing gratuitously long expiration
periods, servers SHOULD promote user privacy by selecting reasonable
cookie expiration periods based on the purpose of the cookie. For
example, a typical session identifier might reasonably be set to
expire in two weeks.

So, while it doesn’t explicitly say whether or not to be constantly updating the expiration date, it does seem to say that using a far-future date should NOT be considered a good practice.

Flask’s Implementation of "Permanent Cookies"

Flask uses the second method (constantly updating the cookie expiration with Set-Cookie) by design. By default, the expiration of the cookie will be 31 days in the future (configurable by PERMANENT_SESSION_LIFETIME). With every request, Flask will use another Set-Cookie to push the expiration out another 31 days (or whatever you set your permanent session lifetime value to). Therefore, the Set-Cookie on every request you see is expected, even if the session has not changed.

Recently, however, there has been a discussion in a pull request regarding using Set-Cookie only when the cookie changes. This resulted in a new feature that allows the user to change how this works. Flask will continue to work as it has, but the user can set a new SESSION_REFRESH_EACH_REQUEST option to False, which will cause the Set-Cookie header to only be sent when the cookie changes.

The new item is documented as:

this flag controls how permanent sessions are refresh [sic]. If set to
True (which is the default) then the cookie is refreshed each
request which automatically bumps the lifetime. If set to False a
set-cookie header is only sent if the session is modified. Non
permanent sessions are not affected by this.

This new option, together with the existing PERMANENT_SESSION_LIFETIME, allows Flask developers to better tune exactly how their "permanent" cookies will be set to expire.

As of this answer’s posting date (December 24th, 2013), the SESSION_REFRESH_EACH_REQUEST option has not been part of any Flask release, and therefore users wishing to use it will need to wait for a future Flask release.

Answered By: Mark Hildreth
Categories: questions Tags: , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.