@facet-llc/origination-coinbase-cdp
v0.2.2
Published
Facet Terminal origination verifier for Coinbase Developer Platform AgentKit credentials. Verifies wallet-signed attestations from agents provisioned via CDP and emits an AgentPrincipal scoped to the agent's CDP wallet address.
Readme
@facet-llc/origination-coinbase-cdp
Facet Terminal origination verifier for Coinbase Developer Platform (CDP) AgentKit-provisioned agents. Implements FacetOriginationVerifier from @facet-llc/protocol.
What this is
AgentKit-provisioned agents are server-managed wallets issued by CDP. The agent proves its identity to a merchant by signing a canonical attestation envelope with its CDP wallet. The merchant verifies the ECDSA signature against the claimed address using viem's verifyMessage.
The CDP SDK's role on the agent side is wallet management. Merchant-side acceptance is plain ECDSA verification. We do not reimplement that. viem is the authoritative tool.
The verifier fails closed: replay cache (rejects duplicate bind_to within maxEnvelopeAgeSeconds), 8 KB attestation cap, character-set sanitization, and a configurable cross-check against the issuer's registered account list.
Install
npm install @facet-llc/origination-coinbase-cdp
# or
pnpm add @facet-llc/origination-coinbase-cdpEnvelope shape
The agent encodes the following JSON as base64 in the X-Agent-Attestation header:
{
"wallet": "0x71C7656EC7ab88b098defB751B7401B5f6d8976F",
"issued_at": "2026-05-24T18:00:00Z",
"expires_at": "2026-05-24T18:05:00Z",
"bind_to": "<idempotency-key>",
"scopes": ["payments:write"],
"signature": "0x..."
}The signature is taken over canonicalMessage(envelope) (see verifier.ts). A stable multi-line text format, not JSON canonicalization.
Usage
import { CoinbaseCdpOriginationVerifier } from "@facet-llc/origination-coinbase-cdp";
const verifier = new CoinbaseCdpOriginationVerifier({
maxEnvelopeAgeSeconds: 600,
});
const result = await verifier.verify({
raw_attestation: req.headers["x-agent-attestation"],
trace_id: traceId,
bind_to: idempotencyKey,
});
if (result.kind === "ok") {
// result.principal.aid === "cdp:0x71c7..."
}Optional: registered-account cross-check
Pass a configured CdpClient from @coinbase/cdp-sdk to additionally verify that the claimed wallet is a registered CDP-managed account, not just any EOA with a valid signature:
import { CdpClient } from "@coinbase/cdp-sdk";
const cdpClient = new CdpClient({ apiKeyId, apiKeySecret, walletSecret });
const verifier = new CoinbaseCdpOriginationVerifier({ cdpClient });When wired this way the verifier returns issuer_unknown for wallets the CDP project does not know about.
License
Apache-2.0. See LICENSE.
