Metadata-Version: 2.5
Name: fastapi-alcazaba
Version: 0.9.1
Summary: Secure, maintained tools for FastAPI: response cache, rate limits, sessions, CSRF, webhooks, a task queue and more
Project-URL: Homepage, https://github.com/nonodev96/fastapi-alcazaba
Project-URL: Documentation, https://nonodev96.github.io/fastapi-alcazaba/
Project-URL: Repository, https://github.com/nonodev96/fastapi-alcazaba
Project-URL: Issues, https://github.com/nonodev96/fastapi-alcazaba/issues
Project-URL: Changelog, https://github.com/nonodev96/fastapi-alcazaba/blob/main/CHANGELOG.md
Author-email: Antonio Mudarra Machuca <nonodev96@gmail.com>
License-Expression: Apache-2.0
License-File: LICENSE
License-File: NOTICE
Keywords: authentication,authorization,cache,caching,casbin,circuit-breaker,cron,fastapi,jwt,oauth2,pagination,rate-limiting,rbac,redis,saml,scheduler,security,toolkit,valkey
Classifier: Development Status :: 4 - Beta
Classifier: Framework :: FastAPI
Classifier: Intended Audience :: Developers
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Internet :: WWW/HTTP
Classifier: Typing :: Typed
Requires-Python: >=3.11
Requires-Dist: fastapi>=0.115
Requires-Dist: pydantic>=2.7
Requires-Dist: typing-extensions>=4.10
Provides-Extra: all
Requires-Dist: aiobotocore>=2.13.1; extra == 'all'
Requires-Dist: aiomcache>=0.8.2; extra == 'all'
Requires-Dist: backports-zstd>=1.0; (python_version < '3.14') and extra == 'all'
Requires-Dist: cedarpy>=4.12; extra == 'all'
Requires-Dist: cryptography>=44; extra == 'all'
Requires-Dist: httpx2>=2.15.1; extra == 'all'
Requires-Dist: opentelemetry-api>=1.27; extra == 'all'
Requires-Dist: pycasbin>=2.0; extra == 'all'
Requires-Dist: pyjwt[crypto]>=2.10; extra == 'all'
Requires-Dist: redis>=5.0.8; extra == 'all'
Requires-Dist: signxml>=5.2; extra == 'all'
Requires-Dist: sqlalchemy>=2.0; extra == 'all'
Requires-Dist: valkey-glide>=2.5; extra == 'all'
Requires-Dist: valkey>=6.0; extra == 'all'
Requires-Dist: zxcvbn>=4.5; extra == 'all'
Provides-Extra: auth-strategy-http-bearer
Provides-Extra: auth-strategy-jwt
Requires-Dist: httpx2>=2.15.1; extra == 'auth-strategy-jwt'
Requires-Dist: pyjwt[crypto]>=2.10; extra == 'auth-strategy-jwt'
Provides-Extra: auth-strategy-oauth2
Requires-Dist: httpx2>=2.15.1; extra == 'auth-strategy-oauth2'
Provides-Extra: auth-strategy-oidc
Requires-Dist: httpx2>=2.15.1; extra == 'auth-strategy-oidc'
Requires-Dist: pyjwt[crypto]>=2.10; extra == 'auth-strategy-oidc'
Provides-Extra: auth-strategy-saml
Requires-Dist: signxml>=5.2; extra == 'auth-strategy-saml'
Provides-Extra: auth-strategy-unkey
Requires-Dist: httpx2>=2.15.1; extra == 'auth-strategy-unkey'
Provides-Extra: casbin
Requires-Dist: pycasbin>=2.0; extra == 'casbin'
Provides-Extra: cedar
Requires-Dist: cedarpy>=4.12; extra == 'cedar'
Provides-Extra: clamav
Provides-Extra: crypto
Requires-Dist: cryptography>=44; extra == 'crypto'
Provides-Extra: dynamodb
Requires-Dist: aiobotocore>=2.13.1; extra == 'dynamodb'
Provides-Extra: glide
Requires-Dist: valkey-glide>=2.5; extra == 'glide'
Provides-Extra: memcache
Requires-Dist: aiomcache>=0.8.2; extra == 'memcache'
Provides-Extra: opa
Requires-Dist: httpx2>=2.15.1; extra == 'opa'
Provides-Extra: otel
Requires-Dist: opentelemetry-api>=1.27; extra == 'otel'
Provides-Extra: password-strength
Requires-Dist: zxcvbn>=4.5; extra == 'password-strength'
Provides-Extra: passwords
Requires-Dist: httpx2>=2.15.1; extra == 'passwords'
Provides-Extra: redis
Requires-Dist: redis>=5.0.8; extra == 'redis'
Provides-Extra: ses
Requires-Dist: aiobotocore>=2.13.1; extra == 'ses'
Provides-Extra: sqlalchemy
Requires-Dist: sqlalchemy>=2.0; extra == 'sqlalchemy'
Provides-Extra: uploads
Requires-Dist: httpx2>=2.15.1; extra == 'uploads'
Provides-Extra: valkey
Requires-Dist: valkey>=6.0; extra == 'valkey'
Provides-Extra: webhooks
Requires-Dist: httpx2>=2.15.1; extra == 'webhooks'
Provides-Extra: zstd
Requires-Dist: backports-zstd>=1.0; (python_version < '3.14') and extra == 'zstd'
Description-Content-Type: text/markdown

