Metadata-Version: 2.4
Name: algovoi-passport-client
Version: 0.1.4
Summary: Present and verify AlgoVoi Agent Passports: Falcon-1024 (FIPS 206) agent credentials, verified fully offline against the issuer's published key (RFC 8785 JCS + pqcrypto). The client half of the AlgoVoi payment rails' agent passport.
Author-email: AlgoVoi <chopmob@gmail.com>
License-Expression: Apache-2.0
Project-URL: Homepage, https://docs.algovoi.co.uk/payment-rails-sqlite
Project-URL: AlgoVoi Payment Rails, https://docs.algovoi.co.uk/payment-rails-sqlite
Project-URL: Source, https://github.com/chopmob-cloud/algovoi-passport-client
Keywords: agent,passport,falcon,pqc,fips-206,x402,a2a,jcs,rfc8785,credential,verify
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
License-File: NOTICE
Requires-Dist: rfc8785>=0.1.2
Requires-Dist: pqcrypto>=0.3.0,<1
Dynamic: license-file

# algovoi-passport-client

Present and verify **AlgoVoi Agent Passports**, the client half of the AlgoVoi payment
rails' agent passport.

Part of the [AlgoVoi Payment Rails](https://docs.algovoi.co.uk/payment-rails-sqlite).

An Agent Passport is a Falcon-1024 (FIPS 206) signed credential that binds an agent DID to
a set of scopes, a spend bound, and an expiry. The issuer runs inside the rails; this is the
client an agent developer needs, both sides of the wire.

```bash
pip install algovoi-passport-client
```

The FIPS 206 verifier (`pqcrypto`) and the RFC 8785 canonicaliser (`rfc8785`) are installed
with it, so verification works out of the box with no AlgoVoi service in the trust path.

## Present your passport (agent side)

```python
from algovoi_passport_client import load_credential, x402_headers, a2a_message_metadata

cred = load_credential()                 # from $ALGOVOI_AGENT_PASSPORT, or pass a path
headers  = x402_headers(cred)            # {"X-Agent-Passport": "<cred>"} on an x402 request
metadata = a2a_message_metadata(cred)    # A2A message metadata carrying the passport
```

## Verify a received passport (relying party)

```python
from algovoi_passport_client import verify_passport, resolve_keys_from_wellknown, fetch_crl

# resolve the issuer key + revocation list once (or pin them from a local trust store)
keys = resolve_keys_from_wellknown("https://pay.issuer.com")   # {kid: pk_bytes}
crl  = fetch_crl("https://pay.issuer.com", next(iter(keys)))

v = verify_passport(cred, issuer_keys=keys, crl=crl, required_scope="pay:invoice")
if v:                                     # True only when status == "active"
    print("ok:", v.agent_did, v.scopes, v.spend_limit_microusd)
else:
    print("refused:", v.status, v.error_code)   # revoked | expired | invalid | unverifiable
```

Verification is **fail-closed**: with no key resolved or no revocation confirmation, the
verdict is `unverifiable`, never a default-trust `active`. The credential's `kid` is checked
against `sha256(pk)[:16]` of the resolved key, so a swapped key cannot validate. The verdict
statuses match the issuer's own: `active | revoked | expired | invalid | unverifiable`.

For a strictly offline trust base, pin the key and CRL and pass them directly; the client
touches the network only through `resolve_keys_from_wellknown` and `fetch_crl`, which you can
also feed with your own `fetch` callable.

## CLI

```bash
algovoi-passport inspect  <credential>                        # decode (does NOT trust)
algovoi-passport verify   <credential> --issuer-url https://pay.issuer.com --scope pay:invoice
algovoi-passport verify   <credential> --keys keys.json --crl crl.json    # strictly offline
algovoi-passport present  <credential> --x402                 # emit the header to attach
```

A `<credential>` may be given literally or as `@path` to read it from a file.

## Keystone interop

The open-source [keystone](https://docs.algovoi.co.uk/keystone) is content-addressed under
the same primitive the passport uses: `keystone_ref(payload) == "sha256:" + SHA-256(RFC 8785
JCS(payload))`. So a verified passport drops straight into a keystone chain or journal as a
content-addressed record:

```python
from algovoi_passport_client import passport_keystone_ref, passport_record

ref = passport_keystone_ref(cred)     # byte-identical to keystone_ref(payload)
record = passport_record(cred)        # {**payload, "passport_ref": ref}; `keystone validate` PASSes it
```

The passport's Falcon-1024 signature carries **authenticity**; keystone carries
**composition** (this delegation binds this passport binds this execution). They share no code
beyond RFC 8785 + SHA-256, so `passport_record(cred)` self-verifies against the published
`keystone validate` and any `keystone_ref` verifier.

## License

Apache-2.0. (c) AlgoVoi. Keep the NOTICE attribution when you redistribute.
