How to Implement User Authentication in Flask with MySQLAlchemy

Author

Admin

Mar 26, 2025

How to Implement User Authentication in Flask with MySQLAlchemy

In this step-by-step guide, you'll learn how to build a secure user authentication system in Flask using MySQLAlchemy for database operations. We'll cover:

User Registration (Signup)
Login & Logout Functionality
Password Hashing (Security Best Practices)
Session Management
Protected Routes (Dashboard)

This tutorial is perfect for developers who want to add authentication to their Flask applications while using MySQL as the database backend.


Why Flask + MySQLAlchemy for Authentication?

🔹 Flask is a lightweight Python framework ideal for web applications.
🔹 MySQLAlchemy provides an ORM (Object-Relational Mapping) for MySQL, making database operations easier.
🔹 Secure authentication is crucial for protecting user data.

By the end, you'll have a fully functional auth system that you can integrate into any Flask project!


Prerequisites

Before we start, make sure you have:

  • Python 3.6+ installed
  • MySQL Server installed and running
  • Basic knowledge of Flask, SQL, and Python

Step 1: Setting Up the Project

1. Create a Virtual Environment

python -m venv venv
source venv/bin/activate  # On Windows: venv\Scripts\activate

2. Install Required Packages

pip install flask flask-sqlalchemy flask-login flask-bcrypt flask-wtf

3. Project Structure

flask_auth_mysql/
│
├── app.py                # Main Flask application
├── models.py             # Database models (User)
├── forms.py              # Login & Registration forms
├── templates/            # HTML templates
│   ├── login.html        # Login page
│   ├── register.html     # Registration page
│   ├── dashboard.html    # Protected dashboard
│   └── layout.html       # Base template
└── requirements.txt      # Dependencies

Step 2: Configuring Flask & MySQLAlchemy

1. app.py – Flask Setup

from flask import Flask, render_template, redirect, url_for, flash, request
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager, UserMixin, login_user, logout_user, login_required, current_user
from flask_bcrypt import Bcrypt
from forms import RegistrationForm, LoginForm

app = Flask(__name__)

# Configuration
app.config['SECRET_KEY'] = 'your-secret-key-here'
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://username:password@localhost/flask_auth_db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

# Initialize extensions
db = SQLAlchemy(app)
bcrypt = Bcrypt(app)
login_manager = LoginManager(app)
login_manager.login_view = 'login'

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

# Import models after db initialization
from models import User

# Routes will be added here later

if __name__ == '__main__':
    app.run(debug=True)

2. models.py – User Model

from app import db, bcrypt
from flask_login import UserMixin

class User(db.Model, UserMixin):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(50), unique=True, nullable=False)
    email = db.Column(db.String(100), unique=True, nullable=False)
    password = db.Column(db.String(60), nullable=False)

    def __repr__(self):
        return f"User('{self.username}', '{self.email}')"

3. forms.py – Login & Registration Forms

from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SubmitField
from wtforms.validators import DataRequired, Length, Email, EqualTo

class RegistrationForm(FlaskForm):
    username = StringField('Username', validators=[DataRequired(), Length(min=2, max=20)])
    email = StringField('Email', validators=[DataRequired(), Email()])
    password = PasswordField('Password', validators=[DataRequired()])
    confirm_password = PasswordField('Confirm Password', validators=[DataRequired(), EqualTo('password')])
    submit = SubmitField('Sign Up')

class LoginForm(FlaskForm):
    email = StringField('Email', validators=[DataRequired(), Email()])
    password = PasswordField('Password', validators=[DataRequired()])
    submit = SubmitField('Login')

Step 3: Creating the Database

1. Create MySQL Database

CREATE DATABASE flask_auth_db;

2. Initialize Database in Flask

Run in Python shell:

from app import app, db
with app.app_context():
    db.create_all()

Step 4: Implementing Authentication Routes

1. Registration Route (app.py)

@app.route('/register', methods=['GET', 'POST'])
def register():
    if current_user.is_authenticated:
        return redirect(url_for('dashboard'))
    
    form = RegistrationForm()
    if form.validate_on_submit():
        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()
        flash('Account created! You can now log in.', 'success')
        return redirect(url_for('login'))
    
    return render_template('register.html', form=form)

2. Login Route (app.py)

