@@ -108,6 +108,36 @@ keyid-less shape is pinned in CI.
108108 [ christian-posta/aauth-python-library] ( https://github.com/christian-posta/aauth-python-library ) —
109109 this library is the thin relying-party verifier that handles both dialects.
110110
111+ ## Budgets: meter a spending envelope (draft-hardt-aauth-budgets)
112+
113+ An agent can carry a PS-issued ** auth token** (` typ: aa-auth+jwt ` ) with a
114+ ` budget ` claim — a spending envelope it uses offline, no per-call round trip
115+ to the control plane. The middleware does the whole resource-side checklist:
116+ verify the token against your pinned PS, atomically reserve → commit →
117+ release per request, answer with ` AAuth-Budget ` , and refuse exhausted
118+ envelopes with a ` 401 ` + ` AAuth-Requirement ` (optionally carrying your signed
119+ resource token with the agent's own consumption records — scoped to its key,
120+ so one agent never learns about a sibling's spending):
121+
122+ ``` python
123+ from regent_httpsig import HttpsigConfig, HttpsigVerifier, InMemoryMeter
124+ from regent_httpsig.fastapi import BudgetMiddleware
125+
126+ app.add_middleware(
127+ BudgetMiddleware,
128+ verifier = HttpsigVerifier(HttpsigConfig(
129+ resource_url = " https://api.example" ,
130+ trusted_ps = {" my-ps" : " https://ps.example/jwks.json" },
131+ )),
132+ meter = InMemoryMeter(),
133+ price_fn = lambda request : PRICES .get(request.url.path), # max cost, minor units
134+ )
135+ ```
136+
137+ The only thing the library cannot do for you is pricing (` price_fn ` ) — that
138+ is your domain. First known implementation of the draft; running in
139+ production on [ get4agent.com] ( https://get4agent.com ) .
140+
111141## Security model (what a naive implementation gets wrong)
112142
113143The verifier fetches key directories from ** attacker-nameable origins** — whoever signs a
0 commit comments