Examples of User Authentication in Flask: 3 Practical Patterns You’ll Actually Use

If you’re building anything more serious than a toy app, you need user logins. The good news: Flask makes that surprisingly straightforward, and seeing real examples of user authentication in Flask is the fastest way to get it right. In this guide, we’ll walk through **3 practical examples of user authentication in Flask: 3 practical examples** that cover the patterns you’ll hit in real projects: classic email/password login, social login with Google, and token-based auth for APIs. Instead of abstract theory, we’ll wire up realistic flows with `flask-login`, hashed passwords, secure session handling, and JSON Web Tokens (JWTs). Along the way, we’ll look at security best practices, common mistakes, and how modern apps in 2024–2025 handle authentication in production. If you’re looking for clear, opinionated examples of user authentication in Flask that you can copy, tweak, and ship, you’re in the right place.
Written by
Jamie
Published
Updated

Most Flask apps still start with the same foundation: a user table in a database, email/password login, and a session cookie. This is the baseline example of user authentication in Flask that everything else builds on.

Here’s a minimal but realistic setup using:

  • flask-login for session management
  • werkzeug.security for password hashing
  • SQLAlchemy for persistence
## app.py
from flask import Flask, render_template, request, redirect, url_for, flash
from flask_sqlalchemy import SQLAlchemy
from flask_login import (
    LoginManager, UserMixin, login_user,
    login_required, logout_user, current_user
)
from werkzeug.security import generate_password_hash, check_password_hash
import os

app = Flask(__name__)
app.config['SECRET_KEY'] = os.environ.get('SECRET_KEY', 'dev-secret')
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///users.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

db = SQLAlchemy(app)
login_manager = LoginManager(app)
login_manager.login_view = 'login'

class User(UserMixin, db.Model):
    id = db.Column(db.Integer, primary_key=True)
    email = db.Column(db.String(255), unique=True, nullable=False)
    password_hash = db.Column(db.String(255), nullable=False)

    def set_password(self, password: str):
        self.password_hash = generate_password_hash(password)

    def check_password(self, password: str) -> bool:
        return check_password_hash(self.password_hash, password)

@login_manager.user_loader
def load_user(user_id):
    return User.query.get(int(user_id))

@app.route('/register', methods=['GET', 'POST'])
def register():
    if request.method == 'POST':
        email = request.form['email'].strip().lower()
        password = request.form['password']

        if User.query.filter_by(email=email).first():
            flash('Email already registered.')
            return redirect(url_for('register'))

        user = User(email=email)
        user.set_password(password)
        db.session.add(user)
        db.session.commit()
        flash('Registration successful. Please log in.')
        return redirect(url_for('login'))

    return render_template('register.html')

@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        email = request.form['email'].strip().lower()
        password = request.form['password']
        user = User.query.filter_by(email=email).first()

        if not user or not user.check_password(password):
            flash('Invalid credentials.')
            return redirect(url_for('login'))

        login_user(user, remember='remember_me' in request.form)
        return redirect(url_for('dashboard'))

    return render_template('login.html')

@app.route('/dashboard')
@login_required
def dashboard():
    return f"Hello, {current_user.email}!"  # Replace with real template

@app.route('/logout')
@login_required
def logout():
    logout_user()
    flash('You have been logged out.')
    return redirect(url_for('login'))

if __name__ == '__main__':
    with app.app_context():
        db.create_all()
    app.run(debug=True)

This first pattern is the baseline in most examples of user authentication in Flask: 3 practical examples you’ll see online, but a lot of tutorials stop too early. In real apps, you’ll usually extend this with:

  • Email verification using a signed token (for instance with itsdangerous)
  • Password reset flows
  • Account lockout after repeated failed logins
  • Multi-factor authentication (MFA) with TOTP apps like Google Authenticator

That’s where the next examples come in.


Example 2: Social Login with Google (OAuth 2.0)

The second of our best examples of user authentication in Flask is social login. Users are tired of new passwords, and many modern apps default to “Continue with Google” or similar. Under the hood, that’s usually OAuth 2.0 or OpenID Connect.

For Flask in 2024–2025, the cleaner approach is to use Authlib, which actively tracks OAuth standards. Here’s a trimmed-down Google login flow.

Google OAuth example of user authentication in Flask

## oauth.py
from authlib.integrations.flask_client import OAuth
from flask import current_app

oauth = OAuth()

