Apikee

Python

apikee for Python — FastAPI, Flask, Starlette, and raw ASGI.

Python

PyPI Python

Installation

pip install apikee                  # local validation only (zero deps)
pip install "apikee[server]"        # + AES-256-GCM encrypted server channel
pip install "apikee[fast]"          # + msgpack (faster serialisation)
pip install "apikee[fastapi]"       # + FastAPI middleware
pip install "apikee[all]"           # everything

FastAPI

SecuredFastAPI is a drop-in replacement for FastAPI(). It automatically:

  • Registers the ASGI validation middleware
  • Patches openapi() to inject ApikeeAuth into every path and the global security block
  • Exports ApikeeDepends(), get_claims(), and require_scope() as ready-to-use dependencies
from apikee.fastapi import SecuredFastAPI, ApikeeDepends, require_scope
from apikee import ApikeeClaims
from fastapi import Depends

app = SecuredFastAPI(
    title="My API",
    secrets=["your-signing-secret"],
    exclude_paths={"/health", "/keys"},  # paths that skip validation
    # server_key="sk_live_...",          # uncomment for server mode
    # project_env="my-app-production",
)

@app.get("/data")
def get_data(claims: ApikeeClaims = ApikeeDepends()):
    return {"tenant": claims.tenant, "scopes": claims.scopes}

@app.delete("/users/{id}", dependencies=[Depends(require_scope("admin"))])
def delete_user(id: str, claims: ApikeeClaims = ApikeeDepends()):
    return {"deleted": id}

Issuing keys

@app.post("/keys", tags=["auth"])
def create_key(tenant: str, scopes: str = "read,write"):
    key = app.apikee.create(
        tenant=tenant,
        scopes=scopes.split(","),
        expires_in=timedelta(days=90),
    )
    return {"key": key}

Opening /docs after adding SecuredFastAPI shows a 🔒 lock icon on every endpoint. The Authorize button lets you paste a key and test all routes directly in Swagger UI.

Flask

from flask import Flask
from apikee.flask import init_apikee, apikee_required, require_scope, get_claims

app = Flask(__name__)
apikee = init_apikee(app, secrets=["your-signing-secret"])

@app.get("/data")
@apikee_required
def get_data():
    claims = get_claims()
    return {"tenant": claims.tenant}

@app.post("/items")
@require_scope("write")
def create_item():
    claims = get_claims()
    return {"created": True, "tenant": claims.tenant}, 201

@app.delete("/items/<int:id>")
@require_scope("admin")
def delete_item(id):
    return {"deleted": id}

Starlette (raw ASGI)

from starlette.applications import Starlette
from apikee import Apikee

apikee = Apikee(secrets=["your-signing-secret"])
app    = Starlette(routes=[...])

# One line — works with any ASGI framework
app.add_middleware(apikee.middleware)

Claims are available on request.state.apikee in every route handler.

Configuration reference

ParameterTypeDefaultDescription
secretslist[str]requiredSigning secrets. First is current; rest accepted for rotation.
server_keystrNoneapikee.dev project key (sk_live_...). Enables server mode.
project_envstrNoneapikee.dev project_env slug, e.g. my-app-production.
header_namestr"x-api-key"Header to read the key from.
default_expirytimedelta90dDefault expiry for new keys.
auto_register_endpointsboolTrueRegister endpoints with apikee.dev on first request (server mode).
auto_create_clientsboolTrueAuto-create client on apikee.dev when issuing a key (server mode).
fail_openboolTrueIf server call fails, allow request through.

ApikeeClaims fields

FieldTypeDescription
idstrUnique key ID (ULID-style)
tenantstrTenant / owner identifier
scopeslist[str]Permission scopes
environmentstrEnvironment tag (production, staging, etc.)
expires_atdatetime | NoneExpiry as a timezone-aware datetime
not_beforedatetime | NoneNot-valid-before as a timezone-aware datetime
metadictArbitrary user-defined metadata
raw_keystrOriginal key string

Errors

All validation failures raise ApikeeError with a code attribute:

CodeCause
MISSING_KEYNo key in request header
INVALID_PREFIXKey doesn't start with apikee_
INVALID_FORMATMissing . separator
DECODE_ERRORInvalid base62 or JSON
INVALID_SIGNATUREHMAC check failed
EXPIREDexp timestamp is in the past
NOT_YET_VALIDnbf timestamp is in the future
INSUFFICIENT_SCOPEKey missing required scope
SERVER_REJECTEDapikee.dev rejected the request (server mode)

Source

github.com/apikee-dev/python

On this page