DEV Community

Cover image for My project 2 : Flask Authentication System(with Python + Flask)
Sabin Sim
Sabin Sim

Posted on

My project 2 : Flask Authentication System(with Python + Flask)

πŸ” Flask Authentication System

I’ve always been curious about how the websites we use every day are actually built. We constantly interact with features like sign-up, login, and logout, yet most of us never really understand what happens behind the scenes. I was no exception β€” this curiosity kept growing, and I wanted to experience the structure myself. So I decided to try building it from scratch, hoping that by doing it hands-on, I could finally understand how these systems really work.


πŸ“‚ 1. Project Structure

auth_blog/
│── main.py
│── users.db (auto-created)
└── templates/
    β”œβ”€β”€ home.html
    β”œβ”€β”€ signup.html
    └── login.html

🧠 2. What This Project Does

  • User sign-up (stores hashed passwords)
  • User login with session management
  • Protected dashboard page using a custom login_required decorator
  • Logout functionality
  • Basic mini blog UI layout

This structure forms the foundation of nearly every modern web application.


πŸ–₯️ 3. Backend Code (main.py)

from flask import Flask, render_template, request, redirect, session
import sqlite3
from werkzeug.security import generate_password_hash, check_password_hash

app = Flask(__name__)
app.secret_key = "super_secret_key"

# Login-required decorator
def login_required(func):
    def wrapper(*args, **kwargs):
        if "user_id" not in session:
            return redirect("/login")
        return func(*args, **kwargs)
    wrapper.__name__ = func.__name__
    return wrapper

# Initialize database
def init_db():
    conn = sqlite3.connect("users.db")
    cur = conn.cursor()
    cur.execute("""
    CREATE TABLE IF NOT EXISTS users (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        username TEXT UNIQUE NOT NULL,
        password TEXT NOT NULL
    )
    """)
    conn.commit()
    conn.close()

init_db()

# Signup
@app.route("/signup", methods=["GET", "POST"])
def signup():
    if request.method == "POST":
        username = request.form["username"]
        password = request.form["password"]

        hashed_pw = generate_password_hash(password)

        conn = sqlite3.connect("users.db")
        cur = conn.cursor()
        try:
            cur.execute("INSERT INTO users (username, password) VALUES (?, ?)",
                        (username, hashed_pw))
            conn.commit()
        except sqlite3.IntegrityError:
            return "Signup failed: Username already exists."
        finally:
            conn.close()

        return redirect("/login")

    return render_template("signup.html")

# Login
@app.route("/login", methods=["GET", "POST"])
def login():
    if request.method == "POST":
        username = request.form["username"]
        password = request.form["password"]

        conn = sqlite3.connect("users.db")
        cur = conn.cursor()
        cur.execute("SELECT id, username, password FROM users WHERE username = ?", 
                    (username,))
        user = cur.fetchone()
        conn.close()

        if user and check_password_hash(user[2], password):
            session["user_id"] = user[0]
            session["username"] = user[1]
            return redirect("/dashboard")
        else:
            return "Login failed: Invalid username or password."

    return render_template("login.html")

# Dashboard (protected)
@app.route("/dashboard")
@login_required
def dashboard():
    return f"Welcome, {session['username']}! (Dashboard Page)"

# Logout
@app.route("/logout")
def logout():
    session.clear()
    return redirect("/login")

# Home
@app.route("/")
def home():
    return render_template("home.html")

if __name__ == "__main__":
    app.run(debug=True)
Enter fullscreen mode Exit fullscreen mode

πŸ–ΌοΈ 4. Templates

🏠 home.html

<!DOCTYPE html>
<html>
<head>
    <title>Mini Blog</title>
    <style>
        body { font-family: sans-serif; padding: 20px; background-color: #f4f7f9; }
        .post { 
            border: 1px solid #ddd; 
            padding: 15px; 
            margin-bottom: 15px; 
            border-radius: 8px; 
            background-color: white;
            box-shadow: 0 2px 4px rgba(0,0,0,0.05);
        }
        .top { 
            display: flex; justify-content: space-between; 
            align-items: center; border-bottom: 2px solid #007bff; 
            margin-bottom: 20px; padding-bottom: 10px;
        }
        a { text-decoration: none; color: #007bff; font-weight: bold; }
    </style>
</head>
<body>

<div class="top">
    <h1>Mini Blog Posts</h1>
    <a href="/new">Write New Post β†’</a>
</div>

{% for post in posts %}
<div class="post">
    <h3>{{ post[1] }}</h3>
    <p>{{ post[2] }}</p>
</div>
{% endfor %}

{% if not posts %}
<p style="color: #6c757d;">No posts yet. Start writing your first entry!</p>
{% endif %}

</body>
</html>
Enter fullscreen mode Exit fullscreen mode

πŸ”‘ login.html

<!DOCTYPE html>
<html>
<head>
    <title>Login</title>
    <style>
        body { font-family: sans-serif; padding: 20px; }
        form { display: flex; flex-direction: column; width: 300px; gap: 10px; }
        input { padding: 10px; border: 1px solid #ccc; border-radius: 4px; }
        button { padding: 10px; background: #28a745; color: white; 
                 border: none; border-radius: 4px; cursor: pointer; }
        button:hover { background: #1e7e34; }
    </style>
</head>
<body>

<h1>Log In</h1>

<form action="/login" method="POST">
    <input type="text" name="username" placeholder="Username" required>
    <input type="password" name="password" placeholder="Password" required>
    <button type="submit">Log In</button>
</form>

</body>
</html>
Enter fullscreen mode Exit fullscreen mode

πŸ“ signup.html

<!DOCTYPE html>
<html>
<head>
    <title>Sign Up</title>
    <style>
        body { font-family: sans-serif; padding: 20px; }
        form { display: flex; flex-direction: column; width: 300px; gap: 10px; }
        input { padding: 10px; border: 1px solid #ccc; border-radius: 4px; }
        button { padding: 10px; background: #007bff; color: white; 
                 border: none; border-radius: 4px; cursor: pointer; }
        button:hover { background: #0056b3; }
    </style>
</head>
<body>

<h1>Sign Up</h1>

<form action="/signup" method="POST">
    <input type="text" name="username" placeholder="Username" required>
    <input type="password" name="password" placeholder="Password" required>
    <button type="submit">Register</button>
</form>

</body>
</html>
Enter fullscreen mode Exit fullscreen mode

πŸ”§ 5. Try It Yourself β€” Easy Improvements

  • Add post creation to the authenticated dashboard
  • Allow users to edit/delete their posts
  • Add timestamps for posts
  • Add password reset functionality
  • Improve the UI with a CSS stylesheet

These small improvements will help you understand web authentication and backend structure more deeply. Try making one or two changes and watch how quickly this project evolves into a real application!

Top comments (0)