Warming up the neural circuits...
By the end of this chapter you will:
Authentication is where small mistakes become severe incidents.
A flawed auth layer can expose user data, allow privilege escalation, or create persistent account takeover vectors.
Production auth design needs clear boundaries:
This chapter focuses on -safe defaults, not copy-paste snippets with hidden risks.
from passlib.context import CryptContext
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
def hash_password(plain_password: str) -> str:
return pwd_context.hash(plain_password)
def verify_password(plain_password: str, hashed_password: str) -> bool:
return pwd_context.verify(plain_password, hashed_password)Never store plaintext passwords. Never build custom hashing algorithms.
A JWT contains:
Keep payload minimal: sub, exp, iat, and maybe scope/role.
Do not place secrets, password hashes, or sensitive PII in token payload.
from datetime import datetime, timedelta, timezone
from jose import jwt, JWTError
SECRET_KEY = "replace-in-env"
ALGORITHM = "HS256"
def create_access_token(subject: str, expires_minutes: int = 15)
from fastapi import Depends, FastAPI, HTTPException
from fastapi.security import OAuth2PasswordBearer
app = FastAPI()
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/auth/login")
def get_current_user(token: str = Depends(oauth2_scheme
Practical defaults:
Stateless-only designs are simpler initially but weaker for revocation control.
from fastapi import Depends, HTTPException
def require_admin(user: dict = Depends(get_current_user)) -> dict:
if user.get("role") != "admin":
raise HTTPException(status_code
Use environment-managed secrets, rotate keys, monitor failed logins, and prefer defense in depth over single-mechanism trust.
| Decision | Better default | Why |
|---|---|---|
| Password storage | bcrypt/argon2 via vetted library | Resistant to offline cracking |
| Access token lifetime | Short TTL | Limits blast radius on token leak |
| Refresh handling | Rotating refresh tokens with revocation store | Better session control |
| Route protection | Dependency-based guards | Consistent enforcement |
| Authorization model | RBAC plus scoped permissions where needed | Scales beyond simple role checks |
| Mistake | Why it hurts | Better move |
|---|---|---|
| Storing plaintext or reversible passwords | Immediate high-severity breach impact | One-way hash with strong algorithm |
| Putting sensitive data in JWT payload | Token disclosure leaks secrets | Keep payload minimal and non-sensitive |
| Long-lived access tokens | Persistent unauthorized access risk | Short TTL + refresh rotation |
| Checking auth in route bodies manually | Inconsistent policy and missed paths | Central dependency guards |
| Ignoring logout/revocation model | Invalid sessions remain active | Implement refresh token invalidation strategy |
Plain password and stored hashCorrect boolean verificationAuthenticated user idSigned token stringAuthorization bearer token401 on invalid token, user object on successUser role in current user context403 for non-adminsCompromised refresh token scenarioPolicy with rotation, revocation, and incident pathBeginner:
"Why do we hash passwords instead of encrypting them?"
Authentication needs verification, not decryption. One-way hashes reduce impact of database compromise.
"What is the difference between authentication and authorization?"
Authentication identifies who the user is. Authorization determines what that user can access.
Senior:
"How do you design token revocation in a JWT-based system?"
Use short access TTL, server-tracked refresh tokens, rotation, revocation lists, and invalidation on key security events.
"What are common JWT implementation pitfalls in APIs?"
Weak secret management, missing audience/issuer checks, long token TTLs, and leaking sensitive claims.
Hash passwords with vetted algorithms
Issue short-lived access tokens
Validate token signature and claims on each request
Use dependencies for auth + RBAC enforcement
Plan refresh revocation before launchWhat should never be stored in JWT payload claims?
Always verify signature, algorithm, and expiration.
Dependency injection keeps auth checks consistent and reusable.
Authentication answers "who are you". Authorization answers "what are you allowed to do".