Skip to main content

Flask: Implementing Authentication

Flask: Implementing Authentication

Authentication is a critical component of Flask web applications, ensuring secure user access to protected resources. Using extensions like Flask-Login and Flask-Bcrypt, Flask integrates seamlessly with Flask Querying the Database and Flask Relationships in Models to manage user sessions and secure passwords. This tutorial explores Flask authentication, covering user registration, login, logout, and session management, with practical applications in building secure web applications.


01. Why Implement Authentication?

Authentication verifies user identity, enabling personalized experiences and protecting sensitive data. Flask’s lightweight framework, combined with SQLAlchemy and extensions, provides a flexible and secure approach to authentication. By leveraging NumPy Array Operations for efficient query processing, Flask ensures scalable user management for applications like blogs, e-commerce platforms, or dashboards.

Example: Basic User Login

from flask import Flask, request, redirect, url_for
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager, UserMixin, login_user
from flask_bcrypt import Bcrypt

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///auth.db'
app.config['SECRET_KEY'] = 'your-secret-key'
db = SQLAlchemy(app)
bcrypt = Bcrypt(app)
login_manager = LoginManager(app)

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

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

@app.route('/login', methods=['POST'])
def login():
    username = request.form['username']
    password = request.form['password']
    user = User.query.filter_by(username=username).first()
    if user and bcrypt.check_password_hash(user.password_hash, password):
        login_user(user)
        return "Login successful"
    return "Invalid credentials"

with app.app_context():
    db.create_all()
    hashed_password = bcrypt.generate_password_hash('mypassword').decode('utf-8')
    db.session.add(User(username='Alice', password_hash=hashed_password))
    db.session.commit()

Output:

Login successful (on valid POST request with username='Alice' and password='mypassword')

Explanation:

  • Flask-Login - Manages user sessions and authentication state.
  • Flask-Bcrypt - Securely hashes and verifies passwords.
  • UserMixin - Adds required methods for user authentication.

02. Key Authentication Techniques

Flask provides tools and extensions to implement secure authentication workflows. Below is a summary of key techniques and their applications in web applications:

Technique Description Use Case
User Registration Create and store new user accounts Sign-up forms
Login Authenticate users and start sessions User login pages
Logout End user sessions Secure session termination
Protected Routes Restrict access to authenticated users Private dashboards
Password Management Securely hash and verify passwords Secure user credentials


2.1 User Registration

Example: Registering a New User

from flask import Flask, request
from flask_sqlalchemy import SQLAlchemy
from flask_bcrypt import Bcrypt

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///register.db'
app.config['SECRET_KEY'] = 'your-secret-key'
db = SQLAlchemy(app)
bcrypt = Bcrypt(app)

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

@app.route('/register', methods=['POST'])
def register():
    username = request.form['username']
    password = request.form['password']
    if User.query.filter_by(username=username).first():
        return "Username already exists"
    hashed_password = bcrypt.generate_password_hash(password).decode('utf-8')
    user = User(username=username, password_hash=hashed_password)
    db.session.add(user)
    db.session.commit()
    return "Registration successful"

with app.app_context():
    db.create_all()

Output:

Registration successful (on valid POST request with unique username)

Explanation:

  • generate_password_hash - Creates a secure password hash.
  • Checks for existing usernames to prevent duplicates.

2.2 User Login

Example: Authenticating a User

from flask import Flask, request, redirect, url_for
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager, UserMixin, login_user
from flask_bcrypt import Bcrypt

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///login.db'
app.config['SECRET_KEY'] = 'your-secret-key'
db = SQLAlchemy(app)
bcrypt = Bcrypt(app)
login_manager = LoginManager(app)

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

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

@app.route('/login', methods=['POST'])
def login():
    username = request.form['username']
    password = request.form['password']
    user = User.query.filter_by(username=username).first()
    if user and bcrypt.check_password_hash(user.password_hash, password):
        login_user(user)
        return "Logged in"
    return "Invalid credentials"

with app.app_context():
    db.create_all()
    hashed_password = bcrypt.generate_password_hash('testpass').decode('utf-8')
    db.session.add(User(username='Bob', password_hash=hashed_password))
    db.session.commit()

Output:

Logged in (on valid POST request with username='Bob' and password='testpass')

Explanation:

  • login_user - Initiates a user session.
  • check_password_hash - Verifies the password against the stored hash.

2.3 User Logout

Example: Logging Out a User

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager, UserMixin, logout_user
from flask_bcrypt import Bcrypt

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///logout.db'
app.config['SECRET_KEY'] = 'your-secret-key'
db = SQLAlchemy(app)
bcrypt = Bcrypt(app)
login_manager = LoginManager(app)

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

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

@app.route('/logout')
def logout():
    logout_user()
    return "Logged out"

with app.app_context():
    db.create_all()

Output:

Logged out (on GET request to /logout)

Explanation:

  • logout_user - Terminates the user session.
  • Ensures secure session management.

2.4 Protecting Routes

Example: Restricting Access

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager, UserMixin, login_required
from flask_bcrypt import Bcrypt

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///protected.db'
app.config['SECRET_KEY'] = 'your-secret-key'
db = SQLAlchemy(app)
bcrypt = Bcrypt(app)
login_manager = LoginManager(app)

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

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

@app.route('/dashboard')
@login_required
def dashboard():
    return "Welcome to your dashboard"

with app.app_context():
    db.create_all()

Output:

Welcome to your dashboard (for authenticated users only)

Explanation:

  • login_required - Restricts route access to authenticated users.
  • Redirects unauthenticated users to the login page (configurable via login_manager.login_view).

