Authentication & Authorization: JWT, OAuth2, RBAC
Implement real authentication. Master JWT with refresh tokens, OAuth2 flows, role-based access control, API key management, session hardening, and security best practices used in production.
Implement real authentication. Master JWT with refresh tokens, OAuth2 flows, role-based access control, API key management, session hardening, and security best practices used in production. This hands-on tutorial focuses on practical implementation of authentication & authorization: jwt, oauth2, rbac concepts.
Authentication & Authorization: JWT, OAuth2, RBAC
Authentication isn't just checking passwords. Production auth systems handle token lifecycle, refresh flows, role hierarchies, and API key scopes. This chapter builds a real auth system.
The Complete Auth Flow
┌──────────┐ ┌──────────────┐ ┌──────────────┐
│ Client │────▶│ POST /login │────▶│ Auth Service │
│ │ │ username+pw │ │ verify + JWT │
│ │◀────│ access_token │◀────│ │
│ │ │ refresh_token│ └──────────────┘
│ │ └──────────────┘
│ Stores │
│ tokens │
│ │ ┌──────────────┐ ┌──────────────┐
│ │────▶│ GET /users │────▶│ JWT Middleware│
│ │ │ Bearer token │ │ verify → user │
│ │◀────│ 200 OK │◀────│ check RBAC │
└──────────┘ └──────────────┘ └──────────────┘
OAuth2 with FastAPI — The Real Flow
FastAPI's OAuth2 support isn't just for documentation — it implements the full specification:
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
# OAuth2 scheme defines where to find the token
oauth2_scheme = OAuth2PasswordBearer(
tokenUrl="/auth/login", # Where to get tokens
scopes={ # Scopes for fine-grained access
"read": "Read access",
"write": "Write access",
"admin": "Administrator access"
}
)
@app.post("/auth/login")
async def login(form_data: OAuth2PasswordRequestForm = Depends()):
"""
Standard OAuth2 password flow.
form_data includes: username, password, scope, grant_type
"""
user = auth_service.authenticate(form_data.username, form_data.password)
if not user:
raise HTTPException(status_code=401)
# Check requested scopes
requested_scopes = form_data.scopes
token_scopes = [s for s in requested_scopes if user.has_scope(s)]
access_token = create_access_token(user, scopes=token_scopes)
return {"access_token": access_token, "token_type": "bearer"}
@app.get("/users/me")
async def read_current_user(
token: str = Depends(oauth2_scheme),
current_user: User = Depends(get_current_user)
):
"""Protected endpoint — requires valid token."""
return current_user
API Key Authentication
For service-to-service communication, JWT is overkill. API keys are simpler and equally secure when properly managed:
Security Best Practices
| Practice | Why |
|---|---|
| Hash passwords with bcrypt | SHA-256 is too fast — attackers can try billions/sec |
| Short access token TTL (15 min) | If stolen, damage is limited |
| Refresh token rotation | Old refresh token revoked on every use |
| Rate limit login endpoints | Prevents brute force |
| Account lockout after 5 failures | Blocks automated attacks |
| CORS: whitelist origins | Don't use allow_origins=["*"] in production |
| HTTPS only | Never send tokens over plain HTTP |
| HttpOnly cookies for web apps | JavaScript can't read the token |
| Audit logging | Track all login attempts, token usage |
AI Mentor
Confused about "FastAPI authentication JWT OAuth2 RBAC API keys security best practices"? Ask our AI mentor for a simplified explanation.
Quiz
Quiz
Question 1 of 10Why use refresh tokens instead of long-lived access tokens?
Key Takeaways
✅ Access + Refresh token pattern with short TTLs and rotation.
✅ RBAC with hierarchical roles prevents privilege escalation.
✅ API keys should be hashed like passwords — never stored in plaintext.
✅ Brute force protection: rate limiting + account lockout.
✅ OAuth2 scopes for fine-grained API access control.
✅ HttpOnly cookies prevent XSS token theft in browser apps.
Keep coding! 🚀