dives deeper in various HTTP responses and their error handling techniques. Consistent error handling improves security and user experience:
from fastapi.exceptions import RequestValidationError
from fastapi.responses import JSONResponse
@app.exception_handler(HTTPException)
async def http_exception_handler(request, exc):
"""Custom HTTP exception handler"""
return JSONResponse(
status_code=exc.status_code,
content={
"error": {
"message": exc.detail,
"type": "authentication_error" if exc.status_code == 401 else "authorization_error",
"status_code": exc.status_code
}
},
headers=exc.headers
)
@app.exception_handler(RequestValidationError)
async def validation_exception_handler(request, exc):
"""Handle validation errors"""
return JSONResponse(
status_code=422,
content={
"error": {
"message": "Validation error",
"type": "validation_error",
"details": exc.errors()
}
}
)
Security Best Practices
1. Never store plain text passwords, always hash password using bcrypt:
from passlib.context import CryptContext
# Use proper password hashing
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
def hash_password(password: str) -> str:
return pwd_context.hash(password)
2. Rate Limiting
from collections import defaultdict
import time
# Simple rate limiting (use Redis in production)
request_counts = defaultdict(list)
def rate_limit(max_requests: int = 100, window_minutes: int = 15):
def decorator(func):
def wrapper(*args, **kwargs):
client_ip = "127.0.0.1"
now = time.time()
window_start = now - (window_minutes * 60)
# Clean old requests
request_counts[client_ip] = [
req_time for req_time in request_counts[client_ip]
if req_time > window_start
]
if len(request_counts[client_ip]) >= max_requests:
raise HTTPException(
status_code=429,
detail="Rate limit exceeded"
)
request_counts[client_ip].append(now)
return func(*args, **kwargs)
return wrapper
return decorator
3. Use environment variables for secrets, with pydantic settings. Never hard code secret keys in your code:
# config.py
from pydantic_settings import BaseSettings
class Settings(BaseSettings):
secret_key: str = "your-secret-key-here"
algorithm: str = "HS256"
access_token_expire_minutes: int = 30
class Config:
env_file = ".env"
settings = Settings()
Wrapping Up
We’ve covered three authentication strategies in FastAPI:
Basic HTTP Authentication : Simple but suitable for internal APIs.
API Key Authentication : Great for public APIs and service-to-service communication.
Session-Based Authentication : Traditional and cookie based approach.
Each method has its use cases, and the choice depends on your application’s requirements.
Key Takeaways:
- Always use HTTPS in production.
- Hash passwords properly with bcrypt or similar.
- Implement proper error handling and logging.
- Add security headers and middleware.
- Test your authentication thoroughly.
- Add rate limiting for public APIs.
- Use environment variables to store sensitive data
Dig Deeper
Have a great one!!!
Author: Join thousands of backend engineers learning backend engineering. Build real-world backend projects, learn from expert-vetted courses and roadmaps, track your learnings and set schedules, and solve backend engineering tasks, exercises, and challenges.
If you like posts like this, you will absolutely enjoy our exclusive weekly newsletter, sharing exclusive backend engineering resources to help you become a great Backend Engineer.
on September 2, 2025.
SOCIAL SHARE CARD GENERATOR