FastAPI AI Kit ships a complete, production-grade authentication system: JWT tokens for user auth, API keys for programmatic access, and per-key rate limiting.
Overview
The kit implements two authentication methods:
| Method | Use case | Token lifetime | |--------|----------|----------------| | JWT (access token) | User login, dashboard sessions | 30 minutes | | JWT (refresh token) | Token renewal without re-login | 7 days | | API key | Programmatic SDK access | Until revoked |
JWT authentication
Registration and login
# POST /v1/auth/register
{
"email": "dev@example.com",
"password": "your-password"
}
# Response
{
"access_token": "eyJ...",
"refresh_token": "eyJ...",
"token_type": "bearer"
}
Using the access token
Include the token in the Authorization header:
curl https://api.example.com/v1/profile \
-H "Authorization: Bearer eyJ..."
Refreshing tokens
# POST /v1/auth/refresh
{
"refresh_token": "eyJ..."
}
# Response
{
"access_token": "eyJ...",
"token_type": "bearer"
}
API keys
Creating a key
# POST /v1/keys (requires JWT auth)
{
"name": "Production API Key",
"tier": "pro" # basic | pro | enterprise
}
# Response — raw key shown ONCE
{
"id": "uuid",
"key": "kit_live_abc123...",
"prefix": "kit_live_ab",
"name": "Production API Key",
"tier": "pro"
}
Store the raw key securely — it's only shown once.
Using an API key
curl https://api.example.com/v1/chat \
-H "X-API-Key: kit_live_abc123..."
Managing keys
# List keys (shows prefix, not full key)
GET /v1/keys
# Revoke a key
DELETE /v1/keys/{key_id}
Protecting routes
Use the provided decorators in your own route handlers:
from app.auth import require_api_key, rate_limit, get_current_user
# Require a valid API key
@router.post("/v1/your-endpoint")
async def endpoint(key: APIKey = Depends(get_api_key)):
...
# Require specific tier
@router.post("/v1/premium")
@require_api_key(tier=["pro", "enterprise"])
async def premium_endpoint(key: APIKey = Depends(get_api_key)):
...
# Require JWT auth (for user-facing routes)
@router.get("/v1/profile")
async def profile(user: User = Depends(get_current_user)):
...
Rate limiting
Rate limits are enforced per API key via Redis:
@router.post("/v1/chat")
@require_api_key(tier=["basic", "pro"])
@rate_limit(per_minute=60, per_day=5000)
async def chat(key: APIKey = Depends(get_api_key)):
...
Configure tier limits in app/config/tiers.py:
TIER_LIMITS = {
"basic": {"per_minute": 20, "per_day": 1000},
"pro": {"per_minute": 60, "per_day": 5000},
"enterprise": {"per_minute": 300, "per_day": 50000},
}
Exceeding a limit returns HTTP 429 with Retry-After and X-RateLimit-Remaining headers.
Configuration
# .env
JWT_SECRET_KEY=generate-with-openssl-rand-hex-32
ACCESS_TOKEN_EXPIRE_MINUTES=30
REFRESH_TOKEN_EXPIRE_DAYS=7
Generate a secure secret:
openssl rand -hex 32
