Protect List and Get
Add authentication and user filtering to the list and get endpoints
Writing code and entering commands is only available on desktop. Open this page on a larger screen to complete this chapter.
Two endpoints, two different patterns
The list_expenses and get_expense endpoints both need authentication, but they filter differently.
list_expenses returns a collection. You add a where clause to the query so each user only sees their own expenses. Without this filter, a logged-in user could see every expense in the database.
get_expense returns a single expense by its identifier. The database lookup still uses session.get(), but you add an ownership check afterward. If the expense belongs to a different user, the endpoint returns 404 — the same response as "expense not found." Returning 404 instead of 403 is intentional. A 403 response would confirm that the expense exists but belongs to someone else. A 404 reveals nothing.
Instructions
Protect the list_expenses and get_expense endpoints.
- Add
current_user: CurrentUseras a parameter tolist_expenses, aftersession: SessionDep— this requires a valid token before the endpoint runs. - Right after
statement = select(Expense), add a filter so each user only sees their own data:statement = statement.where(Expense.user_id == current_user.id). Without this, any logged-in user would see everyone's expenses. - Add
current_user: CurrentUseras a parameter toget_expense, aftersession: SessionDep. - After the existing 404 check (the
if not expenseblock), add an ownership check: ifexpense.user_id != current_user.id, raiseHTTPException(status_code=404, detail="Expense not found"). You return 404, not 403, so an attacker cannot tell whether the expense exists at all.
Interactive Code Editor
Sign in to write and run code, track your progress, and unlock all chapters.
Sign In to Start Coding