This video is available to students only

How to Log Out Users From a Flask App and Test Authentication

Project Source Code

Get the project source code below, and follow along with the lesson material.

Download Project Source Code

To set up the project on your local machine, please follow the directions provided in the README.md file. If you run into any issues with running the project source code, then feel free to reach out to the author in the course's Discord channel.

Requiring Logins

You might want to make certain routes only accessible to logged in users. To do that you'll first need to tell Flask-Login what to do with requests to those routes that are not from logged in users.

The most common action would be send users who try to access to the login page. In order to send users back to the page they were trying to visit before after the login, we'll store the page the were trying to access in their cookies (through the use Flask's session. session is the interface Flask provides for storing and reading writing data in cookies).

from flask import ..., request, session

@login_manager.unauthorized_handler
def unauthorized():
    session['after_login'] = request.url
    return redirect(url_for('user.login'))

Then on the login (and/or signup) route, we'll want to make the redirect attempt to go to the page we stored in the session before. If there's no value stored in the session, we can redirect Users to the Products home page.

    login_user(user)
    return redirect(session.get('after_login') or url_for("products.index"))

To mark that a route requires a user to be logged in, Flask-Login provides a decorator we can add to each route called login_required. To make the product creation route in blueprints/products.py require a login,

from flask_login import login_required
...
@products.route('/create', methods=['GET', 'POST'])
@login_required
def create():
    form = ProductForm()
    ...

Logging out

Implementing log outs requires using the logout_user function from Flask-Login. To ensure that only logged in users can access it, we can use the @login_required decorator.

from flask_login import login_user, logout_user, login_required
...

@user_bp.route('/logout', methods=["GET", "POST"])
@login_required
def logout():
    logout_user()
    return redirect(url_for('products.index'))
    # You may want to only allow access through a valid POST request

Testing

We added a few forms as well as a model here. The first part to test, is our User.create model as well as our password validations.

In tests/test_user.py, we can define two unit tests.

import pytest

from yumroad.models import db, User

EXAMPLE_EMAIL = "[email protected]"
EXAMPLE_PASSWORD = "test"

# Unit Tests
def test_user_creation(client, init_database):
    assert User.query.count() == 0
    user = create_user()
    assert User.query.count() == 1
    assert user.password is not EXAMPLE_PASSWORD

def test_email_password_validation(client, init_database):
    assert User.query.count() == 0
    with pytest.raises(ValueError):
        create_user('', EXAMPLE_PASSWORD)
    with pytest.raises(ValueError):
        create_user(EXAMPLE_EMAIL, '')
    assert User.query.count() == 0

To add functional tests, we can fill out the sign up and login forms with the same credentials. There are many scenarios here, and many of them will depend on having a logged in user, for which we can define a fixture in conftest.py

@pytest.fixture
def authenticated_request(client):
    new_user = User.create("[email protected]", "examplepass")
    db.session.add(new_user)
    db.session.commit()

    response = client.post(url_for('user.login'), data={
        'email': "[email protected]",
        'password': "examplepass"
    }, follow_redirects=True)
    yield client

This lesson preview is part of the Fullstack Flask: Build a Complete SaaS App with Flask course and can be unlocked immediately with a single-time purchase. Already have access to this course? Log in here.

Unlock This Course

Get unlimited access to Fullstack Flask: Build a Complete SaaS App with Flask with a single-time purchase.

Thumbnail for the \newline course Fullstack Flask: Build a Complete SaaS App with Flask