<p align="center">
  <img src="https://raw.githubusercontent.com/nonodev96/fastapi-alcazaba/main/docs/assets/logo.png" alt="Alcazaba's logo: a fortress wall whose horseshoe-arch gate opens on a bolt" width="150">
</p>

<h1 align="center">Alcazaba</h1>

<p align="center">
  <strong>Secure, maintained tools for FastAPI</strong><br>
  Response cache, rate limits, sessions, CSRF, webhooks, a task queue and more, in one package.
</p>

<p align="center">
  <a href="https://nonodev96.github.io/fastapi-alcazaba/"><strong>Documentation</strong></a> |
  <a href="https://nonodev96.github.io/fastapi-alcazaba/latest/examples/">Examples</a> |
  <a href="https://pypi.org/project/fastapi-alcazaba/">PyPI</a> |
  <a href="https://github.com/nonodev96/fastapi-alcazaba/blob/main/CHANGELOG.md">Changelog</a> |
  <a href="https://github.com/nonodev96/fastapi-alcazaba/blob/main/SECURITY.md">Security policy</a>
</p>

---

Alcazaba (`fastapi-alcazaba`) gathers the pieces most FastAPI apps end up writing themselves,
built with security in mind and tested against real servers. They share one backend (memory,
Redis, Valkey, memcached or DynamoDB), one format of errors and one set of metrics.

