Your OAuth proves who is calling. BAP proves what they may do.
If you run an MCP server, an agent, or any API that authenticates callers with
OAuth, you already have the who. BAP is the missing half: every request carries
a cryptographically signed capability — one operation, one target, one time window — and a fresh
proof from the caller’s own key. The resource verifies the envelope and gets facts, never trust.
Keys never leave your custody.
Private keys never enter the library — not even in the demo below.
npm 0.1.2
CI: green on macOS · Linux · Windows
Apache-2.0
The piece OAuth leaves out
OAuth and MCP authentication answer “which client is this?” — and stop there.
What that client may do is left to scopes, hope, and your resource server’s restraint.
BAP closes that gap, alongside the OAuth you already run.
A token says who — not what.
A stolen or over-scoped token keeps every power it was granted, on every
resource, until it expires. “read” means all reads, everywhere, for the token’s whole life.
With BAP, each capability is a signed grant naming
one operation, one target, one window — and each request carries a fresh proof
bound to exactly that request.
Trust moves to facts.
Today your resource trusts the transport, the introspection endpoint, and the
caller’s good behavior. Nothing cryptographic ties this particular request to this particular
permission.
The verifier checks the envelope itself — issuer
signature, holder binding, operation match, time window — and returns cryptographic
facts, with no reason codes for attackers to probe.
Your keys stay yours.
Authority systems usually want your private key, or a vendor to hold it for
you. That’s a new blast radius most teams won’t accept.
BAP never takes key material — issuers and holders
sign through their own custody (HSM, KMS, or a browser key store — the demo below uses one).
Nothing to hand over, nothing to leak.
Where it pays off
Four places teams already feel the gap between who and what —
every one works with the OAuth you already run.
An agent that can spend money
MCP agent · payments API
Hand the agent a token and whatever it decides — or gets injected to decide —
the token allows, until it expires.
grant: transfer · acct acme-77 · until 14:15
No proof, no transfer: a hijacked
prompt can’t move funds at 14:40, or to a different account — the API enforces the envelope,
not the agent’s good behavior.
A third-party tool you didn’t write
your workspace · someone else’s MCP server
Connecting a tool today often means blanket, long-lived scopes over your files
or mail — to code you’ve never audited.
grant: read · attachments/ only · this session
Every tool call carries a fresh
proof against a narrow grant — the tool, or whoever compromises it, can’t browse an inch past
the bound.
Just-in-time elevation
on-call engineer or automation · production
Standing admin rights “just in case,” and break-glass tokens nobody remembers
to revoke.
grant: deploy + rollback · staging · 30 min
The window closes itself —
yesterday’s grant is cryptographically useless today, with no revocation list to babysit.
Key rotation rides the same rails (signKeyTransition).
Support reading one customer
support agent · multi-tenant SaaS
A “support” role token typically reads every tenant’s records — access decided
by policy files, not cryptography.
grant: read · tenant #4821 · ticket #90112
Curiosity can’t cross tenants:
each read is proven against a grant that names one tenant and one ticket’s lifetime.
The envelope playground
Everything below is live: this page bundles the real signer and verifier
packages and signs with a key generated in your browser. No server, no simulation, no mocks.
Issuer grants authority
may
transfer · { kind: "all" }
audience
resource.example.test
window
t=1000 → 2000 (evaluated at 1500)
Holder your agent
request
POST /invoke · amount: 5000
invocation
550e8400-…440000
Verifier the resource
trusts issuer key
—
verify an envelope to see the fact sheet
—
Tamper deckEvery button below produces a real, closed INVALID.
Sign and prove first — then break it on purpose.
Wire viewerClick any artifact to inspect its actual bytes.
nothing selected yet
The family lifecycle
Three protocols, one chain of evidence: what the agent is, what was agreed, what this call may do.
Authorize each requestIssuer-signed grants + holder proofs govern every call, per request — the authority layer over OAuth
Custody boundary
Keys stay in your custody — an HSM, a KMS, or the browser key store this page just used. The library only ever sees a handle.
C1 role gate
A holder handle can never mint its own capability: grants require an issuer-role identity resolved atomically, before sign() is even called.
Wrong-key guard
Every signature is verified against the resolved public key before assembly. A misconfigured custodian fails loudly as signing_failed — never a silent false success.
Closed errors
A closed error-code set; no key material, nonce values, or report content ever appears in an error.