def init_oauth(app):
    oauth.init_app(app)

    oauth.register(
        name='google',
        client_id=app.config['GOOGLE_CLIENT_ID'],
        client_secret=app.config['GOOGLE_CLIENT_SECRET'],
        server_metadata_url='https://accounts.google.com/.well-known/openid-configuration',
        client_kwargs={'scope': 'openid email profile'}
    )

    return oauth
## app.py (excerpt)
from flask import Flask, redirect, url_for, session
from models import db, User
from flask_login import login_user
from oauth import init_oauth

app = Flask(__name__)
app.config.from_mapping(
    SECRET_KEY='dev',
    SQLALCHEMY_DATABASE_URI='sqlite:///users.db',
    GOOGLE_CLIENT_ID='your-google-client-id',
    GOOGLE_CLIENT_SECRET='your-google-client-secret',
)

db.init_app(app)
oauth = init_oauth(app)

@app.route('/login/google')
def login_google():
    redirect_uri = url_for('authorize_google', _external=True)
    return oauth.google.authorize_redirect(redirect_uri)

@app.route('/auth/google/callback')
def authorize_google():
    token = oauth.google.authorize_access_token()
    user_info = oauth.google.parse_id_token(token)

    email = user_info['email'].lower()
    user = User.query.filter_by(email=email).first()

    if not user:
        user = User(email=email)
        db.session.add(user)
        db.session.commit()

    login_user(user)
    return redirect(url_for('dashboard'))

This pattern shows another angle in our examples of user authentication in Flask: 3 practical examples: you don’t always control the password. Instead, you trust Google’s identity system and just create a local record.

A few practical notes that matter in 2024–2025:

  • Use HTTPS in production. OAuth redirects over plain HTTP are a security disaster.
  • Lock down redirect URIs in the Google Cloud Console.
  • Store only what you need. Email and a stable subject identifier are usually enough.

For background on why federated login reduces password fatigue and related risk, see guidance on password habits from the National Institute of Standards and Technology (NIST).


Example 3: JWT-Based API Authentication for SPAs and Mobile Apps

The third pattern rounds out our examples of user authentication in Flask: 3 practical examples: token-based auth for APIs. This is what you’ll use for:

  • Single-page apps (React, Vue, Svelte) hitting a Flask backend
  • Native mobile apps (iOS, Android)
  • Third-party integrations consuming your API

Here we’ll use flask-jwt-extended to issue and verify JSON Web Tokens.

JWT login and protected route

## app_api.py
from flask import Flask, request, jsonify
from flask_sqlalchemy import SQLAlchemy
from flask_jwt_extended import (
    JWTManager, create_access_token,
    jwt_required, get_jwt_identity
)
from werkzeug.security import check_password_hash

app = Flask(__name__)
app.config['SECRET_KEY'] = 'dev'
app.config['JWT_SECRET_KEY'] = 'jwt-secret'  # use env vars in prod
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///users.db'

db = SQLAlchemy(app)
jwt = JWTManager(app)

class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    email = db.Column(db.String(255), unique=True, nullable=False)
    password_hash = db.Column(db.String(255), nullable=False)

@app.post('/api/login')
def api_login():
    data = request.get_json() or {}
    email = data.get('email', '').lower()
    password = data.get('password', '')

    user = User.query.filter_by(email=email).first()
    if not user or not check_password_hash(user.password_hash, password):
        return jsonify({'msg': 'Bad credentials'}), 401

    access_token = create_access_token(identity=user.id)
    return jsonify(access_token=access_token)

@app.get('/api/me')
@jwt_required()
def api_me():
    user_id = get_jwt_identity()
    user = User.query.get_or_404(user_id)
    return jsonify({'id': user.id, 'email': user.email})

if __name__ == '__main__':
    with app.app_context():
        db.create_all()
    app.run(debug=True)

This pattern is a different flavor than the earlier examples of user authentication in Flask because there are no server-side sessions. The client stores the token (preferably in memory or an HTTP-only cookie) and includes it on each request.

In 2024–2025, you’ll see many production APIs using short-lived access tokens plus refresh tokens, often combined with:

  • Rate limiting to reduce brute-force attempts
  • IP-based anomaly detection and device fingerprinting
  • Centralized identity providers like Auth0 or Okta when teams don’t want to own the whole auth stack

For broader context on API security patterns, the OWASP API Security Project at owasp.org is worth bookmarking.


Six Real-World Ways These Patterns Show Up

