Authentication
Goal for this part
Give Campus Wire accounts. Visitors will register, log in, and log out. Writing a new post will require a logged-in user instead of a hard-coded guest author.
You will store only password hashes, wire Flask-Login’s session helpers, and protect selected routes with @login_required. This is the foundation for ownership rules in the next part.
What you should already know
You should be comfortable with forms and with the User model from the Database snapshot. A basic sense of why passwords must not be stored in plain text will help the security pieces click.
You do not need prior experience with Flask-Login. Treat it as a small library that remembers which user is active for the current browser session.
Concepts: hashing and session users
Hashing transforms a password into a stored value that is hard to reverse. Werkzeug’s generate_password_hash and check_password_hash handle that for you. The database stores the hash; login compares a typed password against that hash.
Flask-Login needs a user object that implements a few expected properties. Mixing in UserMixin supplies those defaults so your model can focus on columns and helpers like set_password.
from werkzeug.security import check_password_hash, generate_password_hash
class User(UserMixin, db.Model):
# ... columns including password_hash ...
def set_password(self, password: str) -> None:
self.password_hash = generate_password_hash(password)
def check_password(self, password: str) -> bool:
return check_password_hash(self.password_hash, password)
Walkthrough: Flask-Login setup
Create a LoginManager, attach it to the app, and set login_view to the endpoint name for your login route. When an anonymous visitor hits a protected page, Flask-Login can redirect them there.
The user_loader callback receives the stored user id from the session and returns a User instance. Without it, Flask-Login cannot restore the logged-in user on the next request. Decorate write routes with @login_required.
login_manager = LoginManager(app)
login_manager.login_view = "login"
@login_manager.user_loader
def load_user(user_id):
return db.session.get(User, int(user_id))
@app.route("/new", methods=["GET", "POST"])
@login_required
def new_post():
...
Register, login, logout, and how to run
Registration validates uniqueness, hashes the password, saves the user, and usually redirects to login. Login looks up the account, checks the password, then calls login_user. Logout calls logout_user and clears the session identity.
Run the 05-Auth snapshot, register a practice account, log in, and open the new-post page. Log out and try the protected URL again: you should be sent to login instead of seeing the form.
git clone https://github.com/michaeldunga1/fcc-flask-blog.git
cd fcc-flask-blog/05-Auth
python3 -m venv .venv
source .venv/bin/activate
pip install -r ../requirements.txt
python app.py
Common mistakes and troubleshooting
If login always fails, confirm you are hashing on register and checking the hash on login—not comparing raw strings. If @login_required never redirects, verify login_view matches the login endpoint name exactly.
Duplicate email or username errors mean your uniqueness validators or database constraints are doing their job. Pick a different value or reset the SQLite file while learning.
Try this checklist
- Register two users with different emails
- Confirm a wrong password does not log you in
- Hit a protected route while logged out and watch the redirect
- Log out and confirm the nav no longer treats you as signed in
Next: Posts CRUD
Comments
One comment per signed-in account. Comments are saved with this page’s URL.