Skip to main content
Flask Basics Tutorial
CHAPTER 11 Beginner

User Authentication and Sessions

Updated: May 14, 2026
35 min read

# CHAPTER 11

User Authentication and Sessions

1. Introduction

Because the internet is stateless, the server immediately forgets who you are after loading a webpage. So how do websites keep you logged in as you click from page to page? The answer is Sessions. In this chapter, we will learn how to use Flask's built-in session dictionary to remember users, how to securely hash passwords before saving them to the database, and how to restrict access to specific routes using decorators.

2. Learning Objectives

By the end of this chapter, you will be able to:
  • Understand how Flask Sessions work using cryptographically signed cookies.
  • Set a SECRET_KEY in app.config.
  • Use Werkzeug to securely hash and verify passwords.
  • Store data in the session dictionary.
  • Protect routes by checking the session state.

3. Beginner-Friendly Explanation

Imagine going to a highly secure theme park.
  • Registration (Password Hashing): You give the park your fingerprint. The park scrambles your fingerprint through a complex math formula (Hashing) and saves the scrambled version in their database. They do NOT save your real fingerprint.
  • Login (Verification): You return the next day. You scan your fingerprint. The machine runs the math formula again and checks if the new scrambled image matches the one in the database.
  • Sessions (The Wristband): The park verifies you, but they don't want you to scan your finger at every single roller coaster. So, they hand you a tamper-proof VIP Wristband (The Session Cookie). For the rest of the day, you just flash the wristband, and the roller coaster attendants let you on instantly.

4. Step 1: Security Configuration

Before we can use Sessions, Flask requires us to set a secret cryptographic key. If we don't, Flask will crash.

In app.py:

python
123456
import os
from flask import Flask, session

app = Flask(__name__)
# Used to digitally sign the session cookie. Keep this secret!
app.config['SECRET_KEY'] = 'my_super_secret_random_string_123'

5. Step 2: Password Hashing

Never, ever save plain text passwords in a database. If a hacker steals your database, they steal every user's password. We use Flask's underlying library (Werkzeug) to scramble them.

In app.py:

python
123456789101112131415161718
from werkzeug.security import generate_password_hash, check_password_hash

@app.route('/register', methods=['GET', 'POST'])
def register():
    if request.method == 'POST':
        uname = request.form.get('username')
        pwd = request.form.get('password')
        
        # Scramble the password securely!
        hashed_pwd = generate_password_hash(pwd)
        
        # Save the HASH to the database, not the raw password.
        new_user = User(username=uname, password=hashed_pwd)
        db.session.add(new_user)
        db.session.commit()
        return redirect(url_for('login'))
        
    return render_template('register.html')

6. Step 3: Login and Creating the Session

When a user logs in, we verify the hash. If correct, we hand them the "wristband" by storing their ID inside Flask's global session dictionary.

In app.py:

python
123456789101112131415161718
@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        uname = request.form.get('username')
        pwd = request.form.get('password')
        
        user = User.query.filter_by(username=uname).first()
        
        # Check if user exists AND if the password matches the hash
        if user and check_password_hash(user.password, pwd):
            
            # SUCCESS! Give them the wristband.
            session['user_id'] = user.id
            return redirect(url_for('dashboard'))
            
        return "Invalid credentials."
        
    return render_template('login.html')

7. Step 4: Protecting Routes (Authorization)

Now we have a /dashboard route. We must check if the user is wearing the wristband before showing them the page.
python
123456789
@app.route('/dashboard')
def dashboard():
    # Check if 'user_id' is in the session dictionary
    if 'user_id' not in session:
        return redirect(url_for('login')) # Kick them out!
        
    # If they are logged in, fetch their specific data
    current_user = User.query.get(session['user_id'])
    return f"Welcome to your private dashboard, {current_user.username}!"

8. Step 5: Logging Out

To log out, simply remove the user's ID from the session dictionary.
python
12345
@app.route('/logout')
def logout():
    # .pop() removes the key safely
    session.pop('user_id', None)
    return redirect(url_for('home'))

9. Backend Workflow: Flask-Login

Checking if 'userid' not in session: on every single route gets tedious. In professional applications, developers use a popular extension called Flask-Login. It handles session management perfectly and allows you to protect routes simply by writing @loginrequired directly above your View function.

10. Best Practices

  • Session Data Size: Flask stores the session dictionary inside a cryptographic cookie sent back to the user's browser. Cookies have a strict size limit of 4KB. Never store large objects (like a whole User database object or large strings) in the session. Only store tiny identifiers like the userid.

11. Common Mistakes

  • Leaking the Secret Key: Beginners often hardcode app.config['SECRETKEY'] = '12345' and push it to GitHub. If a hacker knows your secret key, they can forge their own session cookie and magically log in as the Administrator! Always hide your secret key in an Environment Variable (Chapter 19).

12. Exercises

  1. 1. Trace the flow: A user registers with the password hello123. Explain exactly what is saved to the SQLite database, and what happens when they attempt to log in with hello123 the next day.

13. Coding Challenges

  • Challenge: In your base.html template, you can access the session object directly! Write an {% if 'userid' in session %} block in your Navbar. If they are logged in, show a link to "Dashboard" and "Logout". If they are NOT logged in, show a link to "Login" and "Register".

14. MCQs with Answers

Question 1

What is the primary purpose of the app.config['SECRETKEY'] variable in a Flask application?

Question 2

When authenticating a user during login, which Werkzeug function is used to compare a plain-text password submitted in the HTML form against the scrambled password stored in the database?

15. Interview Questions

  • Q: Explain how Flask implements Sessions by default. Where is the session data actually stored, and how does Flask prevent the client from modifying that data?
  • Q: Why is it an unacceptable security practice to store plain-text passwords in a database? How does a hashing algorithm like PBKDF2 or bcrypt mitigate database breaches?

16. FAQs

Q: Can I store the session data on the server instead of the user's browser cookie? A: Yes. If you have sensitive session data, you can use an extension called Flask-Session which stores the cookie data securely on your server's RAM (using Redis) or in the database, sending only a meaningless Session ID token to the user's browser.

17. Summary

In Chapter 11, we conquered the stateless nature of the internet. By establishing a SECRET
KEY, we enabled Flask's secure Session dictionary to track user identities across multiple HTTP requests via signed cookies. We implemented robust security by hashing passwords before database insertion using Werkzeug. Finally, we learned how to restrict access to protected View functions by validating the session state, enabling secure user authentication workflows.

18. Next Chapter Recommendation

Our app.py file is getting massive. It holds our routes, database models, and login logic. We must organize this chaos. Proceed to Chapter 12: Flask Blueprints and Project Structure.

Finish this Chapter

Save your progress on your learning path and prepare for coding interview challenges.

Discussion

Join the discussion

Log in or create a free account to participate.

Sort: ·