Show HN: Verify OpenAI's signed agent traffic in Python (RFC 9421/Web Bot Auth) Regent released regent-httpsig, a Python library that verifies and signs AI agent HTTP traffic per RFC 9421 and the Web Bot Auth draft, enabling FastAPI and framework-agnostic verification of OpenAI-signed requests and egress signing for agent identification. The library passes byte-exact test vectors for RFC 9421 Appendix B.2.6 and Web Bot Auth drafts -05 A.2.2 and A.2.3, with sign-verify roundtrips and AAuth identity-mode interop pinned in CI, and reports upstream deviations in the draft's A.2.2 example and aauth-signing's base64 encoding. Verification is enrichment by default, returning None for missing or invalid signatures, and the FastAPI dependency rebuilds signed URLs from X-Forwarded-Proto and Host for reverse proxy deployments. Verify and sign AI agent HTTP traffic in Python — the way OpenAI signs and Cloudflare verifies. RFC 9421 · Web Bot Auth · AAuth OpenAI's agents cryptographically sign every HTTP request they make. Cloudflare, AWS WAF and Google verify those signatures. This library brings both sides of that handshake to Python: verify signed agents hitting your API, and sign your own agent's traffic so bot walls recognize it. pip install regent-httpsig python from fastapi import FastAPI from regent httpsig import HttpsigVerifier from regent httpsig.fastapi import attach, SignatureDep, VerifiedSignature app = FastAPI attach app, HttpsigVerifier @app.post "/v1/orders" async def create order sig: VerifiedSignature | None = SignatureDep : if sig: print sig.agent "https://chatgpt.com" print sig.keyid RFC 7638 key thumbprint ... No FastAPI? The core has no framework dependencies: verifier = HttpsigVerifier sig = await verifier.verify method, url, headers VerifiedSignature | None Verification is enrichment by default : no Signature header costs nothing, a bad signature yields None , and nothing ever raises on untrusted input. Use regent httpsig.fastapi.RequiredSignatureDep when a signature must be present — the 401 tells the agent exactly how to sign. Behind a reverse proxy?The agent signed thepublicURL https://api.example/… , but your ASGI server sees http://container/… . The FastAPI dependency rebuilds the signed URL from X-Forwarded-Proto + Host , so make sure your proxy forwards the scheme — nginx: proxy set header X-Forwarded-Proto $scheme; . If signatures mysteriously fail to verify in production, check this first. python from regent httpsig import EgressSigner signer = EgressSigner seed=os.environ "AGENT KEY SEED" , signature agent="https://myagent.example" headers = signer.sign "POST", url, {"content-type": "application/json"} resp = httpx.post url, json=body, headers=headers Generate a key and the ready-to-publish /.well-known/ files in one command: regent-httpsig keygen --agent https://myagent.example --out ./well-known/ Publish the directory at https://myagent.example/.well-known/http-message-signatures-directory and every Web Bot Auth verifier on the internet can now identify your agent. | Check | Status | |---|---| | RFC 9421 Appendix B.2.6 Ed25519 vector byte-exact | ✅ in CI | Web Bot Auth draft -05 A.2.2 — sf-dictionary Signature-Agent covered with ;key= | ✅ in CI¹ | Web Bot Auth A.2.3 — legacy sf-string form what OpenAI ships in production | ✅ in CI | | Sign → verify roundtrip fresh keys, full pipeline | ✅ in CI | AAuth identity-mode roundtrip aa-agent+jwt + cnf.jwk proof of possession | ✅ in CI | | Signed by aauth-signing | ¹ The signature bytes printed in the draft's own A.2.2 example do not verify over the draft's own signature base the legacy A.2.3 vector and RFC 9421 B.2.6 both do, so the defect is in the example, not the canonicalization . Ed25519 is deterministic, so our test pins the vector re-signed with the same RFC test key over the same byte-exact base — reported upstream. ² Cross-library interop with aauth-signing 's jwt scheme: token layer, cnf.jwk proof of possession and canonicalization all verify. Its signers correctly omit the optional keyid parameter — which exposed an unconditional keyid read in the underlying RFC 9421 library that we now handle. One deviation reported upstream to aauth-signing : it emits the Signature byte sequence as base64url, while RFC 8941 requires standard base64. The keyid-less shape is pinned in CI. Web Bot Auth draft-meunier-web-bot-auth-architecture : key discovery via {Signature-Agent}/.well-known/http-message-signatures-directory . Both wire forms of Signature-Agent are accepted — the current sf-dictionary and the legacy bare sf-string OpenAI actually sends. AAuth draft-hardt-oauth-aauth-protocol , identity-based mode : the agent carries a JWT agent token in Signature-Key ; the issuer's JWKS verifies the token, the token's cnf.jwk verifies the request signature. Install with pip install 'regent-httpsig aauth ' . Tracks the -11 editor's copy : fully-specified algorithms RFC 9864, Ed25519 — with a transition flag for the -10 ecosystem's EdDSA and person tokens aa-person+jwt , opt-in via HttpsigConfig.resource url . For a full-protocol AAuth implementation both roles, all token types see christian-posta/aauth-python-library https://github.com/christian-posta/aauth-python-library — this library is the thin relying-party verifier that handles both dialects. The verifier fetches key directories from attacker-nameable origins — whoever signs a request chooses its Signature-Agent . regent-httpsig ships with the guard rails on: SSRF protection by default : https-only, every resolved IP must be public catches 169.254.169.254 , loopback, private ranges, DNS names mapping to internal services , redirects never followed, responses size-capped. Bounded caching : per-instance TTL cache with eviction — a keyid-spam attack can't grow memory; failures are negative-cached so a dead origin can't be used to slow you down. A valid signature proves key possession — not trustworthiness. VerifiedSignature.trusted reflects only your configured allow-list; deciding whether to trust a key is your policy layer's job. Known sharp edges of the underlying ecosystem, already handled: the upstream http-message-signatures library cannot resolve RFC 9421 ;key= dictionary members we provide the component resolver , it looks up header names case-sensitively while ASGI frameworks lowercase them we wrap , and it forgets to declare typing extensions we declare it . python from regent httpsig import HttpsigConfig, HttpsigVerifier verifier = HttpsigVerifier HttpsigConfig trusted agents=frozenset {"https://chatgpt.com", "https://operator.openai.com"} , max age hours=25, reject signatures created earlier than this cache ttl=600, key-directory cache seconds Pass your app's shared client to reuse its pool: HttpsigVerifier http client=my async client . - Web Bot Auth and AAuth are IETF drafts RFC 9421 itself is a final standard . We track the drafts; breaking draft changes land as minor releases while we're 0.x. Ed25519 only for now — it's what the agent ecosystem ships.- Body coverage content-digest is verified when covered by the signature, but this library does not require it; decide per-route whether you need it. cloudflare/web-bot-auth https://github.com/cloudflare/web-bot-auth TypeScript/Rust · christian-posta/aauth-python-library https://github.com/christian-posta/aauth-python-library full AAuth protocol · pyauth/http-message-signatures https://github.com/pyauth/http-message-signatures the RFC 9421 primitive this builds on Built and battle-tested in production by Regent Protocol https://regentprotocol.org — runtime control and identity for AI agents. Apache-2.0.