@app.route('/login', methods=['GET', 'POST'])
def login():
    if current_user.is_authenticated:
        return redirect(url_for('dashboard'))
    
    form = LoginForm()
    if form.validate_on_submit():
        user = User.query.filter_by(email=form.email.data).first()
        if user and bcrypt.check_password_hash(user.password, form.password.data):
            login_user(user)
            next_page = request.args.get('next')
            return redirect(next_page) if next_page else redirect(url_for('dashboard'))
        else:
            flash('Login failed. Check email and password.', 'danger')
    
    return render_template('login.html', form=form)

3. Logout & Dashboard Routes (app.py)

@app.route('/dashboard')
@login_required
def dashboard():
    return render_template('dashboard.html', username=current_user.username)

@app.route('/logout')
def logout():
    logout_user()
    return redirect(url_for('login'))

Step 5: Creating HTML Templates

1. templates/layout.html (Base Template)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Flask Auth with MySQL</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
    <nav class="navbar navbar-expand-lg navbar-dark bg-dark">
        <div class="container">
            <a class="navbar-brand" href="/">Flask Auth</a>
            <div class="navbar-nav ms-auto">
                {% if current_user.is_authenticated %}
                    <a class="nav-link" href="{{ url_for('dashboard') }}">Dashboard</a>
                    <a class="nav-link" href="{{ url_for('logout') }}">Logout</a>
                {% else %}
                    <a class="nav-link" href="{{ url_for('login') }}">Login</a>
                    <a class="nav-link" href="{{ url_for('register') }}">Register</a>
                {% endif %}
            </div>
        </div>
    </nav>

    <div class="container mt-4">
        {% with messages = get_flashed_messages(with_categories=true) %}
            {% if messages %}
                {% for category, message in messages %}
                    <div class="alert alert-{{ category }}">
                        {{ message }}
                    </div>
                {% endfor %}
            {% endif %}
        {% endwith %}

        {% block content %}{% endblock %}
    </div>

    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>

2. templates/register.html

{% extends "layout.html" %}

{% block content %}
<div class="row justify-content-center">
    <div class="col-md-6">
        <h2 class="mb-4">Register</h2>
        <form method="POST" action="">
            {{ form.hidden_tag() }}
            <div class="form-group mb-3">
                {{ form.username.label(class="form-label") }}
                {{ form.username(class="form-control") }}
            </div>
            <div class="form-group mb-3">
                {{ form.email.label(class="form-label") }}
                {{ form.email(class="form-control") }}
            </div>
            <div class="form-group mb-3">
                {{ form.password.label(class="form-label") }}
                {{ form.password(class="form-control") }}
            </div>
            <div class="form-group mb-3">
                {{ form.confirm_password.label(class="form-label") }}
                {{ form.confirm_password(class="form-control") }}
            </div>
            <div class="form-group">
                {{ form.submit(class="btn btn-primary") }}
            </div>
        </form>
        <p class="mt-3">Already have an account? <a href="{{ url_for('login') }}">Login</a></p>
    </div>
</div>
{% endblock %}

3. templates/login.html

{% extends "layout.html" %}

{% block content %}
<div class="row justify-content-center">
    <div class="col-md-6">
        <h2 class="mb-4">Login</h2>
        <form method="POST" action="">
            {{ form.hidden_tag() }}
            <div class="form-group mb-3">
                {{ form.email.label(class="form-label") }}
                {{ form.email(class="form-control") }}
            </div>
            <div class="form-group mb-3">
                {{ form.password.label(class="form-label") }}
                {{ form.password(class="form-control") }}
            </div>
            <div class="form-group">
                {{ form.submit(class="btn btn-primary") }}
            </div>
        </form>
        <p class="mt-3">Don't have an account? <a href="{{ url_for('register') }}">Register</a></p>
    </div>
</div>
{% endblock %}

4. templates/dashboard.html

{% extends "layout.html" %}

{% block content %}
<div class="row justify-content-center">
    <div class="col-md-8">
        <h2>Welcome, {{ username }}!</h2>
        <p>This is your secure dashboard.</p>
    </div>
</div>
{% endblock %}

Step 6: Running the Application

Start the Flask development server:

python app.py

Visit:

  • Register: http://127.0.0.1:5000/register
  • Login: http://127.0.0.1:5000/login
  • Dashboard: http://127.0.0.1:5000/dashboard (Protected)

Conclusion

You’ve successfully built a Flask authentication system with MySQLAlchemy! 🎉

🔹 Users can register, log in, and log out.
🔹 Passwords are securely hashed.
🔹 Protected routes ensure only logged-in users access the dashboard.

Next Steps:

Add email verification
Implement password reset functionality
Deploy to production (e.g., using Gunicorn + Nginx)


Tags

Python Coding Programming

Related Posts