Skip to content

Alcazaba's logo: a fortress wall whose horseshoe-arch gate opens on a bolt

Alcazaba

Secure, maintained tools for FastAPI
Response cache, rate limits, sessions, CSRF, webhooks, a task queue and more, in one package.

CI PyPI version Python versions OpenSSF Scorecard License: Apache 2.0


Documentation: https://nonodev96.github.io/fastapi-alcazaba/

Source code: https://github.com/nonodev96/fastapi-alcazaba


Alcazaba (fastapi-alcazaba) gathers the pieces most FastAPI apps end up writing themselves: a response cache, rate limits, authorization, sessions, CSRF protection, webhooks, a task queue and more, built with security in mind.

The key features are:

  • Secure by default: users never get each other's cached responses, nothing that opens a door (keys, codes, tokens) is stored in clear, and whatever could leak data is opt-in.
  • Shared by every process: rate limits, locks, sessions, revoked tokens, feature flags and maintenance mode live in Redis, Valkey, memcached or DynamoDB, so that every process and container sees them at once.
  • Resilient: every call to the backend has a timeout and a circuit breaker. A backend that fails doesn't take the app down.
  • The FastAPI way: dependencies, decorators and middlewares that show in the OpenAPI docs, with types your editor completes.
  • Standards: problem details (RFC 9457), Cache-Status (RFC 9211), the IETF's RateLimit headers, Standard Webhooks, Casbin, Cedar and Open Policy Agent policies, and OpenTelemetry.
  • Tested hard: against real servers on Python 3.11 to 3.14, with fuzzing and mutation testing.
  • Many tools, one package: a response cache, rate and concurrency limits, idempotency keys, authentication strategies, API keys and tokens, passkeys and a second factor (TOTP), authorization, accounting and quotas, sessions and CSRF, an audit trail, upload checks, webhooks, scheduled jobs, a task queue, circuit breakers, maintenance mode and feature flags. See them all.

Get started Features

Requirements

Python 3.11 or later, FastAPI 0.115 or later and Pydantic v2. Everything else is optional: each backend and integration comes with an extra.

Installation

$ pip install fastapi-alcazaba

That's enough for an app in a single process, with everything kept in memory.

Example

Create it

Create a file main.py with:

main.py
from collections.abc import AsyncIterator
from contextlib import asynccontextmanager

from fastapi import FastAPI, HTTPException
from pydantic import BaseModel

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


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


app = FastAPI(lifespan=lifespan)


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


PRODUCTS = {1: Product(name="Olive oil", price=9.5)}


@app.get("/products/{product_id}")
@cache(expire=60)
async def read_product(product_id: int) -> Product:
    if product_id not in PRODUCTS:
        raise HTTPException(404, "No such product")
    return PRODUCTS[product_id]

Run it

Run it with fastapi dev, which comes with pip install "fastapi[standard]" (or uvicorn main:app --reload):

$ fastapi dev main.py

 ⚡️ Starting FastAPI in development mode

 🌐 Server started at http://127.0.0.1:8000
    Documentation at http://127.0.0.1:8000/docs

Check it

Ask for the product twice:

$ curl -i http://127.0.0.1:8000/products/1
HTTP/1.1 200 OK
cache-status: Alcazaba; fwd=miss; stored
cache-control: max-age=60

{"name":"Olive oil","price":9.5}

$ curl -i http://127.0.0.1:8000/products/1
HTTP/1.1 200 OK
cache-status: Alcazaba; hit; ttl=60
cache-control: max-age=60

{"name":"Olive oil","price":9.5}

The first request ran read_product; the second one came from the cache, which keeps the response for 60 seconds. Requests with an Authorization or Cookie header get entries of their own: users never see each other's responses.

Interactive API docs

Open http://127.0.0.1:8000/docs: the endpoint is there as FastAPI documents it, with its parameters and response model.

Example upgrade

The Tutorial - User Guide takes this app further, a step at a time: five requests a minute for each client, then prices that only the staff may change, as a Casbin policy says:

@app.put("/products/{product_id}", dependencies=[Depends(authz)])
async def update_product(product_id: int, product: Product) -> Product:
    if product_id not in PRODUCTS:
        raise HTTPException(404, "No such product")
    PRODUCTS[product_id] = product
    await FastAPICache.invalidate_tags(f"product:{product_id}")
    return product

Recap

In summary, you add Alcazaba's tools the way FastAPI already works: a decorator caches an endpoint, a dependency limits it or checks who may call it, and the lifespan sets up where their state lives. The app keeps its OpenAPI schema and its types, and moving from memory to Redis changes one line.

For a more complete example, with more tools, see the Tutorial - User Guide.

Optional dependencies

Each backend and integration needs a library of its own, which an extra installs:

Extra Installs For
redis redis-py RedisBackend
valkey valkey-py ValkeyBackend
glide Valkey GLIDE GlideBackend
memcache aiomcache MemcachedBackend
dynamodb aiobotocore DynamoBackend
otel the OpenTelemetry API metrics and traces
crypto cryptography encrypted entries
zstd backports.zstd, before Python 3.14 zstd compression
casbin PyCasbin the enforcers of FastAPIAuthz
cedar cedarpy CedarEnforcer
opa httpx2 OPAEnforcer
auth-strategy-jwt PyJWT, with cryptography JWTStrategy
auth-strategy-oauth2 httpx2 OAuth2Strategy
auth-strategy-oidc httpx2, PyJWT OIDCStrategy
auth-strategy-saml signxml SAMLStrategy
auth-strategy-unkey httpx2 UnkeyStrategy
auth-strategy-http-bearer nothing more HTTPBearerStrategy
all all of the above
$ pip install "fastapi-alcazaba[redis,casbin]"

License

This project is licensed under the terms of the Apache License 2.0. Its credits, and where its name comes from, are in About.