1. Current-user dependencies
Start with the contract: make inputs, outputs and failure behavior explicit before adding infrastructure. This keeps the feature easy to reason about and gives tests a stable boundary.
2. Scopes and role-based permissions
Apply the pattern through a small vertical slice. Keep framework wiring at the edge and business decisions in focused functions or services that can be tested without starting the whole application.
def require_scope(required: str):
def check(user = Depends(current_user)):
if required not in user.scopes:
raise HTTPException(status_code=403, detail="Insufficient permission")
return user
return check3. Refresh-token rotation and revocation
Treat failure paths as part of the design. Add bounded resource usage, meaningful errors and a verification step so the behavior remains dependable under real production conditions.
4. Hands-on Exercise
Build the feature
Add admin-only task deletion and rotating refresh tokens. Reusing an old refresh token must revoke that token family.
Definition of done
- The happy path works through the real HTTP boundary.
- At least one failure path is handled and tested.
- Configuration and secrets stay outside source code.
- The README explains how to run and verify the result.
5. Knowledge Check
When should an API return 401 versus 403?
Show answer
Use 401 when valid authentication is missing; use 403 when the authenticated identity lacks permission.