Middleware Configuration
This section covers advanced configuration options for Auth Middleware, including environment variables, custom providers, and performance tuning.
Basic Middleware Setup
The Auth Middleware is added to your FastAPI or Starlette application using the standard middleware protocol:
from fastapi import FastAPI
from auth_middleware import JwtAuthMiddleware
from auth_middleware.providers.authn.cognito_provider import CognitoProvider
app = FastAPI()
# Add authentication middleware
app.add_middleware(
JwtAuthMiddleware,
auth_provider=your_auth_provider,
# Additional configuration options...
)
Middleware Parameters
The JwtAuthMiddleware
accepts the following parameters:
Parameter |
Description |
Type |
Default |
---|---|---|---|
|
The authentication provider instance |
|
Required |
|
Paths to exclude from authentication |
|
|
|
Paths to include in authentication |
|
|
|
HTTP header for authentication token |
|
|
|
Authentication scheme |
|
|
Path Configuration
Excluding Paths from Authentication
You can exclude specific paths from authentication requirements:
app.add_middleware(
JwtAuthMiddleware,
auth_provider=cognito_provider,
exclude_paths=[
"/", # Public homepage
"/health", # Health check endpoint
"/docs", # OpenAPI documentation
"/openapi.json", # OpenAPI schema
"/metrics", # Prometheus metrics
"/static/*", # Static files
"/public/*", # Public assets
]
)
Including Specific Paths Only
Alternatively, you can specify only the paths that require authentication:
app.add_middleware(
JwtAuthMiddleware,
auth_provider=cognito_provider,
include_paths=[
"/api/*", # All API endpoints
"/admin/*", # Admin interface
"/user/*", # User-specific endpoints
]
)
Pattern Matching
The middleware supports glob-style pattern matching:
*
matches any characters within a single path segment**
matches any characters across multiple path segments?
matches any single character
exclude_paths = [
"/api/v*/public/*", # Version-specific public endpoints
"/health*", # All health-related endpoints
"/static/**", # All static files recursively
]
Environment Variables
Core Configuration
Environment Variable |
Description |
Default |
---|---|---|
|
Disable all authentication |
|
|
Logging level |
|
|
Logger name |
|
Provider-Specific Variables
AWS Cognito:
AWS_COGNITO_USER_POOL_ID=us-east-1_abcdef123
AWS_COGNITO_USER_POOL_REGION=us-east-1
TOKEN_VERIFICATION_DISABLED=false
Azure Entra ID:
AZURE_TENANT_ID=your-tenant-id
AZURE_CLIENT_ID=your-client-id
AZURE_CLIENT_SECRET=your-client-secret
JWT Provider:
JWT_SECRET_KEY=your-secret-key
JWT_ALGORITHM=HS256
JWT_ISSUER=your-issuer
Custom Authentication Providers
Creating a Custom Provider
You can create custom authentication providers by implementing the AuthProvider
interface:
from abc import ABC, abstractmethod
from typing import Optional
from auth_middleware.types import User
class CustomAuthProvider(ABC):
@abstractmethod
async def authenticate(self, token: str) -> Optional[User]:
"""Validate token and return user information."""
pass
@abstractmethod
async def get_user_groups(self, user: User) -> List[str]:
"""Get user group memberships."""
pass
Example Custom Provider
import jwt
from auth_middleware.types import User
from auth_middleware.exceptions import AuthenticationError
class ApiKeyProvider:
def __init__(self, valid_api_keys: dict):
self.valid_api_keys = valid_api_keys
async def authenticate(self, token: str) -> Optional[User]:
# Remove 'Bearer ' prefix if present
if token.startswith('Bearer '):
token = token[7:]
# Look up API key
user_info = self.valid_api_keys.get(token)
if not user_info:
raise AuthenticationError("Invalid API key")
return User(
id=user_info["id"],
name=user_info["name"],
email=user_info["email"],
groups=user_info.get("groups", []),
raw_token=token,
)
async def get_user_groups(self, user: User) -> List[str]:
return user.groups
# Usage
api_keys = {
"api_key_123": {
"id": "user1",
"name": "John Doe",
"email": "john@example.com",
"groups": ["user", "admin"]
}
}
app.add_middleware(
JwtAuthMiddleware,
auth_provider=ApiKeyProvider(api_keys)
)
Performance Configuration
Connection Pooling
For providers that make HTTP requests (like Cognito), configure connection pooling:
import httpx
from auth_middleware.providers.authn.cognito_provider import CognitoProvider
# Custom HTTP client with connection pooling
http_client = httpx.AsyncClient(
timeout=30.0,
limits=httpx.Limits(
max_keepalive_connections=10,
max_connections=100,
)
)
# Note: This is conceptual - actual implementation may vary
cognito_provider = CognitoProvider(
settings=auth_settings,
http_client=http_client,
)
Caching Configuration
Token validation results can be cached to improve performance:
# This is conceptual - check actual provider documentation
auth_settings = CognitoAuthzProviderSettings(
user_pool_id="us-east-1_abcdef123",
user_pool_region="us-east-1",
cache_jwks=True, # Cache JSON Web Key Sets
cache_ttl=3600, # Cache TTL in seconds
)
Logging Configuration
Detailed Logging
Enable detailed logging for debugging:
import logging
# Configure auth middleware logging
auth_logger = logging.getLogger("auth_middleware")
auth_logger.setLevel(logging.DEBUG)
# Add handler
handler = logging.StreamHandler()
formatter = logging.Formatter(
'%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
handler.setFormatter(formatter)
auth_logger.addHandler(handler)
Environment-based Logging
# Set log level via environment
AUTH_MIDDLEWARE_LOG_LEVEL=DEBUG
AUTH_MIDDLEWARE_LOG_FORMAT="%(asctime)s %(name)s %(levelname)s %(message)s"
AUTH_MIDDLEWARE_LOGGER_NAME="my_auth"
Security Best Practices
Token Security
Use HTTPS: Always use HTTPS in production to protect tokens in transit
Token Expiration: Ensure tokens have reasonable expiration times
Secure Storage: Never log or store JWT tokens in plain text
Rotation: Implement token rotation strategies
Configuration Security
Environment Variables: Store sensitive configuration in environment variables
Secrets Management: Use proper secrets management systems in production
Least Privilege: Configure minimal required permissions
Monitoring: Monitor authentication failures and suspicious activity
Error Handling Configuration
Custom Error Handlers
from fastapi import FastAPI, HTTPException
from fastapi.responses import JSONResponse
from auth_middleware.exceptions import (
AuthenticationError,
AuthorizationError,
TokenExpiredError,
)
app = FastAPI()
@app.exception_handler(AuthenticationError)
async def authentication_error_handler(request, exc):
return JSONResponse(
status_code=401,
content={
"error": "Authentication Failed",
"message": "Please provide a valid authentication token",
"type": "authentication_error"
}
)
@app.exception_handler(AuthorizationError)
async def authorization_error_handler(request, exc):
return JSONResponse(
status_code=403,
content={
"error": "Access Denied",
"message": "You don't have permission to access this resource",
"type": "authorization_error"
}
)
@app.exception_handler(TokenExpiredError)
async def token_expired_handler(request, exc):
return JSONResponse(
status_code=401,
content={
"error": "Token Expired",
"message": "Your authentication token has expired. Please login again",
"type": "token_expired"
}
)
Development Configuration
Development Mode
For development and testing environments:
import os
# Development-friendly configuration
auth_settings = CognitoAuthzProviderSettings(
user_pool_id=os.getenv("AWS_COGNITO_USER_POOL_ID"),
user_pool_region=os.getenv("AWS_COGNITO_USER_POOL_REGION"),
jwt_token_verification_disabled=os.getenv("ENVIRONMENT") == "development",
)
Hot Reloading
Auth Middleware works with FastAPI’s hot reloading in development:
# Development server with hot reloading
uvicorn main:app --reload --host 0.0.0.0 --port 8000
Testing Configuration
import pytest
from fastapi.testclient import TestClient
@pytest.fixture
def test_app():
app = FastAPI()
# Use mock auth provider for testing
app.add_middleware(
JwtAuthMiddleware,
auth_provider=MockAuthProvider(),
)
return app
def test_protected_endpoint(test_app):
client = TestClient(test_app)
response = client.get(
"/protected",
headers={"Authorization": "Bearer test_token"}
)
assert response.status_code == 200
For more specific provider configurations, see the individual provider documentation:
- JWT Authentication Provider
AUTH_MIDDLEWARE_JWKS_CACHE_INTERVAL_MINUTES
JWKS keys file refreshing interval
An integer value
20
AUTH_MIDDLEWARE_JWKS_CACHE_USAGES
JWKS keys refreshing interval (counter)
An integer value
1000