Verify a signed agent decision. Then try to forge it.
Below is a real authorization decision: an AI agent tried to pay a $9,000 invoice, the gate escalated it, and a human approved it — signing the approval with their own key. Your browser is about to check both signatures. Nothing is uploaded. No account. No call to authoxi. Then edit any field you like and watch it fail.
The decision
loss-event/v2 · editable — that's the point
Not checked yet
- ·Press Verify in my browser.
What just happened
Your browser took the event, stripped the signature fields the signer excluded, canonicalized the
rest (sorted keys, no whitespace, floats refused), hashed it with SHA-256, pulled the Ed25519
public key out of the event's own did:key, and checked the signature.
No registry lookup. No network call. It works if authoxi is offline, acquired, or dead.
There are two signatures, and the order is asymmetric on purpose. The human signs first, at decision time, over a body that excludes the gate's envelope — they cannot attest to a countersignature that does not exist yet. The gate then signs last, over a body that includes the human's signature. That is what binds an approval to this event: without it, a valid $9,000 approval could be lifted off and stapled onto a $9,000,000 payment, with both signatures still verifying.
Same check, on your machine, in your CI:
curl -O https://docs.authoxi.com/assets/approved-payment.json
npx -p @authoxi/js authoxi-verify approved-payment.json # exit 0 if it holds, 1 if it doesn't
Or in Python, where your agents probably already live:
from authoxi import verify_event, verify_stream
result = verify_event(event)
result.ok # every signature holds; nothing was altered
result.verified # a human signed it — derived from the signature, never from the flag
ok, checks = verify_stream(events) # signatures AND seq continuity — catches deletion
It drops straight into a pipeline and fails the build on a broken audit trail. There are three implementations — Python, a zero-dependency Node CLI, and the WebCrypto module you just ran — and they share no code, on purpose. Three independent programs agreeing on one signed vector is evidence the format is real, rather than something that is true only because one program says so. Read any of them: a verifier you haven't read is just a second thing to trust.
What a PASS does not prove
We would rather you knew the limits than trusted the output. This is the section every vendor in this category leaves out.
- It does not bind a key to a person. A signature binds an action to a key. Binding that key to a named human is your identity process, not this tool's job. What it does guarantee: whoever holds that key cannot later deny the decision.
-
It does not prove no event was suppressed. A signature proves an event is
unaltered; it says nothing about one you never received. That is what the signed, monotonic
seqfield is for — verify a stream and a hole in the sequence is a decision somebody didn't want you to see. Deletion, not forgery, was always the easier attack on an audit trail. - It does not prove the action executed. This is the record of an authorization, not of an effect.
Why this matters at all
Most teams gate their agent's dangerous actions with a Slack message and an approved_by
column. That works right until someone has to prove it — and a database row is mutable by
everyone who can write to the database, which includes the person you are trying to hold
accountable. A log tells you what happened;
evidence proves it.
The format is an open spec. Implement it, fork it, or ignore us and build your own — but if you are letting an agent touch money, please make the record signed.