Python SDK for verifying Web Bot Auth (OpenBotAuth) signed requests using RFC 9421 HTTP Message Signatures
Project description
OpenBotAuth Verifier SDK for Python
Python SDK for verifying OpenBotAuth-signed HTTP requests (aligned with the Web Bot Auth IETF draft) using RFC 9421 HTTP Message Signatures.
OpenBotAuth is an open-source implementation that follows the approach described in the Web Bot Auth draft. The draft is evolving; this SDK focuses on practical interoperability by calling the OpenBotAuth verifier service (hosted or self-hosted). It enables Python origins (FastAPI, Starlette, Flask) to verify AI agent and bot signatures.
Installation
pip install openbotauth-verifier
For framework-specific middleware:
# FastAPI/Starlette
pip install openbotauth-verifier[fastapi]
# Flask
pip install openbotauth-verifier[flask]
# All extras including dev dependencies
pip install openbotauth-verifier[all]
Quick Start
FastAPI / Starlette
from fastapi import FastAPI, Request
from openbotauth_verifier import OpenBotAuthASGIMiddleware
app = FastAPI()
# Add middleware (observe mode - logs verification but allows all requests)
app.add_middleware(OpenBotAuthASGIMiddleware)
# Or enforce verification:
# app.add_middleware(OpenBotAuthASGIMiddleware, require_verified=True)
@app.get("/protected")
async def protected(request: Request):
oba = request.state.oba
if oba.signed and oba.result.verified:
return {
"message": "Verified bot access",
"agent": oba.result.agent,
}
return {"message": "Unverified access"}
Flask
from flask import Flask, request, g
from openbotauth_verifier.middleware.wsgi import OpenBotAuthWSGIMiddleware
app = Flask(__name__)
app.wsgi_app = OpenBotAuthWSGIMiddleware(app.wsgi_app)
@app.before_request
def load_oba():
g.oba = request.environ.get("openbotauth.oba")
@app.route("/protected")
def protected():
if g.oba and g.oba.signed and g.oba.result.verified:
return {
"message": "Verified bot access",
"agent": g.oba.result.agent,
}
return {"message": "Unverified access"}
Direct Client Usage
from openbotauth_verifier import VerifierClient
client = VerifierClient()
# Async
result = await client.verify(
method="GET",
url="https://example.com/api",
headers={
"signature-input": 'sig=("host");created=1699900000',
"signature": "base64signature==",
"signature-agent": "https://registry.openbotauth.org/jwks/mybot.json",
"host": "example.com",
},
)
if result.verified:
print(f"Verified agent: {result.agent['client_name']}")
else:
print(f"Verification failed: {result.error}")
# Sync
result = client.verify_sync(method="GET", url="...", headers={...})
Configuration
Verifier URL
By default, the SDK uses the hosted verifier at https://verifier.openbotauth.org/verify.
For local development or self-hosted verifiers:
# Middleware
app.add_middleware(
OpenBotAuthASGIMiddleware,
verifier_url="http://localhost:8081/verify",
)
# Client
client = VerifierClient(verifier_url="http://localhost:8081/verify")
Middleware Modes
Observe Mode (default): Attaches verification state but allows all requests.
app.add_middleware(OpenBotAuthASGIMiddleware, require_verified=False)
Require Mode: Returns 401 for unsigned or failed verification.
app.add_middleware(OpenBotAuthASGIMiddleware, require_verified=True)
Timeout
app.add_middleware(OpenBotAuthASGIMiddleware, timeout_s=10.0)
client = VerifierClient(timeout_s=10.0)
Verification State
The middleware attaches an OBAState object:
@dataclass
class OBAState:
signed: bool # Request had signature headers
result: VerificationResult | None
@dataclass
class VerificationResult:
verified: bool # Signature was valid
agent: dict | None # Agent info (kid, jwks_url, client_name)
error: str | None # Error message if failed
created: int | None # Signature creation timestamp
expires: int | None # Signature expiration timestamp
Access in your handlers:
# FastAPI/Starlette
oba = request.state.oba
# Flask
oba = request.environ.get("openbotauth.oba")
Security
Sensitive Header Protection
The SDK never forwards sensitive headers to the verifier service:
cookieauthorizationproxy-authorizationwww-authenticate
If any of these headers are covered by Signature-Input, the verification fails immediately with a ValueError - no network call is made.
Header Forwarding
Only these headers are forwarded to the verifier:
signature-input,signature,signature-agent(always)- Headers explicitly listed in the
Signature-Inputcovered components - Derived components (starting with
@) are parsed but not forwarded as headers
Testing with bot-cli
Use the Node.js bot-cli from the OpenBotAuth monorepo to test your Python server:
1. Start your Python server
cd sdks/python
python -m venv .venv
source .venv/bin/activate
pip install -e ".[fastapi]"
uvicorn examples.fastapi_demo:app --port 8009
2. Test with bot-cli
# From the monorepo root
pnpm --filter @openbotauth/bot-cli dev fetch http://localhost:8009/protected -v
Notes
-
Hosted verifier: Requires your JWKS URL (from
Signature-Agent) to be publicly reachable. Use an OpenBotAuth registry JWKS URL if you have one. -
Local verifier: Start the verifier service locally and configure:
app.add_middleware( OpenBotAuthASGIMiddleware, verifier_url="http://localhost:8081/verify", )
API Reference
VerifierClient
VerifierClient(
verifier_url: str = "https://verifier.openbotauth.org/verify",
timeout_s: float = 5.0,
)
Methods:
async verify(method, url, headers, body=None) -> VerificationResultverify_sync(method, url, headers, body=None) -> VerificationResult
OpenBotAuthASGIMiddleware
OpenBotAuthASGIMiddleware(
app,
verifier_url: str = "https://verifier.openbotauth.org/verify",
require_verified: bool = False,
timeout_s: float = 5.0,
)
Sets request.state.oba: OBAState
OpenBotAuthWSGIMiddleware
OpenBotAuthWSGIMiddleware(
app,
verifier_url: str = "https://verifier.openbotauth.org/verify",
require_verified: bool = False,
timeout_s: float = 5.0,
)
Sets environ["openbotauth.oba"]: OBAState
Header Utilities
from openbotauth_verifier import parse_covered_headers, extract_forwarded_headers
# Parse covered headers from Signature-Input
headers = parse_covered_headers('sig=("host" "content-type");created=123')
# Returns: ["host", "content-type"]
# Extract safe headers to forward
forwarded = extract_forwarded_headers(request_headers)
# Raises ValueError if sensitive headers are covered
Development
cd sdks/python
python -m venv .venv
source .venv/bin/activate
pip install -e ".[all]"
# Run tests
pytest
# Type checking
mypy src
# Linting
ruff check src tests
Resources
- OpenBotAuth Website: https://openbotauth.org
- Main Repository: https://github.com/OpenBotAuth/openbotauth
- Web Bot Auth (IETF Draft): https://datatracker.ietf.org/doc/draft-kelsey-httpbis-web-bot-auth/
- RFC 9421 (HTTP Message Signatures): https://www.rfc-editor.org/rfc/rfc9421.html
- PyPI Package: https://pypi.org/project/openbotauth-verifier/
License
Apache-2.0
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 openbotauth_verifier-0.1.0.tar.gz.
File metadata
- Download URL: openbotauth_verifier-0.1.0.tar.gz
- Upload date:
- Size: 19.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
09ae259e73ddd887ea73907339bd8406930416a6261132413f2abdcfc5200d19
|
|
| MD5 |
f556554492a2842fcffd7ecefaa74701
|
|
| BLAKE2b-256 |
4c1c1bf27cba517de29e15d94be2f21e05622a7e3921ccd2464bc0e4c90fce9f
|
File details
Details for the file openbotauth_verifier-0.1.0-py3-none-any.whl.
File metadata
- Download URL: openbotauth_verifier-0.1.0-py3-none-any.whl
- Upload date:
- Size: 21.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
75db2f214cf6dc5001ed1f672b22e91491add3e3b784f82b19a6bcf05c481924
|
|
| MD5 |
13213bd0602243fc9537230eacfe924e
|
|
| BLAKE2b-256 |
b424885b7768e98ae6ea03397439f4158fca2c254da8bec36fbbd7623c8a2481
|