Python 2 min read

FastAPI Tutorial Part 18: API Security Best Practices

Secure your FastAPI application against common vulnerabilities. Learn input validation, rate limiting, CORS, and OWASP security patterns.

MR

Moshiour Rahman

Advertisement

Input Validation

Pydantic Validation

from pydantic import BaseModel, Field, field_validator
import re

class UserInput(BaseModel):
    username: str = Field(min_length=3, max_length=50, pattern=r"^[a-zA-Z0-9_]+$")
    email: str = Field(pattern=r"^[\w\.-]+@[\w\.-]+\.\w+$")

    @field_validator("username")
    @classmethod
    def no_sql_injection(cls, v):
        dangerous = ["'", '"', ";", "--", "/*", "*/"]
        if any(char in v for char in dangerous):
            raise ValueError("Invalid characters")
        return v

SQL Injection Prevention

# NEVER do this
query = f"SELECT * FROM users WHERE name = '{user_input}'"

# Use parameterized queries
result = db.execute(
    text("SELECT * FROM users WHERE name = :name"),
    {"name": user_input}
)

Rate Limiting

from slowapi import Limiter
from slowapi.util import get_remote_address

limiter = Limiter(key_func=get_remote_address)
app.state.limiter = limiter

@app.get("/api/data")
@limiter.limit("10/minute")
async def get_data(request: Request):
    return {"data": "limited"}

Security Headers

from fastapi.middleware.cors import CORSMiddleware

@app.middleware("http")
async def add_security_headers(request, call_next):
    response = await call_next(request)
    response.headers["X-Content-Type-Options"] = "nosniff"
    response.headers["X-Frame-Options"] = "DENY"
    response.headers["X-XSS-Protection"] = "1; mode=block"
    response.headers["Strict-Transport-Security"] = "max-age=31536000"
    return response

CORS Configuration

app.add_middleware(
    CORSMiddleware,
    allow_origins=["https://yourdomain.com"],  # Not "*" in production
    allow_credentials=True,
    allow_methods=["GET", "POST", "PUT", "DELETE"],
    allow_headers=["Authorization", "Content-Type"],
)

Secrets Management

from pydantic_settings import BaseSettings

class Settings(BaseSettings):
    secret_key: str  # From environment
    database_url: str
    api_key: str

    class Config:
        env_file = ".env"

# Never hardcode secrets
# Use: export SECRET_KEY="your-secret" or .env file

Authentication Security

from passlib.context import CryptContext

pwd_context = CryptContext(
    schemes=["bcrypt"],
    deprecated="auto",
    bcrypt__rounds=12  # Increase rounds for security
)

# Token expiration
ACCESS_TOKEN_EXPIRE_MINUTES = 15  # Short-lived
REFRESH_TOKEN_EXPIRE_DAYS = 7

Security Checklist

VulnerabilityPrevention
SQL InjectionParameterized queries
XSSInput validation, output encoding
CSRFCORS, SameSite cookies
Auth bypassJWT validation, secure sessions
Data exposureResponse filtering

Summary

Security LayerImplementation
InputPydantic validation
TransportHTTPS, security headers
AuthenticationJWT, bcrypt
Rate limitingslowapi

Next Steps

In Part 19, we’ll explore OpenAPI and Documentation - creating comprehensive API documentation.

Series Navigation:

  • Part 1-17: Previous parts
  • Part 18: Security (You are here)
  • Part 19: OpenAPI & Documentation

Advertisement

MR

Moshiour Rahman

Software Architect & AI Engineer

Share:
MR

Moshiour Rahman

Software Architect & AI Engineer

Enterprise software architect with deep expertise in financial systems, distributed architecture, and AI-powered applications. Building large-scale systems at Fortune 500 companies. Specializing in LLM orchestration, multi-agent systems, and cloud-native solutions. I share battle-tested patterns from real enterprise projects.

Related Articles

Comments

Comments are powered by GitHub Discussions.

Configure Giscus at giscus.app to enable comments.