Clone the canonical repo (login, signup, forgot password, protected account page, SQLite user store, hashed passwords, safe redirects, session cookie posture): github.com/dorian-sotpyrc/flask-10-line-auth
Most Flask auth guides are either (1) too small to be safe, or (2) so “frameworky” you can’t tell what’s happening anymore.
The fastest path to something you can ship is boring on purpose: put a single uid in the signed session cookie, and gate protected routes with one decorator.
That’s the spine. Everything else stays explicit and auditable in your app.
The smallest correct auth baseline in Flask is not a framework. It’s a rule:
store only a uid in session, and use a decorator to gate protected routes.
That gives you predictable behavior, easy audits, and no hidden magic.
- Session: store only
uid(nothing sensitive) - Gate:
@login_requiredredirects to login and preservesnext - Ship-ready rails: safe
nextredirects + sensible session cookie posture (behind HTTPS)
UI preview (starter wireframe)
You don’t need a “design system overhaul” to ship auth. Start with a clean browser frame, one centered card, and four primitives: two inputs, one primary button, and two secondary links (forgot + signup). The repo keeps that structure consistent across all screens so the UX feels intentional without getting noisy.
The 10-line auth “spine” (session UID + gate)
Here’s the only code you need to understand to reason about the whole system. Everything else (signup flow, password hashing, storage, forgot-password UX) is implemented in the repo — but your auth posture lives or dies on these ten lines.
from functools import wraps
from flask import session, redirect, url_for, request
def login_user(uid): session["uid"] = uid
def logout_user(): session.pop("uid", None)
def current_uid(): return session.get("uid")
def login_required(view):
@wraps(view)
def wrapper(*args, **kwargs):
if not current_uid():
return redirect(url_for("login", next=request.full_path))
return view(*args, **kwargs)
return wrapper
Why this is “production-shaped” without sprawl
Flask’s session cookie is signed, which is perfect for a tiny auth baseline: you can trust integrity, but you still keep the payload minimal.
Storing a uid (and only a uid) keeps you out of the danger zone: no secrets in the cookie, no huge user objects, no hidden state.
The repo makes this shippable: clean UI, login/signup/forgot flows, a protected account page, a simple user store, and secure sessions — while keeping the mental model simple: “session contains UID; gate checks UID; login sets UID; logout clears UID.”
Drop it into any Flask app
-
Copy the spineAdd the 10-line module to your project as
plex_auth.py(or similar). Keep it dependency-free and easy to audit. -
Gate routesPut
@login_requiredon anything protected. Let unauth users bounce to login with a preservednextpath. -
Use the repo as your known-good templateClone the GitHub demo and lift the pieces you need (templates, routes, storage). Don’t reinvent auth behavior — keep it boring and consistent.
Related PLEX reading
References & further reading
-
flask-10-line-auth (canonical demo repo)
The runnable baseline with UI + flows built around the session UID spine. -
Flask documentation: Sessions
How Flask’s signed session cookie works and what it’s designed for. -
Flask configuration: session cookie settings
SESSION_COOKIE_*posture (HttpOnly / SameSite / Secure) for real deployments. -
OWASP: Unvalidated Redirects and Forwards
Why validatingnextis not optional if you preserve redirects. -
MDN: SameSite cookies
Practical browser behavior notes (and why defaults matter).