Sessions

About

Sessions provide a place to persist data in web applications, Beaker’s session system simplifies session implementation details by providing WSGI middleware that handles them.

All cookies are signed with an HMAC signature to prevent tampering by the client.

Lazy-Loading

Only when a session object is actually accessed will the session be loaded from the file-system, preventing performance hits on pages that don’t use the session.

Using

The session object provided by Beaker’s SessionMiddleware implements a dict-style interface with a few additional object methods. Once the SessionMiddleware is in place, a session object will be made available as beaker.session in the WSGI environ.

Getting data out of the session:

myvar = session['somekey']

Testing for a value:

logged_in = 'user_id' in session

Adding data to the session:

session['name'] = 'Fred Smith'

Complete example using a basic WSGI app with sessions:

from beaker.middleware import SessionMiddleware

def simple_app(environ, start_response):
    # Get the session object from the environ
    session = environ['beaker.session']

    # Check to see if a value is in the session
    if 'logged_in' in session:
        user = True
    else:
        user = False

    # Set some other session variable
    session['user_id'] = 10

    start_response('200 OK', [('Content-type', 'text/plain')])
    return ['User is logged in: %s' % user]

# Configure the SessionMiddleware
session_opts = {
    'session.type': 'file',
    'session.cookie_expires': True,
}
wsgi_app = SessionMiddleware(simple_app, session_opts)

Note

This example does not actually save the session for the next request. Adding the save() call explained below is required, or having the session set to auto-save.

Session Attributes / Keys

Sessions have several special attributes that can be used as needed by an application.

  • id - Unique 40 char SHA-generated session ID
  • last_accessed - The last time the session was accessed before the current access, will be None if the session was just made

There’s several special session keys populated as well:

  • _accessed_time - Current accessed time of the session, when it was loaded
  • _creation_time - When the session was created

Saving

Sessions can be saved using the save() method on the session object:

session.save()

Warning

Beaker relies on Python’s pickle module to pickle data objects for storage in the session. Objects that cannot be pickled should not be stored in the session.

This flags a session to be saved, and it will be stored on the chosen back-end at the end of the request.

If it’s necessary to immediately save the session to the back-end, the persist() method should be used:

session.persist()

This is not usually the case however, as a session generally should not be saved should something catastrophic happen during a request.

Order Matters: When using the Beaker middleware, you must call save before the headers are sent to the client. Since Beaker’s middleware watches for when the start_response function is called to know that it should add its cookie header, the session must be saved before its called.

Keep in mind that Response objects in popular frameworks (WebOb, Werkzeug, etc.) call start_response immediately, so if you are using one of those objects to handle your Response, you must call .save() before the Response object is called:

# this would apply to WebOb and possibly others too
from werkzeug.wrappers import Response

# this will work
def sessions_work(environ, start_response):
    environ['beaker.session']['count'] += 1
    resp = Response('hello')
    environ['beaker.session'].save()
    return resp(environ, start_response)

# this will not work
def sessions_broken(environ, start_response):
    environ['beaker.session']['count'] += 1
    resp = Response('hello')
    retval = resp(environ, start_response)
    environ['beaker.session'].save()
    return retval

Auto-save

Saves can be done automatically by setting the auto configuration option for sessions. When set, calling the save() method is no longer required, and the session will be saved automatically anytime its accessed during a request.

Deleting

Calling the delete() method deletes the session from the back-end storage and sends an expiration on the cookie requesting the browser to clear it:

session.delete()

This should be used at the end of a request when the session should be deleted and will not be used further in the request.

If a session should be invalidated, and a new session created and used during the request, the invalidate() method should be used:

session.invalidate()

Removing Expired/Old Sessions

Beaker does not automatically delete expired or old cookies on any of its back-ends. This task is left up to the developer based on how sessions are being used, and on what back-end.

The database backend records the last accessed time as a column in the database so a script could be run to delete session rows in the database that haven’t been used in a long time.

When using the file-based sessions, a script could run to remove files that haven’t been touched in a long time, for example (in the session’s data dir):

find . -mtime +3 -exec rm {} \;