FastAPI Security Best Practices: From Authentication & Authorization to CORS
📋 Article Highlights (Summary)
- Who is this for?
Intermediate to advanced engineers who want to build production-level APIs with FastAPI but are concerned about strengthening security - What you’ll learn
- Core design of token authentication using OAuth2 & JWT
- Implementing role-based authorization (permission management)
- Secure front-end integration using CORS (Cross-Origin Resource Sharing) settings
- Issuing API keys & introducing rate limiting to prevent unauthorized access
- Integrating security scanning tools for vulnerability checks
- Benefits
- Prevent unauthorized API usage with robust auth mechanisms, significantly reducing operational risk
- Achieve safe and smooth integration with front-ends and other services
🎯 Target Audience
- API Developer D (30s, in a company)
Wants to add strong authentication & authorization to an existing FastAPI service already published internally - Startup Engineer E (25)
Seeking to ensure security requirements from the prototype stage for a new product’s API design - Freelancer F (40s)
Needs to quickly implement API keys and rate control to meet client requirements
♿ Accessibility Level
- Readability: Balanced use of Kanji, Hiragana, and Katakana, with annotations for technical terms
- Structure: Generous use of headings/subheadings for a hierarchy that’s easy for screen readers
- Code Examples: Simple, well-commented, with attention to color contrast
- Summaries: “Key Takeaways” at the end of each section for easy reference
1. Introduction: The Importance of API Security
In recent years, attacks targeting APIs have increased, and flaws in authentication, authorization, or CORS settings can lead to severe data leaks.
FastAPI is a fast, type-safe framework, but developers must carefully design and implement security measures themselves.
This article walks you through a step-by-step best-practice approach covering authentication, authorization, CORS settings, API key issuance, rate limiting, and even integrating automated vulnerability scanning tools♡
Key Takeaways
- Understanding API attack risks and combining countermeasures is crucial
- Leverage FastAPI features plus external libraries for a robust system
2. Implement Robust Token Authentication with OAuth2 + JWT
2.1 Core Design & Required Packages
It’s common to combine OAuth2’s password flow with JWT (JSON Web Token).
Required packages:
pip install python-jose[cryptography] passlib[bcrypt]
2.2 Sample: User Authentication & Token Issuance
from fastapi import FastAPI, Depends, HTTPException, status
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
from jose import JWTError, jwt
from passlib.context import CryptContext
from datetime import datetime, timedelta
app = FastAPI()
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
SECRET_KEY = "YOUR_SECRET_KEY"
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 30
# Dummy DB for user authentication
fake_users_db = {
"alice": {"username": "alice", "hashed_password": pwd_context.hash("secret")}
}
def authenticate_user(username: str, password: str):
user = fake_users_db.get(username)
if not user or not pwd_context.verify(password, user["hashed_password"]):
return False
return user
def create_access_token(data: dict):
to_encode = data.copy()
expire = datetime.utcnow() + timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
to_encode.update({"exp": expire})
return jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
@app.post("/token")
async def login(form_data: OAuth2PasswordRequestForm = Depends()):
user = authenticate_user(form_data.username, form_data.password)
if not user:
raise HTTPException(status_code=400, detail="Authentication failed")
access_token = create_access_token({"sub": user["username"]})
return {"access_token": access_token, "token_type": "bearer"}
Key Takeaways
- Define the token endpoint with
OAuth2PasswordBearer
- Include an expiration (
exp
) in the JWT to ensure safety
3. Fine-Grained Permission Management with Role-Based Authorization
3.1 Define Roles with a Pydantic Model
from pydantic import BaseModel
class TokenData(BaseModel):
username: str | None = None
roles: list[str] = []
3.2 Authorization Check via Dependency
from fastapi import Security
def get_current_user(token: str = Depends(oauth2_scheme)):
credentials_exception = HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED, detail="Token authentication failed"
)
try:
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
username: str = payload.get("sub")
roles: list[str] = payload.get("roles", [])
except JWTError:
raise credentials_exception
return TokenData(username=username, roles=roles)
def require_role(role: str):
def role_checker(current: TokenData = Depends(get_current_user)):
if role not in current.roles:
raise HTTPException(status_code=403, detail="Insufficient permissions")
return Depends(role_checker)
@app.get("/admin")
async def read_admin_data(_ = require_role("admin")):
return {"message": "Admin-only data"}
Key Takeaways
- Include
roles
in the JWT payload and check permissions in dependencies- Use reusable
require_role("role_name")
for cleaner code
4. Secure Front-End Integration with CORS Settings
FastAPI makes this easy using CORSMiddleware
:
from fastapi.middleware.cors import CORSMiddleware
app.add_middleware(
CORSMiddleware,
allow_origins=["https://your-frontend.com"], # Trusted origins only
allow_credentials=True,
allow_methods=["GET", "POST", "PUT", "DELETE"],
allow_headers=["*"],
)
- Only include your production domains in
allow_origins
. - Use
"*"
only in development, and avoid it in production.
Key Takeaways
- Permit only trusted origins
- Differentiate settings for development vs. production to maintain security
5. Prevent Unauthorized Access with API Keys & Rate Limiting
5.1 API Key Management
- Issue a random string as the key
- Store
key
,owner
,scopes
, etc. in a table - Validate the
X-API-Key
header via middleware
from fastapi import Header
async def verify_api_key(x_api_key: str = Header(...)):
if x_api_key != "YOUR_STORED_API_KEY":
raise HTTPException(status_code=403, detail="Invalid API key")
5.2 Example Rate Limiting with slowapi
pip install slowapi
from slowapi import Limiter
from slowapi.util import get_remote_address
limiter = Limiter(key_func=get_remote_address)
app.state.limiter = limiter
@app.get("/limited")
@limiter.limit("5/minute")
async def limited_endpoint():
return {"message": "This endpoint is rate-limited"}
Key Takeaways
- Identify clients with API keys for access control
- Use rate limiting to curb brute force and scraping
6. Integrate Security Scanning Tools
- Bandit: Static analysis to detect Python code vulnerabilities
pip install bandit bandit -r .
- OWASP ZAP: Dynamic analysis to scan live APIs
- Integrate into your CI/CD pipeline for automated security tests
Key Takeaways
- Combine static & dynamic analysis for early vulnerability detection
- Automate tests in CI/CD to strengthen quality assurance
7. Conclusion & Next Steps
This article covered practical security measures for FastAPI:
- Token authentication design with OAuth2 + JWT
- Role-based authorization for permission control
- Secure front-end integration via CORS
- API key issuance & rate limiting to block unauthorized access
- Automated vulnerability scanning with Bandit & OWASP ZAP
By combining these practices, you can build secure, reliable APIs. Next, try advancing your security further with audit logging, WAF integration, and more♡