Server Side Sessions

By default, Flask will store user session information in a client-side cookie. This works, however, it has some drawbacks. For instance, it doesn’t allow sessions to be terminated by the server, implementation and user details get exposed in the cookie, and logout isn’t fully implemented (Flask asks the browser to delete the cookie, and it will, but if the cookie had been saved/intercepted and later resubmitted, eg by a nefarious party, the cookie would continue to work even though the user thought they logged out). Using server side sessions solves these problems for us, and it’s really easy to set up thanks to Flask-Session.

Install Dependencies

pip install "flask-unchained[session]"

Enable the Session Bundle:

# unchained_config.py

BUNDLES = [
    # ...
    'flask_unchained.bundles.session',
    'app',
]

Configuration

Let’s configure the Session Bundle to use SQLAlchemy:

# app/config.py

class Config(BundleConfig):
    # ...
    SESSION_TYPE = 'sqlalchemy'
    SESSION_SQLALCHEMY_TABLE = 'flask_sessions'

Because the Session Bundle is just a thin wrapper around Flask Session, configuration options are the same as documented in the official docs.

Database Migrations

And now we need to create the table, using a database migration:

flask db migrate -m 'create sessions table'

It’s always a good idea to inspect the migration to make sure it’s going to do exactly what you expect it to do before running it. It should look something about like this:

# db/migrations/versions/[hash]_create_sessions_table.py

"""create sessions table

Revision ID: 17c5247038a6
Revises:
Create Date: 2018-07-30 11:50:19.709960

"""
from alembic import op
import sqlalchemy as sa
import flask_unchained.bundles.sqlalchemy.sqla.types as sqla_bundle

# revision identifiers, used by Alembic.
revision = '17c5247038a6'
down_revision = None
branch_labels = None
depends_on = None

def upgrade():
    # ### commands auto generated by Alembic - please adjust! ###
    op.create_table('flask_sessions',
        sa.Column('id', sa.Integer(), nullable=False),
        sa.Column('session_id', sa.String(length=255), nullable=False),
        sa.Column('data', sa.LargeBinary(), nullable=False),
        sa.Column('expiry', sa.DateTime(), nullable=True),
        sa.Column('created_at', sqla_bundle.DateTime(timezone=True),
                  server_default=sa.text('CURRENT_TIMESTAMP'), nullable=False),
        sa.Column('updated_at', sqla_bundle.DateTime(timezone=True),
                  server_default=sa.text('CURRENT_TIMESTAMP'), nullable=False),
        sa.PrimaryKeyConstraint('id', name=op.f('pk_flask_sessions')),
        sa.UniqueConstraint('session_id', name=op.f('uq_flask_sessions_session_id'))
    )
    # ### end Alembic commands ###

def downgrade():
    # ### commands auto generated by Alembic - please adjust! ###
    op.drop_table('flask_sessions')
    # ### end Alembic commands ###

Once you’re satisfied, run the migration:

flask db upgrade

That’s it for setting up server side sessions! Let’s make a commit before we continue:

git add .
git status
git commit -m 'install session bundle'

And proceed to Authentication and Authorization using the Security Bundle.