Admin
Mar 26, 2025
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.
🔹 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!
Before we start, make sure you have:
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
pip install flask flask-sqlalchemy flask-login flask-bcrypt flask-wtf
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
app.py
– Flask Setupfrom 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)
models.py
– User Modelfrom 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}')"
forms.py
– Login & Registration Formsfrom 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')
CREATE DATABASE flask_auth_db;
Run in Python shell:
from app import app, db
with app.app_context():
db.create_all()
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)
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)
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'))
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>
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 %}
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 %}
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 %}
Start the Flask development server:
python app.py
Visit:
http://127.0.0.1:5000/register
http://127.0.0.1:5000/login
http://127.0.0.1:5000/dashboard
(Protected)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.
✅ Add email verification
✅ Implement password reset functionality
✅ Deploy to production (e.g., using Gunicorn + Nginx)