Authentication & Login

Reviewed & published by Brayan K

Authentication is the process of verifying who a user is — confirming a person owns the account they claim — so your app can show private pages, save their data, and keep everyone else out.

Part of the free Flask course at LearnCodingFast — hands-on lessons with worked examples and the output they print, plus practice exercises and a quick quiz.

In this lesson you'll hash passwords securely with Werkzeug, manage user sessions with Flask-Login, and protect routes so only signed-in users can reach them.

What You'll Learn in This Lesson

1 Hashing Passwords Securely

A password hash is a one-way scrambled version of a password. You can check whether a guess matches the hash, but you can never turn the hash back into the original password.

Werkzeug — the library Flask is built on — ships two helpers for this. Use generate_password_hash when a user registers, and check_password_hash when they log in. Never store the raw password.

# Hashing and verifying passwords with Werkzeug
from werkzeug.security import generate_password_hash, check_password_hash

# When a user registers, store the HASH, not the password.
raw_password = "hunter2"
hashed = generate_password_hash(raw_password)

print("Stored in database:", hashed)
# Notice the hash is long and unreadable — that is the point.

# When a user logs in, compare their guess to the stored hash.
print("Correct password:", check_password_hash(hashed, "hunter2"))
print("Wrong password:  ", check_password_hash(hashed, "letmein"))

2 Setting Up Flask-Login

Flask-Login tracks which user is signed in across requests. You create a LoginManager, mix UserMixin into your model, and tell Flask-Login how to load a user from their stored ID.

# Wiring up Flask-Login with a User model
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager, UserMixin
from werkzeug.security import generate_password_hash

app = Flask(__name__)
app.config["SECRET_KEY"] = "change-this-in-production"
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///users.db"
db = SQLAlchemy(app)

# The LoginManager connects Flask-Login to your app.
login_manager = LoginManager(app)
login_manager.login_view = "login"   # where to redirect anonymous users

# UserMixin adds is_authenticated, get_id, and friends for free.
class User(db.Model, UserMixin):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(80), unique=True, nullable=False)
    password_hash = db.Column(db.String(255), nullable=False)

# Flask-Login calls this to reload a user from the session.
@login_manager.user_loader
def load_user(user_id):
    return db.session.get(User, int(user_id))

print("User model and LoginManager configured.")

# ✅ Expected output:
# User model and LoginManager configured.

3 Login, Logout & Protected Routes

With the model in place you can write the three core routes. login_user starts a session, logout_user ends it, and @login_required guards any page that needs a signed-in visitor.

# Register, login, logout, and a protected dashboard
from flask import Flask, request, redirect, url_for, render_template_string
from flask_login import login_user, logout_user, login_required, current_user
from werkzeug.security import generate_password_hash, check_password_hash

# (db, User, login_manager assumed configured as in section 2)

@app.route("/register", methods=["GET", "POST"])
def register():
    if request.method == "POST":
        user = User(
            username=request.form["username"],
            password_hash=generate_password_hash(request.form["password"]),
        )
        db.session.add(user)
        db.session.commit()
        return redirect(url_for("login"))
    return render_template_string("<form method='post'>...</form>")

@app.route("/login", methods=["GET", "POST"])
def login():
    if request.method == "POST":
        user = User.query.filter_by(username=request.form["username"]).first()
        if user and check_password_hash(user.password_hash, request.form["password"]):
            login_user(user)               # start the session
            return redirect(url_for("dashboard"))
        return "Invalid credentials", 401
    return render_template_string("<form method='post'>...</form>")

@app.route("/logout")
@login_required
def logout():
    logout_user()                          # end the session
    return redirect(url_for("login"))

@app.route("/dashboard")
@login_required                            # blocks anonymous visitors
def dashboard():
    return f"Welcome back, {current_user.username}!"

print("Auth routes ready. Start the server with: flask run")

Inside any template or view you can use current_user to read the logged-in user, or check current_user.is_authenticated to show different content to guests and members.

🎯 Your Turn: Fill in the Blanks

Complete the login route below. Replace each ___ so it verifies the password and starts a session.

# 🎯 YOUR TURN: replace each ___ to finish the login route
from flask_login import ___          # the function that starts a session
from werkzeug.security import ___    # the function that verifies a password

@app.route("/login", methods=["GET", "POST"])
def login():
    user = User.query.filter_by(username=request.form["username"]).first()
    # Check the submitted password against the stored hash
    if user and ___(user.password_hash, request.form["password"]):
        ___(user)                    # log the user in
        return redirect(url_for("dashboard"))
    return "Invalid credentials", 401

