Metadata-Version: 2.1
Name: os-fastapi-middleware
Version: 1.1.4
Summary: Adaptable security middlewares for FastAPI: API keys, rate limiting, IP whitelist
Author-email: Tiago Morais <tcharrua@oddsscanner.com>
License: MIT
Project-URL: Homepage, https://github.com/tcharrua-odds/os-fastapi-middleware
Project-URL: Documentation, https://github.com/tcharrua-odds/os-fastapi-middleware/blob/main/README.md
Project-URL: Repository, https://github.com/tcharrua-odds/os-fastapi-middleware
Project-URL: Issues, https://github.com/tcharrua-odds/os-fastapi-middleware/issues
Keywords: fastapi,middleware,security,rate-limit,api-key,ip-whitelist
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Framework :: FastAPI
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE.md
Requires-Dist: fastapi>=0.100.0
Requires-Dist: starlette>=0.27.0
Provides-Extra: redis
Requires-Dist: redis>=5.0.0; extra == "redis"
Provides-Extra: dev
Requires-Dist: pytest>=7.0.0; extra == "dev"
Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
Requires-Dist: httpx>=0.24.0; extra == "dev"
Requires-Dist: black>=23.0.0; extra == "dev"
Requires-Dist: ruff>=0.0.270; extra == "dev"

# OS FastAPI Middlewares

Simple and adaptable: production-ready security middlewares for FastAPI, including API Key, Rate Limit, and IP Whitelist. Plug in in-memory or Redis providers, or implement your own.

- API Key: validates a key from the request, optionally injects metadata into request.state
- Rate Limit: enforces requests per time window and adds X-RateLimit-* headers
- IP Whitelist: allows only approved IPs or networks (supports CIDR)

Docs: see docs/installation.md, docs/quickstart.md, and docs/advanced.md.

## Installation

- Basic: `pip install os-fastapi-middleware`
- With Redis (optional): `pip install os-fastapi-middleware[redis]`

Requirements: Python >= 3.8, FastAPI >= 0.100, Starlette >= 0.27.

## Quick example

```python
from fastapi import FastAPI, Request
from os_fastapi_middleware.middleware import APIKeyMiddleware, RateLimitMiddleware, IPWhitelistMiddleware
from os_fastapi_middleware.providers import (
    InMemoryAPIKeyProvider,
    InMemoryRateLimitProvider,
    InMemoryIPWhitelistProvider,
)

app = FastAPI()

api_key_provider = InMemoryAPIKeyProvider(valid_keys={
    "account_123": "secret-key-123"
})
rate_limit_provider = InMemoryRateLimitProvider()
ip_whitelist_provider = InMemoryIPWhitelistProvider(allowed_ips=["127.0.0.1"]) 

app.add_middleware(RateLimitMiddleware, provider=rate_limit_provider, requests_per_window=100, window_seconds=60)
app.add_middleware(APIKeyMiddleware, provider=api_key_provider, include_metadata=True)
app.add_middleware(IPWhitelistMiddleware, provider=ip_whitelist_provider)

@app.get("/secure")
async def secure(request: Request):
    return {"hello": request.state.api_key_metadata["account_id"]}
```

More examples in examples/.

## Per-route or route group usage

You can also apply validations selectively to specific routes or route groups using dependencies:

```python
from fastapi import FastAPI, Depends, Request
from os_fastapi_middleware.dependencies import APIKeyDependency, RateLimitDependency, IPWhitelistDependency
from os_fastapi_middleware.providers import (
    InMemoryAPIKeyProvider,
    InMemoryRateLimitProvider,
    InMemoryIPWhitelistProvider,
)

app = FastAPI()

# Configure providers
api_key_provider = InMemoryAPIKeyProvider(valid_keys={"account_123": "secret-key-123"})
rate_limit_provider = InMemoryRateLimitProvider()
ip_whitelist_provider = InMemoryIPWhitelistProvider(allowed_ips=["127.0.0.1"])

# Create dependency instances
api_key_dep = APIKeyDependency(provider=api_key_provider)
rate_limit_dep = RateLimitDependency(provider=rate_limit_provider, requests_per_window=10, window_seconds=60)
ip_whitelist_dep = IPWhitelistDependency(provider=ip_whitelist_provider)

# Public route - no validation
@app.get("/public")
async def public():
    return {"message": "This is public"}

# Protected route - API key only
@app.get("/protected", dependencies=[Depends(api_key_dep)])
async def protected():
    return {"message": "API key validated"}

# Strict route - multiple validations
@app.get("/admin", dependencies=[Depends(ip_whitelist_dep), Depends(api_key_dep), Depends(rate_limit_dep)])
async def admin():
    return {"message": "Admin area with all protections"}

# Route group with shared dependencies
from fastapi import APIRouter
api_router = APIRouter(prefix="/api", dependencies=[Depends(api_key_dep)])

@api_router.get("/data")
async def get_data():
    return {"data": "protected by API key"}

@api_router.get("/stats")
async def get_stats():
    return {"stats": "also protected by API key"}

app.include_router(api_router)
```

See examples/selective_routes.py for more details.

## Key features

- Pluggable providers: in-memory, Redis, and base classes to customize
- Clear configuration: sensible, named parameters
- Rate limit headers: X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset
- Works behind proxies (X-Forwarded-For) when enabled

## Tests

Install dev dependencies and run:

```bash
pip install -e .[dev]
pytest -q
```

## License

MIT. See LICENSE if available.