To make this less abstract, here are real examples of how teams combine these patterns in production:

  • A small internal tool at a university: Google login only using the OAuth pattern, restricted to @school.edu emails.
  • A consumer-facing SaaS dashboard: Email/password with flask-login plus MFA, and later they add JWTs for a React-powered reporting API.
  • A healthcare scheduling app: Email/password plus enforced strong passwords and rate limiting, influenced by security guidance like that published by NIST and health privacy expectations.
  • A mobile-first fitness app: JWT auth only, with sign-in via email or Apple/Google ID, all hitting a Flask-based API.
  • An internal analytics system: Single sign-on (SSO) via corporate identity provider (SAML/OIDC), wired into Flask similarly to the Google example.
  • A public developer API: API keys for server-to-server calls, plus optional OAuth 2.0 client credentials for partners, implemented alongside the JWT example.

These are the kinds of real examples of user authentication in Flask that show up in 2024–2025 projects, far beyond the “hello world” login form.


Choosing Between the 3 Practical Examples of User Authentication in Flask

If you’re wondering how to pick among these examples of user authentication in Flask: 3 practical examples, here’s the blunt version:

  • If you’re building a classic web app with server-rendered HTML: start with email/password + flask-login and add MFA later.
  • If your users already live in Google Workspace, Microsoft 365, or a campus identity provider: OAuth/OIDC social or enterprise login will cut support tickets and password resets.
  • If you’re exposing a public or mobile API: JWT-based auth is the pattern your clients will expect.

In many real apps, you’ll combine them. A common pattern is:

  • Use flask-login for browser sessions
  • Use JWTs for API calls from SPAs or mobile
  • Use OAuth to let users sign in without creating yet another password

That combination gives you flexible, modern authentication without locking you into a single vendor.


Security Practices You Should Not Skip

User authentication is where attackers focus. While this article is about examples of user authentication in Flask, ignoring security details turns those examples into liabilities.

A few practices that deserve attention:

  • Hash passwords correctly. Use werkzeug.security (which wraps modern hash algorithms) or dedicated libraries like argon2-cffi. Never store plain text passwords.
  • Use HTTPS everywhere in production. TLS is non‑negotiable for logins. Without it, even the best examples of user authentication in Flask won’t protect users.
  • Protect against CSRF for form-based logins and state-changing actions. Libraries like Flask-WTF make this straightforward.
  • Limit login attempts and log suspicious behavior. OWASP’s guidance on authentication and session management at owasp.org is a good reference.
  • Educate users about password hygiene and phishing. While not Flask-specific, user behavior is a major factor in breaches; public resources like the Cybersecurity & Infrastructure Security Agency (CISA) offer practical guidance.

In other words: the code examples show you how. These practices help keep that code from becoming the weakest link.


FAQ: Common Questions About Flask Authentication

What are some real examples of user authentication in Flask for production apps?

Real projects usually combine patterns. A typical SaaS app might use email/password with flask-login for browser sessions, JWTs for its public API, and Google OAuth for fast sign‑ups. Internal tools often rely on SSO via OAuth or SAML. All of these are realistic examples of user authentication in Flask: 3 practical examples that you can adapt.

Which example of user authentication in Flask is best for a simple side project?

For a side project or MVP, go with the first pattern: email/password using flask-login and SQLAlchemy. It’s fast to implement, easy to reason about, and you can bolt on MFA or OAuth later without rewriting everything.

Can I mix session-based auth and JWTs in the same Flask app?

Yes. Many teams use flask-login for classic web pages and JWTs for API endpoints consumed by SPAs or mobile apps. Just be clear about which routes use which method, and keep your authorization checks consistent.

How do I secure password reset and email verification flows?

Use signed, time-limited tokens (for example, via itsdangerous) that you embed in links emailed to the user. Verify the token, then let the user set a new password. Never include the password itself in an email. For general guidance on secure user practices, resources from organizations like CISA are helpful.

Are there production-ready libraries that hide most of this complexity?

Yes. In addition to flask-login, projects like Flask-Security-Too and Flask-User bundle authentication, registration, password reset, and role management. They can be good starting points, but understanding the underlying examples of user authentication in Flask still matters when you need to debug or extend behavior.


If you keep these three patterns in your toolkit—email/password with sessions, OAuth social/enterprise login, and JWT-based API auth—you’ll be able to handle almost any real-world authentication requirement Flask throws at you in 2024 and beyond.

Explore More Flask Code Snippets

Discover more examples and insights in this category.

View All Flask Code Snippets