print("Fill in the blanks to make login work!")

Common Errors & Quick Reference

❌ RuntimeError: Missing user_loader or request_loader

You forgot to register a @login_manager.user_loader function. Flask-Login needs it to reload the user from the session on every request.

❌ The session secret key is not set

Set app.config["SECRET_KEY"] to a long random string. Without it, Flask cannot sign the session cookie and login will fail.

TaskCommand / Code
Install Flask-Loginpip install flask-login
Hash a passwordgenerate_password_hash(pw)
Verify a passwordcheck_password_hash(hash, pw)
Start a sessionlogin_user(user)
Protect a route@login_required

🏆 Mini Challenge: A "My Profile" Page

Add a protected profile page that greets the logged-in user by name.

# 🏆 Mini Challenge: a protected profile page
from flask_login import login_required, current_user

@app.route("/profile")
@login_required
def profile():
    # Only signed-in users reach this line.
    return f"This is the profile of {current_user.username}."

# Anonymous visitors are redirected to login_manager.login_view ("login").
print("Visit /profile while logged in to see your name.")

❓ Frequently Asked Questions

Lesson complete — your app can sign users in!

You can now hash passwords with Werkzeug, manage sessions with Flask-Login, and lock pages behind @login_required. That is the foundation of every account-based web app.

Practice quiz

Which Werkzeug function creates a password hash when a user registers?

  • generate_password_hash
  • hashlib.md5
  • encrypt_password
  • make_hash

Answer: generate_password_hash. generate_password_hash creates an irreversible hash on registration.

Which function verifies a password guess at login?

  • verify_hash
  • check_password_hash
  • compare_password
  • match_hash

Answer: check_password_hash. check_password_hash(hash, guess) verifies the guess against the stored hash.

Why hash passwords instead of storing them plain?

  • It saves storage space
  • It speeds up login
  • If the database leaks, hashes can't be reversed
  • Flask requires it

Answer: If the database leaks, hashes can't be reversed. Hashing is irreversible, so a leaked database does not expose passwords.

What does the @login_required decorator do?

  • Hashes the password
  • Logs all requests
  • Creates a session cookie
  • Blocks the route unless a user is logged in

Answer: Blocks the route unless a user is logged in. @login_required blocks access and redirects anonymous visitors to the login page.

Which function starts a user session in Flask-Login?

  • login_user(user)
  • start_session(user)
  • authenticate(user)
  • session.login(user)

Answer: login_user(user). login_user(user) starts the session.

Which class adds default methods like is_authenticated to your model?

  • LoginManager
  • UserMixin
  • AnonymousUser
  • BaseModel

Answer: UserMixin. UserMixin adds is_authenticated, is_active, get_id, and more.

Why must SECRET_KEY be set for Flask-Login?

  • To hash passwords
  • To name the app
  • To sign the session cookie so it can be trusted
  • To enable debug mode

Answer: To sign the session cookie so it can be trusted. Flask-Login needs SECRET_KEY to sign the session cookie.

What does @login_manager.user_loader register?

  • A logout handler
  • A password hasher
  • A route guard
  • A function to reload the user from the session

Answer: A function to reload the user from the session. user_loader reloads the user from their stored id on each request.

How do you read the currently signed-in user in a view?

  • current_user
  • session.user
  • g.login
  • request.user

Answer: current_user. current_user gives the logged-in user (or an anonymous user).

Which function ends a user's session?

  • session.clear()
  • logout_user()
  • end_login()
  • current_user.logout()

Answer: logout_user(). logout_user() ends the session.

Continue this course

Frequently asked questions

What is Flask-Login?

Flask-Login is an extension that manages user sessions for you. It handles logging users in and out, remembering them across requests, and protecting routes that require a signed-in user.

Why should I hash passwords instead of storing them directly?

Storing plain-text passwords is dangerous — if your database leaks, every account is exposed. Hashing with werkzeug's generate_password_hash turns the password into an irreversible string, so even you cannot read the original.

What does @login_required do?

The @login_required decorator blocks access to a route unless a user is logged in. Anonymous visitors are redirected to your login page automatically.

What is UserMixin used for?

UserMixin is a helper class from Flask-Login that adds the default methods (is_authenticated, is_active, get_id, and so on) your User model needs to work with the login system.