Skip to main content

Welcome to a Grasp lesson

Create a free account to keep studying and create your own study path.

Lesson 20

User Authentication and Protected Routes

Recommended resources

Hello! Welcome to the next lesson in your journey to becoming a Full Stack AI Developer.

In our last lesson, we established the crucial theoretical foundations for secure authentication: understanding why we must hash passwords and how session-based authentication allows a web server to "remember" a user across multiple requests.

Today, we'll turn that theory into practice. The learning outcome for this lesson is to implement user registration, login, logout, and protected routes. We'll use the forms you built previously and integrate powerful Flask extensions to create a complete, secure authentication system from scratch. This is a fundamental skill for any web developer.

Let's get started.

1. Secure User Registration

Our first step is to take the data from the registration form, securely hash the password, and save the new user to our database. We'll also ensure that each user has a unique username and email.

Password Hashing and Saving Users

In the last lesson, we discussed using slow, salted hash functions. The Flask-Bcrypt extension provides a convenient way to use the robust bcrypt algorithm within Flask.

The following video from Corey Schafer's excellent Flask series will walk you through installing Flask-Bcrypt, initializing it, and using it in your registration route to securely handle passwords. It also demonstrates how to add custom validators to your form to prevent duplicate usernames and emails, which is a much more user-friendly approach than letting the database raise an error.

Python Flask Tutorial: Full-Featured Web App Part 6 - User Authentication

This video covers the entire process of building a user authentication system. We'll watch it in sections. First, let's focus on implementing a secure registration process.

Watch from the beginning (00:29) to 19:34. Pay close attention to these three key parts: Password Hashing (00:29 - 04:01): How to install and use Flask-Bcrypt to generate and check password hashes. Registration Logic (04:01 - 08:15): How to integrate password hashing into the registration route to save a new user with a hashed password. Custom Validation (10:09 - 19:34): How to add validate_username and validate_email methods to your registration form to check if a user already exists, providing a clean user experience.

To summarize the key steps for registration:

  1. Install and Initialize:
    pip install flask-bcrypt
    
    In your app's __init__.py:
    from flask_bcrypt import Bcrypt
    bcrypt = Bcrypt(app)
    
  2. Hash Password in Route: In your register route, after the form validates:
    hashed_password = bcrypt.generate_password_hash(form.password.data).decode('utf-8')
    user = User(username=form.username.data, email=form.email.data, password=hashed_password)
    db.session.add(user)
    db.session.commit()
    
  3. Add Custom Validators: In your forms.py, inside the RegistrationForm class:
    from .models import User
    from wtforms.validators import ValidationError
    
    def validate_username(self, username):
        user = User.query.filter_by(username=username.data).first()
        if user:
            raise ValidationError('That username is taken. Please choose a different one.')
            
    def validate_email(self, email):
        user = User.query.filter_by(email=email.data).first()
        if user:
            raise ValidationError('That email is taken. Please choose a different one.')
    

2. Managing User Sessions with Flask-Login

Now that users can register, we need a way to manage their sessions when they log in. This is where Flask-Login comes in. It handles all the background work of session management, such as creating session cookies and providing access to the currently logged-in user.

The setup involves three crucial steps:

  1. Initializing the LoginManager.
  2. Preparing your User model to work with Flask-Login.
  3. Creating a user_loader function.

Let's continue with the same video to see how this is done.

Python Flask Tutorial: Full-Featured Web App Part 6 - User Authentication

This section of the video explains how to set up Flask-Login to manage user sessions.

Watch from 19:34 to 24:05. Focus on understanding the role of: The LoginManager class. The UserMixin class that you add to your User model. The @login_manager.user_loader decorated function, which tells Flask-Login how to find a specific user by their ID.

The user_loader function is the bridge between Flask-Login's session management and your user database. When a request comes in, Flask-Login reads the user ID from the session cookie and then calls your user_loader function with that ID to retrieve the actual user object. This object is then made available as current_user.

This diagram illustrates the flow after a user has logged in.

User Authentication Flow with Sessions
This diagram shows how Flask-Login works. When a user is logged in, their ID is stored in a session. For each new request, the `user_loader` function uses this ID to fetch the user from the database, making it available as the `current_user` object. If no session exists, the user is considered anonymous.

3. Implementing Login and Logout

With Flask-Login configured, we can now implement the core login and logout functionality.

Login

The login process involves:

  1. Finding the user in the database by their email or username.
  2. Verifying their password using bcrypt.check_password_hash().
  3. If credentials are valid, calling login_user() to create the session.

Logout

The logout process is even simpler: just call the logout_user() function to clear the session.

Conditional Navigation

A good user experience requires showing relevant navigation links. Logged-in users should see "Account" and "Logout," while anonymous users should see "Login" and "Register." This is easily achieved in your Jinja2 templates using current_user.is_authenticated.

Let's see this all in action.

Python Flask Tutorial: Full-Featured Web App Part 6 - User Authentication

The next sections of the video demonstrate how to build the login and logout routes and update the navigation bar.

Watch these two segments: Login Route (24:05 - 28:26): See how to query the user, check the password, and use login_user(). Logout and Navigation (31:27 - 35:08): Learn how to create the logout route with logout_user() and use current_user.is_authenticated in the template to display the correct links.


4. Protected Routes and Final Touches

The primary purpose of authentication is to restrict access to certain parts of your application. Flask-Login makes this incredibly simple with the @login_required decorator.

We also want to improve the user experience by redirecting users back to the page they were trying to access before they were prompted to log in.

Python Flask Tutorial: Full-Featured Web App Part 6 - User Authentication

Let's finish by implementing route protection and a few final enhancements.

Watch from 29:32 to the end of the video (46:21). You will learn: Preventing Access (29:32 - 31:27): How to stop already logged-in users from visiting the login/register pages. Route Protection (35:08 - 40:01): How to use the @login_required decorator and configure the login_view. Redirects and Messaging (40:01 - 46:21): How to handle the next query parameter for a smooth redirect after login and how to customize flashed messages.

To make a route require authentication, you do two things:

  1. Tell Flask-Login where your login page is in your __init__.py:
    login_manager.login_view = 'auth.login' # 'auth.login' is the endpoint name
    
  2. Add the decorator to any route you want to protect:
    from flask_login import login_required
    
    @app.route('/account')
    @login_required
    def account():
    
    
    
        # This code will only run if the user is logged in
        return render_template('account.html')
    

This flowchart provides a high-level overview of the complete authentication system you've just built.

User Authentication Flowchart
This flowchart shows the complete user journey through your application: signing up, logging in, accessing content, and logging out.

Conclusion

Congratulations! You have now implemented a complete and secure user authentication system in Flask. This is a major milestone and a foundational component of almost every web application you will build.

Key Takeaways:

  • Registration: Use Flask-Bcrypt's generate_password_hash() to securely store passwords and implement custom form validators to check for unique user details.
  • Flask-Login Setup: Configure Flask-Login by initializing LoginManager, adding UserMixin to your User model, and creating a @login_manager.user_loader callback.
  • Login/Logout: Use login_user() to create a session and logout_user() to destroy it.
  • Access Control: Use the @login_required decorator to protect routes and current_user.is_authenticated in templates to control what the user sees.
  • User Experience: Improve flow by redirecting users to their intended page after login using the next parameter.

In our next lesson, we'll shift gears to another core component of modern web development: building RESTful APIs. You'll learn the principles behind APIs and how to build your first endpoints using Flask, which will eventually allow your AI models to communicate with other services and front-end applications.