| Tool | In `fastapi_alcazaba.` | What it does |
| --- | --- | --- |
| [Response cache](https://nonodev96.github.io/fastapi-alcazaba/latest/guide/cache/) | `response_cache` | `@cache` for endpoints and functions, invalidated by tag, signed or encrypted |
| [Rate and concurrency limits](https://nonodev96.github.io/fastapi-alcazaba/latest/guide/limits/) | `rate_limit` | a sliding window, and at most N requests at a time, shared by every process |
| [Idempotency keys](https://nonodev96.github.io/fastapi-alcazaba/latest/guide/idempotency/) | `idempotency` | a retried POST gets the first response instead of running twice |
| [Authentication](https://nonodev96.github.io/fastapi-alcazaba/latest/guide/authentication/) | `auth` | `FastAPIAuth` with strategies: JWTs (signing keys of any type that rotate, refresh tokens), bearer tokens, sessions, OAuth2, OpenID Connect and SAML logins, Unkey's API keys, your own |
| [Tokens, codes and API keys](https://nonodev96.github.io/fastapi-alcazaba/latest/guide/auth/) | `auth` | a JWT blocklist, refresh tokens that detect reuse, one-time codes and API keys, nothing stored in clear |
| [Passwords](https://nonodev96.github.io/fastapi-alcazaba/latest/guide/passwords/) | `auth` | weak, common and leaked passwords refused with the reasons (zxcvbn, a blocklist, Have I Been Pwned), scrypt hashes with a pepper, guesses limited per account, resets by a link that works once |
| [Passkeys](https://nonodev96.github.io/fastapi-alcazaba/latest/guide/passkeys/) | `auth` | logins without a password (WebAuthn), which a phishing page can't relay |
| [Second factor](https://nonodev96.github.io/fastapi-alcazaba/latest/guide/two-factor/) | `auth` | authenticator apps' codes (TOTP) after the password, recovery codes, step-up for sensitive actions |
| [Authorization](https://nonodev96.github.io/fastapi-alcazaba/latest/guide/authorization/) | `authz` | `FastAPIAuthz`: a Casbin, Cedar or Open Policy Agent policy decides who may do what, per route or for every request |
| [Browser apps](https://nonodev96.github.io/fastapi-alcazaba/latest/guide/browser/) | `security` | server-side sessions (each user's, listed and ended), CSRF protection, security headers and body size |
| [Webhooks and outbound calls](https://nonodev96.github.io/fastapi-alcazaba/latest/guide/webhooks/) | `webhooks`, `outbound` | webhooks verified (Standard Webhooks, GitHub, Stripe, Slack) and sent (signed, retried, SSRF-guarded); deadlines, breakers and SSRF protection for httpx |
| [Uploads](https://nonodev96.github.io/fastapi-alcazaba/latest/guide/uploads/) | `uploads` | the real type from the bytes, size, image dimensions, safe names |
| [Object storage](https://nonodev96.github.io/fastapi-alcazaba/latest/guide/storage/) | `uploads` | signed URLs and upload forms for S3, R2 or MinIO, without an SDK |
| [Countries and Spain](https://nonodev96.github.io/fastapi-alcazaba/latest/guide/countries/) | `countries` | ISO 3166-1 countries by any code; Spain's provinces, postal codes and tax IDs (DNI, NIE, NIF, CIF) checked, as Pydantic fields |
| [E-mail](https://nonodev96.github.io/fastapi-alcazaba/latest/guide/mail/) | `mail` | password resets, codes and receipts over SMTP with TLS, without forged headers |
| [Pagination](https://nonodev96.github.io/fastapi-alcazaba/latest/guide/pagination/) | `pagination` | page numbers, offsets, ranges, cursors, keysets, scrolls and streams, cached page by page |
| [Background work](https://nonodev96.github.io/fastapi-alcazaba/latest/guide/background/) | `background` | a task queue (timeouts, unique tasks, status, a command line), scheduled jobs, locks, leader election, broadcast to every process and an outbox (purged, traced, recoverable) |
| [Operations](https://nonodev96.github.io/fastapi-alcazaba/latest/guide/operations/) | `operations` | circuit breakers, maintenance mode and feature flags |
| [Observability](https://nonodev96.github.io/fastapi-alcazaba/latest/guide/observability/) | `observability`, `telemetry` | problem details, request IDs, timeouts, health checks (of the queue, broadcast, leader, SMTP, storage), backlog gauges, OpenTelemetry, logs as JSON |
| [Accounting](https://nonodev96.github.io/fastapi-alcazaba/latest/guide/accounting/) | `accounting` | what each user, API key or tenant uses per period, held to its plan's quotas, a record per charge for billing |
| [Audit trail](https://nonodev96.github.io/fastapi-alcazaba/latest/guide/audit/) | `audit` | who did what to which resource; no secrets, signed and chained |

## Install

```shell
pip install fastapi-alcazaba            # in-memory backend only
pip install "fastapi-alcazaba[redis]"   # or [valkey], [glide], [memcache], [dynamodb], [all]
```

Python 3.11+, FastAPI 0.115+ and Pydantic v2. The other extras (OpenTelemetry, encryption,
Casbin, JWT, OAuth2, SAML...) are in the
[guide](https://nonodev96.github.io/fastapi-alcazaba/latest/guide/production/).

## A taste

```python
from collections.abc import AsyncIterator
from contextlib import asynccontextmanager

from fastapi import Depends, FastAPI
from pydantic import BaseModel

from fastapi_alcazaba import FastAPICache
from fastapi_alcazaba.backends.inmemory import InMemoryBackend
from fastapi_alcazaba.rate_limit import FastAPIRateLimiter
from fastapi_alcazaba.response_cache import cache


@asynccontextmanager
async def lifespan(_: FastAPI) -> AsyncIterator[None]:
    FastAPICache.init(InMemoryBackend(), prefix="shop")  # RedisBackend for several processes
    yield


app = FastAPI(lifespan=lifespan)


class Product(BaseModel):
    name: str
    price: float


@app.get(
    "/products/{product_id}",
    dependencies=[Depends(FastAPIRateLimiter(times=10, seconds=1))],  # per client
)
@cache(expire=60, vary_headers=())  # the same response for everybody: one shared entry
async def product(product_id: int) -> Product:
    return Product(name="Olive oil", price=9.5)
```

The [guide](https://nonodev96.github.io/fastapi-alcazaba/latest/guide/) starts with an app built
in three steps, and each tool has a page of its own and an example app that runs as it is.

## Security

The security tools (revocations, idempotency, webhooks, sessions, the task queue) fail closed
when the backend does, and none of them puts secrets in logs, keys or errors. The
[security model](https://nonodev96.github.io/fastapi-alcazaba/latest/guide/security-model/)
says what each tool protects against and what it needs from you; report vulnerabilities as
[SECURITY.md](SECURITY.md) says.

## Development

```shell
make deps               # .venv with every extra
make lint               # ruff, mypy and pylint
make test               # the unit tests, with coverage
make services-up        # Redis, Valkey, memcached and DynamoDB in Docker, for:
make test-integration
```

[CONTRIBUTING.md](CONTRIBUTING.md) has the rest.

## License

Apache License 2.0: see [LICENSE](LICENSE) and [NOTICE](NOTICE).
