# Auth — JWT Authentication ## Stack python-jose (JWT signing/verification) + passlib (bcrypt password hashing). Token-based, stateless. ## Structure ``` auth/ models.py # Pydantic models: UserCreate, UserLogin, Token, UserOut service.py # Business logic: authenticate_user, create_user, create_access_token dependencies.py # FastAPI Depends: get_current_user, require_admin middleware.py # ASGI middleware (if any global auth checks) router.py # APIRouter: /login, /register, /whoami ``` ## Patterns - Passwords hashed with bcrypt via `passlib` — never store plaintext - JWT tokens signed with `python-jose`, include `sub` (username) and `exp` - `get_current_user()` is the standard `Depends()` to inject user into endpoints - Auth endpoints return Pydantic models: `Token(access_token=...)`, `UserOut(username=...)` - HTTP status codes: 401 for bad credentials, 409 for duplicate user ## Usage in Routers ```python from auth.dependencies import get_current_user @router.get("/protected") async def protected_route(current_user = Depends(get_current_user)): ... ``` ## Anti-Patterns - Don't hardcode secret keys — use `Settings` from environment - Don't store tokens client-side without HttpOnly cookies - Don't skip `response_model` on auth endpoints - Don't leak whether username or password was wrong — always "incorrect username or password" - Don't bypass `Depends(get_current_user)` for protected routes