Metadata-Version: 2.5
Name: aidr-verifier
Version: 0.1.3
Summary: Verify AI agents' AIDR identities on your own site, offline: credentials and RFC 9421 signatures.
Project-URL: Homepage, https://aidr.evolivcore.com
Project-URL: Documentation, https://evolivcore.com/resources
Author: Evoliv Core
License-Expression: Apache-2.0
License-File: LICENSE
Keywords: ai-agents,aiaf,aidr,bot-verification,identity,rfc9421
Classifier: Development Status :: 3 - Alpha
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Security
Requires-Python: >=3.10
Requires-Dist: aidr-crypto<0.2,>=0.1
Requires-Dist: httpx>=0.27
Provides-Extra: django
Requires-Dist: django>=4.2; extra == 'django'
Provides-Extra: fastapi
Requires-Dist: fastapi>=0.110; extra == 'fastapi'
Provides-Extra: flask
Requires-Dist: flask>=3.0; extra == 'flask'
Description-Content-Type: text/markdown

# aidr-verifier

Verify an AI agent's identity on your own site, offline: the agent's credential (signed by the
[AIDR](https://aidr.evolivcore.com) registry) and its RFC 9421 request signature. Nothing in the
request path calls the registry.

```
pip install "aidr-verifier[fastapi]"
```

ASGI (FastAPI, Starlette): the middleware keeps keys and revocation state in sync in the
background and puts the result in `request.state.aidr`:

```python
from aidr_verifier import AidrMiddleware, RelyingPartyConfig

app.add_middleware(AidrMiddleware, config=RelyingPartyConfig(
    issuer="https://api.evolivcore.com", public_origin="https://shop.example", min_agal=1))
```

Anonymous visitors pass as `anonymous`; a request that claims an identity and fails is refused.
An audience-bound credential is checked against the site being visited (or `public_origin`).
Flask (WSGI), in one line:

```python
from aidr_verifier.wsgi import AidrWSGIMiddleware, RelyingPartyConfig

app.wsgi_app = AidrWSGIMiddleware(app.wsgi_app, RelyingPartyConfig(
    issuer="https://api.evolivcore.com", public_origin="https://shop.example"))
# request.environ["aidr"] in a view
```

Classic Django: add `"aidr_verifier.django.AidrMiddleware"` first in `MIDDLEWARE` and set
`AIDR = {"issuer": "https://api.evolivcore.com", "public_origin": "https://shop.example"}`; views
read `request.aidr`.

`public_origin` is your site's own origin (or `AIDR_PUBLIC_ORIGIN`; a list for several host names).
Signatures are checked against it, never against the Host header a client sends, which would let a
request signed for another site be replayed here. On localhost it can be left out. In 0.1.3 a
missing `public_origin` logs a warning; from 0.2.0 agents are refused without it.

If the registry stays out of reach, agents are refused (503 `aidr.registry.unavailable`) once the
newest revocation list held was signed 11 minutes (`max_revocation_age_seconds=660`) earlier,
judged from its signed `iat`; anonymous visitors are unaffected. Every AIDR verifier applies the
same limit. `health()["revocation_issued_at"]` shows how close a site is to it.

`mode="verified-only"` (with `verified_only_paths`) refuses anonymous requests with 401, as the
Cloudflare Worker and the Node middleware do. Or verify a request yourself with `AgentVerifier`.
Apache-2.0.