2.5 Incorrect Authentication Setup

Example: Missing Secret Key

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///error.db'
# Missing SECRET_KEY
db = SQLAlchemy(app)
login_manager = LoginManager(app)

class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(80), nullable=False)

try:
    with app.app_context():
        db.create_all()
except Exception as e:
    print("Error:", str(e))

Output:

Error: The session is unavailable because no secret key was set

Explanation:

  • A SECRET_KEY is required for session management.
  • Solution: Set app.config['SECRET_KEY'] to a secure value.

03. Effective Usage

3.1 Recommended Practices

  • Use Flask-Bcrypt for secure password hashing.

Example: Comprehensive Authentication

from flask import Flask, request, redirect, url_for
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager, UserMixin, login_user, logout_user, login_required
from flask_bcrypt import Bcrypt

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///complete.db'
app.config['SECRET_KEY'] = 'secure-secret-key'
db = SQLAlchemy(app)
bcrypt = Bcrypt(app)
login_manager = LoginManager(app)
login_manager.login_view = 'login'

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

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

@app.route('/register', methods=['POST'])
def register():
    username = request.form['username']
    password = request.form['password']
    if User.query.filter_by(username=username).first():
        return "Username taken"
    hashed_password = bcrypt.generate_password_hash(password).decode('utf-8')
    user = User(username=username, password_hash=hashed_password)
    db.session.add(user)
    db.session.commit()
    return "Registered"

@app.route('/login', methods=['POST'])
def login():
    username = request.form['username']
    password = request.form['password']
    user = User.query.filter_by(username=username).first()
    if user and bcrypt.check_password_hash(user.password_hash, password):
        login_user(user)
        return "Logged in"
    return "Invalid credentials"

@app.route('/logout')
@login_required
def logout():
    logout_user()
    return "Logged out"

@app.route('/profile')
@login_required
def profile():
    return "User profile"

with app.app_context():
    db.create_all()

Output:

Registered (on valid registration)
Logged in (on valid login)
User profile (on accessing /profile when logged in)
Logged out (on accessing /logout)
  • login_manager.login_view - Redirects unauthenticated users to the login route.
  • Combines registration, login, logout, and protected routes for a complete workflow.

3.2 Practices to Avoid

  • Avoid storing plain-text passwords.

Example: Insecure Password Storage

from flask import Flask, request
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///insecure.db'
db = SQLAlchemy(app)

class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(80), unique=True, nullable=False)
    password = db.Column(db.String(120), nullable=False)  # Insecure: plain text

@app.route('/register', methods=['POST'])
def register():
    username = request.form['username']
    password = request.form['password']  # Stored as plain text
    user = User(username=username, password=password)
    db.session.add(user)
    db.session.commit()
    return "Registered"

with app.app_context():
    db.create_all()

Output:

Registered (but passwords are insecurely stored)
  • Plain-text passwords are vulnerable to breaches.
  • Solution: Use Flask-Bcrypt for hashing.

04. Common Use Cases in Web Development

4.1 Secure User Dashboards

Protect user-specific dashboards with authentication.

Example: Protected Dashboard

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager, UserMixin, login_required, current_user
from flask_bcrypt import Bcrypt

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///dashboard.db'
app.config['SECRET_KEY'] = 'your-secret-key'
db = SQLAlchemy(app)
bcrypt = Bcrypt(app)
login_manager = LoginManager(app)

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

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

@app.route('/dashboard')
@login_required
def dashboard():
    return f"Welcome, {current_user.username}, to your dashboard"

with app.app_context():
    db.create_all()

Output:

Welcome, Alice, to your dashboard (for authenticated user 'Alice')

Explanation:

  • current_user - Accesses the authenticated user’s data.
  • Ensures personalized and secure access.

4.2 User Registration for Blog Platforms

Allow users to register and access blogging features securely.

Example: Blog User Registration

from flask import Flask, request
from flask_sqlalchemy import SQLAlchemy
from flask_bcrypt import Bcrypt

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///blog.db'
app.config['SECRET_KEY'] = 'your-secret-key'
db = SQLAlchemy(app)
bcrypt = Bcrypt(app)

class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(80), unique=True, nullable=False)
    password_hash = db.Column(db.String(120), nullable=False)
    posts = db.relationship('Post', backref='author', lazy=True)

class Post(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(100), nullable=False)
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)

@app.route('/register', methods=['POST'])
def register():
    username = request.form['username']
    password = request.form['password']
    if User.query.filter_by(username=username).first():
        return "Username taken"
    hashed_password = bcrypt.generate_password_hash(password).decode('utf-8')
    user = User(username=username, password_hash=hashed_password)
    db.session.add(user)
    db.session.commit()
    return "Registered"

with app.app_context():
    db.create_all()

Output:

Registered (on valid POST request with unique username)

Explanation:

  • Integrates with Flask Relationships in Models to link users to posts.
  • Secure registration enables blog content creation.

Conclusion

Flask, with Flask-Login, Flask-Bcrypt, and integration with Flask Querying the Database and NumPy Array Operations, provides a robust framework for implementing secure authentication. Key takeaways:

  • Use Flask-Login for session management and Flask-Bcrypt for password security.
  • Implement registration, login, logout, and protected routes for complete workflows.
  • Apply authentication in dashboards, blogs, or e-commerce platforms.
  • Avoid insecure practices like plain-text password storage or missing secret keys.

With these techniques, you can build secure, user-friendly Flask applications that protect data and enhance user experiences!

Comments