Lesson Complete!

Protect Your Endpoints

What you built

Every expense endpoint now requires a valid JWT token. Each endpoint uses CurrentUser — a type alias for Annotated[User, Depends(get_current_user)] — to enforce authentication. You made three types of changes:

  • Create: sets expense.user_id to the current user's identifier before saving
  • List and summary: filter queries with .where(Expense.user_id == current_user.id) so each user sees only their own data
  • Get, update, and delete: check expense.user_id != current_user.id and return 404 if the expense belongs to a different user

Authentication vs. authorization

This lesson covers authentication — proving who you are. Every request must include a valid token, and the server identifies the user from that token.

Authorization is a separate concern — what a specific user is allowed to do. For example, an admin user who can view all expenses would require authorization rules. Your API does not have authorization yet, but the pattern is similar: add another dependency that checks the user's role or permissions before the endpoint runs.

What comes next

Your existing tests are all broken. They send requests without tokens, so every test gets a 401 error. Lesson 4 updates the test suite to register a user, log in, and include the token in every request.