Guarding the Gate (Auth Middleware)
architect, critique, revise, code, testModule 3: Guarding the Gate (Auth Middleware)
Goal: Intercept incoming requests to verify tokens and ensure users can only access their own data.
What you need to know first
Middleware/Dependencies (The Security Guard): Code that runs before your endpoint functions execute. In FastAPI, we use a feature called dependency injection (using Depends).
- Think of it like a security guard standing at the door of your functions. Before your route handler is allowed to run, FastAPI routes the request to the guard function first.
- The guard inspects the
Authorizationheader, extracts and decrypts the JWT pass, and verifies the signature. - If the signature is valid, the guard hands the user object to your route function and lets it run. If the signature is invalid or missing, the guard throws an HTTP exception immediately, blocking the request from ever reaching your code.
Database Scoping (The Locker Keys):
- In CRUD systems, you must filter database actions using the authenticated user's ID.
- Insecure query:
SELECT * FROM tasks WHERE id = ? - Secure query:
SELECT * FROM tasks WHERE id = ? AND user_id = ?
- Insecure query:
- Think of it like a gym locker room. Every locker has a number (
id). If you only check the locker number, User A can open User B's locker simply by asking for that number. To make it secure, you must require both the locker number and the user's specific key (user_id). If the key doesn't match the locker, access is denied.
The SOLO idea
Never trust route parameters blindly. Under Pillar 03: Security-First, we write secure database isolation queries immediately. User data must be isolated at the query layer. We plan our route dependencies and query filters together using the planning loop before generating code.
Lab 3: Guardo & User Scope
Estimated AI conversations: 3
- Create a
user_idcolumn (INTEGER) in your SQLitetaskstable. Update the database schema definition. - Step A: Plan the security gate. Open Copilot Chat and type:
Follow #file:workflows/architect.md — Plan a FastAPI dependency
get_current_userinmain.py.- It must read the
Authorizationrequest header, extract the Bearer token, and decode it usingJWT_SECRET. - If validation fails (token expired, altered signature, missing header), return a
401 Unauthorized. - Plan to inject this dependency into the CRUD
/tasksendpoints and re-write SQL queries to scope task actions to the authenticated user'sid.
- It must read the
- Step B: Critique security isolation. In the same conversation, type:
Follow #file:workflows/critique.md — Critique the gatekeeper plan. What happens if the
Authorizationheader is poorly formatted (e.g. missing the word 'Bearer')? Does our SQLite query structure fully isolate operations? - Step C: Revise.
Follow #file:workflows/revise.md — Revise the plan to handle header formatting errors gracefully and double-check database isolation queries.
- Step D: Implement.
Follow #file:workflows/code.md — Write the dependency logic and update routes in
main.py. - Review the implementation. A route definition with auth injection should look similar to:
@app.get("/tasks") def list_tasks(current_user: dict = Depends(get_current_user)): # SQLite query: SELECT * FROM tasks WHERE user_id = ? ... - Write automated tests: Open
test_main.pyand write tests to assert:- Requesting
/taskswithout a Bearer token returns 401. - User A logs in, logs a task. User B logs in, and calls GET
/tasks. User B's task list must be empty.
- Requesting
- Run the tests:
pytest -v - Commit:
git add . git commit -m "Module 3: guarded routes and user database scoping" git push
Checkpoint
Create checkpoint_03.md:
- Paste the code snippet for your
get_current_userauth dependency. - Paste the test summary output of
pytest -v. - Explain how User A is blocked from deleting User B's tasks.