Skip to content

Commit 6d99e36

Browse files
committed
Release 0.3.0 — AAuth Budgets resource side (first known implementation)
1 parent d3b7b52 commit 6d99e36

4 files changed

Lines changed: 54 additions & 2 deletions

File tree

CHANGELOG.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,27 @@
11
# Changelog
22

3+
## 0.3.0
4+
5+
**AAuth Budgets** (draft-hardt-aauth-budgets, editor's copy) — the resource
6+
side, first known implementation (running in production on get4agent.com):
7+
8+
- **Auth tokens** (`typ: aa-auth+jwt`): PS-issued budget carriers verified
9+
against a configuration-pinned PS (`HttpsigConfig.trusted_ps`: issuer →
10+
JWKS URL), `aud`-checked against `resource_url`, `cnf`-bound, ≤1h lifetime.
11+
- **`BudgetClaim` + `InMemoryMeter`**: atomic reserve → commit → release
12+
pooled per the draft's `(iss, sub, aud)` aggregation key; conservative
13+
crash-safety (an unresolved reservation counts as consumed); consumption
14+
records **scoped to the presenting agent's `jkt`** so one agent never
15+
learns about a sibling's spending.
16+
- **`BudgetMiddleware`** (FastAPI): `price_fn` hook, metering cycle,
17+
refusals (401 + `AAuth-Requirement` with `reason=insufficient-budget` /
18+
`budget-exhausted` and an optional resource token via
19+
`resource_token_provider`), per-response `AAuth-Budget` header; error
20+
responses release the reservation.
21+
- `build_aauth_budget_header` / `build_aauth_requirement` — RFC 9651
22+
serialization (note: the field is a Dictionary, so members are
23+
comma-separated; the draft's §11 example shows parameter separators).
24+
325
## 0.2.0
426

527
AAuth draft **-11** support (per the editor's copy, ahead of datatracker publication):

README.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

113143
The verifier fetches key directories from **attacker-nameable origins** — whoever signs a

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
44

55
[project]
66
name = "regent-httpsig"
7-
version = "0.2.0"
7+
version = "0.3.0"
88
description = "Verify and sign AI agent HTTP traffic in Python — RFC 9421 HTTP Message Signatures: Web Bot Auth (what OpenAI ships) and AAuth."
99
readme = "README.md"
1010
license = "Apache-2.0"

src/regent_httpsig/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
from regent_httpsig.sign import DIRECTORY_MEDIA_TYPE, EgressSigner, generate_seed
2323
from regent_httpsig.verify import WBA_TAG, HttpsigVerifier, VerifiedSignature
2424

25-
__version__ = "0.2.0"
25+
__version__ = "0.3.0"
2626

2727
__all__ = [
2828
"DIRECTORY_MEDIA_TYPE",

0 commit comments

Comments
 (0)