API Key Management in FastAPI with APIAuth

FastAPI is the go-to framework for modern Python APIs. But managing the API keys that protect those endpoints? That's still a manual mess — keys in .env files, secrets in CI logs, no rotation, no audit trail.

APIAuth is a local CLI that generates, stores, verifies, and rotates API keys in an AES-256-GCM encrypted keystore. It works offline, has no telemetry, and integrates with FastAPI through a simple dependency. Here's how to wire it up.

Install

pip install git+https://github.com/Coding-Dev-Tools/apiauth.git
# or: pip install git+https://github.com/Coding-Dev-Tools/apiauth.git

Generate keys for your FastAPI services

Each service gets its own named key with an expiry date:

# Generate a key for the payments service
apiauth generate api-key --name "Payments API" --service "payments" --expiry-days 90

# Generate a JWT with custom claims for the auth service
apiauth generate jwt --name "Auth Service JWT" --service "auth" --expiry-days 30 --claim role=admin --claim scope=write

Keys are stored in ~/.apiauth/keystore.enc encrypted with a master key that never leaves your machine.

FastAPI dependency for key verification

Create a dependency that verifies incoming keys against the local keystore:

# auth.py
from fastapi import Depends, HTTPException, Security
from fastapi.security import APIKeyHeader
import subprocess
import json

api_key_header = APIKeyHeader(name="X-API-Key", auto_error=False)

def verify_api_key(api_key: str = Security(api_key_header)):
    if not api_key:
        raise HTTPException(status_code=401, detail="Missing API key")
    
    # Verify against the local keystore
    result = subprocess.run(
        ["apiauth", "verify", api_key, "--json-output"],
        capture_output=True, text=True
    )
    
    if result.returncode != 0:
        raise HTTPException(status_code=401, detail="Invalid or expired API key")
    
    key_data = json.loads(result.stdout)
    return key_data

# Usage in your routes
@app.get("/api/payments")
async def get_payments(key_data: dict = Depends(verify_api_key)):
    return {"service": key_data.get("service"), "data": "..."}

Middleware for automatic verification

For global protection, add middleware that verifies every request:

# middleware.py
from starlette.middleware.base import BaseHTTPMiddleware
from starlette.requests import Request
from starlette.responses import Response, JSONResponse
import subprocess

class APIAuthMiddleware(BaseHTTPMiddleware):
    async def dispatch(self, request: Request, call_next):
        # Skip health checks and docs
        if request.url.path in ["/health", "/docs", "/openapi.json", "/redoc"]:
            return await call_next(request)
        
        api_key = request.headers.get("X-API-Key")
        if not api_key:
            return JSONResponse({"detail": "Missing API key"}, status_code=401)
        
        result = subprocess.run(
            ["apiauth", "verify", api_key, "--json-output"],
            capture_output=True, text=True
        )
        
        if result.returncode != 0:
            return JSONResponse({"detail": "Invalid or expired API key"}, status_code=401)
        
        # Attach key info to request state for downstream use
        import json
        request.state.api_key_data = json.loads(result.stdout)
        
        return await call_next(request)

app.add_middleware(APIAuthMiddleware)

Rotate keys in CI/CD without downtime

Rotate the key, export the new value for the runner, and the old key is hashed out:

# In your deployment pipeline
# 1. Rotate the key for the service being deployed
apiauth rotate 

# 2. Export the fresh key value for GitHub Actions
apiauth export --format github-actions --service payments >> $GITHUB_ENV

# 3. Audit before release — fails if any key is expired
apiauth audit --exit-on-expired

apiauth audit --exit-on-expired exits non-zero if anything is stale, so the deploy stops before a bad key ships.

Free vs Individual tier

The Free tier covers generate, verify, and env-format export for up to 5 keys — enough for a solo project. The Individual tier ($12/mo, $10/yr) unlocks unlimited keys, all export formats (dotenv, JSON, GitHub Actions), JWT custom claims, and audit/stats commands. A Suite license covering all 11 Coding Dev Tools tools is $49/mo ($39/yr).

Verification notes

Claims sourced from apiauth/README.md and cross-checked against Obsidian-Vault-Local/40-Marketing/verified-facts-ledger.md (last verified 2026-07-07). Install is not public PyPI. Working paths: pip install git+https://github.com/Coding-Dev-Tools/apiauth.git or pip install git+https://github.com/Coding-Dev-Tools/apiauth.git. Pricing table: Free $0 (5 keys), Individual $12/mo ($10/yr), Suite $49/mo ($39/yr), Team $79/mo ($63/yr), Enterprise custom. License: MIT. Python 3.10+.