The Secure Courier: How an AI Agent Proves It May Act for You
Share
How, in Tollbooth DPYC, an Agent proves to an MCP that it may act for you — with no password, and no one in the middle.
An assistant wants to do something on your behalf at a shop that charges by the sip. It knows your public name. It does not hold your key, and you are not at the keyboard. So how does the shop know it is really allowed to spend on your account?
That single question is what the Secure Courier answers. Every other part of the network — the metered tools, the tiny Bitcoin payments, the ledgers — rests on it. Get it wrong and a stranger spends your credits. Get it right and you are asked once, in your own hands, and then left in peace. The name of the whole network is a promise about exactly that: Don't Pester Your Customer.
The actors in this story
The Patron. You. Your patron is known to the Tollbooth DPYC network by an arbitrary public name — a Nostr npub (which looks like npub1<somehash>…) — like the address on an envelope. You use no username, no password, and haveno account to break into. Only you hold the secret half of the Nostr identity, the nsec phrase.
The Agent. The AI assistant acting for you, perhaps Claude or Grok. It holds no key of yours and never should. It can use your public name, and that is all it starts with.
The Operator. The MCP service or shop — a service that answers questions for a few satoshis each. It needs to be paid, and it wants to be sure whom it is serving before it provides service.
The Courier and the Relays. Relays are the Nostr public postal network of untrusted carriers. They ferry sealed envelopes they cannot open, cannot trace, and are asked to burn once read. No carrier is trusted; the seals do the trusting. The Courier is the Tollbooth DPYC software.
How a first meeting goes
1. The agent presents your name, the Patron npub
The agent tells the shop the account it means to act on: your public name. Anyone could type it — a name is not a secret. So the shop does not take the agent's word. It asks for proof that this really comes from you.
2. The shop sends a sealed letter, the secure-courier DM
The Operator writes you a letter and hands it to the couriers, sealed so only you can open it. Inside is a memorable code word — something like calm-yarn-86 — and a short note the shop has signed with its own hand: this is really me asking, here is why I am asking, and here is where you already saw this same code word a moment ago. That signature is the part an impostor cannot forge.
3. You decide, in your own hands
The letter arrives in your Nostr app, not in the agent's UI. You read who is asking and why. The letter identifies the requester and their reason for your confirmation. You check that the code word matches the one the agent said you should expect. If it all lines up, you sign a reply in your own hand for a duration of your choosing, "yes confirmed, but this permission only holds for two weeks." If it doesn't look legit, you may ignore it, and nothing happens. This is the only moment you are asked, until the duration expires or a different operator needs a different permission.
4. The MCP shop issues a grant
The Operator MCP collects your reply, confirms the signature is truly yours, and burns the letter. Then it returns to the agent a grant: a voucher the shop has sealed with its own signature, naming who it is for (your npub), who issued it (its npub), and the day it expires (your duration). From here on the code word is just the label on the envelope — it points to the grant. By itself that initial code phrase will open nothing.
Coming back
5. Every visit thereafter
Now the agent simply presents the grant. The receiving MCP shop reads its own seal, sees your name and an as yet unexpired date, and lets the tool request proceed — no ledger to look up, nothing remembered from last time, so the grant works even after the MCP shop has been asleep, gone cold, and lost memories. The grant carries its own truth.
6. Taking it back (revocation)
You are never forced to honor your original expiration duration. Figuratively, say forget me to the MCP and the MCP shop marks a line in time; every grant ever made in your name, held by any agent anywhere, goes dead on the spot. The next visit has to start over back at the initial protocol.
What a voucher may be worth to a thief
Theft of a voucher deserves concern: the agent carries the grant from visit to visit, so what if someone lifts it? The answer is that the voucher is only a thing you hold rather than a secret you know, and the Tollbooth network makes it costly to steal and inconsequential if lost.
A voucher is legitimate for only one MCP shop: a voucher taken from the GoodEarth seed shop opens nothing at the Explorers map shop, because only the shop that sealed it can read its own seal. A voucher is legitimate only for your Patron: presented under any other name, it is refused, so it is not an all-purpose skeleton key. It cannot be guessed or forged — it is a full signature, not a short word, and the shop keeps no copy of it, so there is no drawer of live vouchers to break into. It expires on the day you chose. And you can burn it early. A stolen voucher is a narrow, short, revocable thing, not a master key.
If the messenger holds its own signet (an nsec)
There is a stronger protocol, for any messenger that carries a key of its own. Such a messenger needs no voucher at all. It signs each request fresh, in the moment, for that one errand — so there is simply nothing to steal, and nothing to lend. This is how the Tollbooth network's own services already interact with one another.
The carried voucher is an arrangement for when the agent does not hold your nsec. When such an assistant asks on your behalf, the voucher is made out to that messenger by name, and your reply signs over the name, so it must also sign in its own hand each time it presents the voucher. A copy in another's hand is then dead paper.
The code word may select a grant, but it never unlocks one. What opens the door is the sealed voucher — signed by the shop, over a signature it watched you make, good only until the day you chose. A word overheard in passing buys nothing.
The word points. The seal opens.
The whole of it. You provide a key, not an account. You are asked once, on a device only you hold, by a shop that has signed its request. What the assistant carries afterward is a sealed voucher that proves itself, expires on your terms, and dies the moment you withdraw it. No password leaves your hands, no central keeper stands in the middle, and no one has to pester you again.
Appendix: what the voucher actually is
For readers who want the field names
The story above calls it a sealed voucher, because that is how it behaves. Underneath, it is a signed Nostr event — the same species of object as a public note or a private message, differing only in the number that declares its type. A note is kind 1 and a direct message is kind 4, whereas a Tollbooth grant is kind 30080, which marks it a credential. It is verified with the same BIP-340 Schnorr signature over secp256k1 that identifies every key in the network, so there is no JOSE header to parse, no header.payload.signature encoding to split apart, and no JWKS endpoint to fetch before a reader can check it.
Anyone who has worked with JSON Web Tokens will recognise most of the furniture. The issuer that a JWT writes as iss is here the event's own pubkey, which is the Operator's key. The subject that a JWT writes as sub is the p tag, naming your patron npub. Where a JWT carries iat, exp and jti, the grant carries created_at, an expiration tag and a d tag holding a UUID. The holder binding that OAuth writes as cnf is a challenge tag holding the SHA-256 of the code word, which is precisely why that word can select a grant without ever opening one.
| Field | Role | What it holds |
|---|---|---|
pubkey |
Issuer | The Operator's own Nostr public key — the shop that sealed the grant. The community registry lists Operators under these keys, so the issuer resolves to a named Operator rather than to an opaque URL. |
p |
Subject | Your patron npub. Presented under any other name, the grant is refused. |
challenge |
Binding | The SHA-256 of the selecting code word. The agent has to present the matching word before the grant will be read. |
patron_sigpatron_event_id
|
Possession | Your own signature, taken from the reply the Operator verified, together with the id of the reply event that signature covers. |
expiration |
Expiry | The NIP-40 expiry, set to the duration you named in your reply and to nothing else. |
d |
Unique id | A UUID belonging to this one grant, which is what a JWT would call its jti. |
tL
|
Type |
dpyc-proof-grant and dpyc.proof_grant, the markers that distinguish a grant from a plain identity credential of the same kind. |
idsig
|
Integrity | The SHA-256 of the serialized event, and the Operator's Schnorr signature over that hash. |
content |
Echo | A small JSON copy of the subject, the issuer, the issued-at time and the challenge, for readers that skip the tags. |
One line of that comparison has no JWT equivalent at all, and it is the line that matters most. A JWT's subject is asserted by the issuer and by nobody else, so the token says you are you because the issuer says so. On the other hand, this grant carries your own signature over the challenge together with the id of the reply that signature covers, and the Operator's seal attests that it verified you making them. The grant is therefore not a shop vouching for your name. It is a shop notarizing something you did.
Two chores that a JWT deployment has to build for itself are answered here by the shape of the thing. Key discovery needs no JWKS document and no rotation endpoint, because the signer is its npub, and whether that npub belongs to a genuine Operator is a lookup in the community registry rather than a fetch from the issuer's own server. Revocation needs no store of live tokens, because the line in time described above refuses any grant issued at or before the moment you said forget me.
Note finally that the id is not a value the issuer gets to choose. It is the hash of the serialized event, and the signature covers precisely that hash, so altering any field at all breaks the id before a verifier even reaches the signature. A JWT's jti, on the other hand, is only a claim the issuer writes in.
For the cryptographic machinery underneath this story — NIP-44v2, the kind-27235 proof event, DPoP session binding and the vault — see No Passwords, No OAuth, No Problem and Applied Cryptography in the Tollbooth DPYC Secure Courier.
Tollbooth-DPYC™ is open source under Apache 2.0. tollbooth-dpyc · dpyc-community








