FastAPI dependency authenticating an Auths-Presentation request into a typed Principal
Project description
auths-fastapi
A FastAPI dependency that authenticates an Auths-Presentation request and yields a typed
Principal, or raises HTTPException. It is the Python counterpart of the Axum reference
middleware in crates/auths-api/src/rp_auth.rs: an injectable verifier, a real single-use
challenge store, a verdict→status mapping, and a dependency that hands a handler a Principal
only on success.
Scope
- First-party only. The relying party trusts credentials issued under DIDs it has pinned
in
pinned_roots(the.auths/rootsmodel — DID-only; capabilities come from the verified credential, never the request). There is no federation or third-party issuer discovery. - Challenge mode is the default. The interactive
GET /v1/auth/challenge→ single-use nonce → present flow is the v1 path and the one this package mints. A TTL binding is opt-in (non-interactive, no store entry to consume); within its TTL a TTL presentation can be replayed, so prefer the challenge binding unless you have a reason not to. - Single process. The bundled
ChallengeStorelives in one process's heap. Behind a load balancer fronting N nodes a nonce minted on one node is unknown to another, and the single-use guarantee holds only per node — supply a shared store backend for multi-node.
Security notes
- The nonce and signature are never logged by this package; do not log the
Authorizationheader in your own middleware either. - 401 responses carry
WWW-Authenticate: Bearerso generic clients treat them as a standard auth challenge. - The expected audience is the relying party's configured audience, not the wire header.
Install
pip install auths-fastapi # the dependency + challenge store (fake-verifier testable)
pip install "auths-fastapi[native]" # + the `auths` binding for the production verifier
pip install "auths-fastapi[client]" # + httpx for fetch_challenge
Usage
from fastapi import Depends, FastAPI
from auths_fastapi import (
Capability, ChallengeStore, KeriPresentationVerifier, Principal,
PresentationInputs, auths_principal, challenge_router, configure, configure_mint,
)
AUDIENCE = "api.example.com"
store = ChallengeStore(max_live=10_000)
def load_inputs(credential_said: str) -> PresentationInputs:
# Resolve the credential SAID to its KEL/TEL inputs from your registry.
...
configure(KeriPresentationVerifier(
audience=AUDIENCE,
challenges=store,
load_inputs=load_inputs,
pinned_roots=frozenset({"did:keri:Eroot"}),
))
configure_mint(store, AUDIENCE)
app = FastAPI()
app.include_router(challenge_router) # GET /v1/auth/challenge
@app.post("/v1/deploy")
async def deploy(principal: Principal = Depends(auths_principal(Capability("deploy:prod")))):
return {"deployed_by": principal.subject}
Guard a whole group
from fastapi import APIRouter, Depends
admin = APIRouter(
prefix="/v1/admin",
dependencies=[Depends(auths_principal(Capability("admin:read")))],
)
@admin.get("/status") # protected by the router-level dependency; no Principal needed
async def admin_status():
return {"status": "ok"}
A route that does not depend on auths_principal(...) receives no Principal and is
unauthenticated by construction.
Client flow
from auths_fastapi import fetch_challenge
issued = fetch_challenge("https://api.example.com/v1/auth/challenge")
# sign over issued.nonce, build the Auths-Presentation token, send it in Authorization.
Status mapping
| Outcome | Status | Header |
|---|---|---|
| Verified, capability satisfied | 200 | — |
| Missing/malformed header, expired, revoked, wrong audience, replay, holder-not-current, unpinned issuer | 401 | WWW-Authenticate: Bearer |
| Authenticated but missing the required capability | 403 | — |
| Challenge store at capacity | 503 | — |
Testing without the native binding
The crypto verify step is injected behind the PresentationVerifier protocol. Tests supply a
fake verifier over the real ChallengeStore, so replay/audience/expiry are genuinely
exercised with no binding installed (see tests/test_dependency.py). Run pytest.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file auths_fastapi-0.1.3.tar.gz.
File metadata
- Download URL: auths_fastapi-0.1.3.tar.gz
- Upload date:
- Size: 51.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
70f9972490a20ddd00f4d0b207f2b26d40ebc6e15240abb2050b00f55a8a7397
|
|
| MD5 |
7000b229d8e6edcad2a3a5737273f6a5
|
|
| BLAKE2b-256 |
ce643f53f3745300013d33a7354212641763855ded94e9d01de4725c26b39601
|
Provenance
The following attestation bundles were made for auths_fastapi-0.1.3.tar.gz:
Publisher:
publish-fastapi.yml on auths-dev/auths
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
auths_fastapi-0.1.3.tar.gz -
Subject digest:
70f9972490a20ddd00f4d0b207f2b26d40ebc6e15240abb2050b00f55a8a7397 - Sigstore transparency entry: 1784609321
- Sigstore integration time:
-
Permalink:
auths-dev/auths@7f1e0fac474987cf3d86280eb90a0e267167d19d -
Branch / Tag:
refs/tags/v0.1.3 - Owner: https://github.com/auths-dev
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-fastapi.yml@7f1e0fac474987cf3d86280eb90a0e267167d19d -
Trigger Event:
push
-
Statement type:
File details
Details for the file auths_fastapi-0.1.3-py3-none-any.whl.
File metadata
- Download URL: auths_fastapi-0.1.3-py3-none-any.whl
- Upload date:
- Size: 15.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
159bd3b06455e463d6ffe229039504418e9d086f306ba3ec299195417142b8d7
|
|
| MD5 |
799b8669c7058b0f4cc6febaba207083
|
|
| BLAKE2b-256 |
b1e90db0f2d27f65f3bd88c467e5296c1287115bd70721a14ef477f2a1bdfd72
|
Provenance
The following attestation bundles were made for auths_fastapi-0.1.3-py3-none-any.whl:
Publisher:
publish-fastapi.yml on auths-dev/auths
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
auths_fastapi-0.1.3-py3-none-any.whl -
Subject digest:
159bd3b06455e463d6ffe229039504418e9d086f306ba3ec299195417142b8d7 - Sigstore transparency entry: 1784609489
- Sigstore integration time:
-
Permalink:
auths-dev/auths@7f1e0fac474987cf3d86280eb90a0e267167d19d -
Branch / Tag:
refs/tags/v0.1.3 - Owner: https://github.com/auths-dev
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-fastapi.yml@7f1e0fac474987cf3d86280eb90a0e267167d19d -
Trigger Event:
push
-
Statement type: