Credential-Gated API Access, and the Line Between What the Proof Covers and What It Does Not

The idea, and why it is attractive

Replace the anonymous API key with a verified identity. Instead of a shared secret that proves somebody once received a string, the caller presents a proof that a named agent holds a credential saying what it may do.

The check runs offline. Verifying the proof needs no call to us and no account with us, which is what makes this usable by somebody who has no relationship with us at all.

What ships

Four entry points: one for Express, one for Fastify, one for a tool-call server, and one for edge runtimes using only web APIs.

Each takes a verifier and options, the most useful of which requires specific scopes and rejects a credential that lacks them, plus a hook for your own policy over the disclosed claims.

Failures come back as a status, a title and a detail, and the tool-call guard raises an error carrying a protocol-style error code instead.

What the proof covers, exactly

Over HTTP: the request method, the request path, and a timestamp. Nothing else. Not the body, not the query semantics beyond the path string.

Over a tool call: the tool name, and a timestamp. Not the arguments.

That second one deserves a paragraph rather than a clause. For an HTTP endpoint, the path usually carries most of the meaning, so binding it covers most of what a gate cares about. For a tool call, the arguments frequently are the entire request. A proof presented for one invocation of a tool is valid for any other invocation of the same tool inside the acceptance window.

So: do not put an authorisation-relevant decision in tool arguments and expect the proof to cover it. If the amount, the target or the scope of an action lives in the arguments, the gate has verified who is calling and not what they asked for.

Design around it by making the consequential distinction part of the tool name, or by carrying your own challenge, which the package explicitly recommends for anything needing one-time semantics.

Require the status reference, at the gate

A gate is precisely where somebody reads the headline field and moves on.

With no status reference in the envelope, verification returns a valid verdict with an unchecked revocation state, and the reference is supplied by the presenting side. A gate that accepts on the headline field alone lets the caller decide whether its own revocation is checked.

Reject an envelope with no status reference. Treat an unchecked state as a failure. Supply the issuer's status-signing key, or every reference will fail closed and you will have built a gate that refuses everyone.

And treat a revoked verdict from either path as revoked, because the two paths disagree in one direction during a partial failure.

The model you are relying on

Cross-endpoint replay is prevented by construction, since the method and path, or the tool name, are inside the signed binding.

Same-endpoint replay is time-boxed by a skew window that defaults to sixty seconds, with a replay cache on by default.

And the package names the boundary of its own guarantee: anything needing strict one-time semantics should issue its own challenge and verify against that. For a gate protecting something consequential, take that advice rather than the default.

What is genuinely good here

Offline verification. No call to us on the request path, so your latency and your availability do not become our problem.

Scope enforcement and a policy hook, so the common case is configuration rather than code, and the uncommon case is still reachable.

Four runtimes including an edge one, built on web APIs only, which is a real constraint somebody respected rather than an afterthought.

And the honest frame

The scopes you gate on answer to no vocabulary. Nothing defines an allowed set, so the strings in your requireScopes list and the strings an issuer put in a credential have to be agreed between you.

Keep reading

Credential-Gated API Access, and the Line Between What the Proof Covers and What It Does Not · Solidus · Solidus Agents