x-agent-trust

April 14, 2026 · View on GitHub

Canonical ECDSA P-256 signing and verification for the x-agent-trust OpenAPI extension and the IETF draft draft-sharif-agent-payment-trust.

This is a reference implementation of the signing primitive only. It has zero dependencies, zero network calls, and exposes a tiny surface. Use it to produce or verify Agent-Signature headers in any language ecosystem that speaks ECDSA P-256 (which is all of them).

Standards status

The scheme in one paragraph

Every request carries an Agent-Signature header. The signature is ECDSA P-256 over a canonical string:

<METHOD> <path>\n<unix-ts>\n<sha256-hex(body)>

Header format:

Agent-Signature: keyid="<agent-id>",alg="ES256",ts="<unix>",sig="<base64>"

Servers verify the signature, check the timestamp is within a ±300-second clock-skew window, and reject otherwise. That's the whole primitive.

Install

npm install x-agent-trust

Quick start

Sign a request (client side)

const { generateKeyPair, signRequest } = require('x-agent-trust');

const { privateKey, publicKey } = generateKeyPair();

const body = JSON.stringify({ to: 'acme', amount: 2500, currency: 'USD' });
const { header } = signRequest({
  method: 'POST',
  path: '/api/payments',
  body,
  keyid: 'my-agent-001',
  privateKeyPem: privateKey
});

// Send:
//   POST /api/payments
//   Agent-Signature: keyid="my-agent-001",alg="ES256",ts="...",sig="..."
//   Content-Type: application/json
//   <body>

Verify a request (server side)

const { verifyRequest } = require('x-agent-trust');

const result = verifyRequest({
  headerVal: req.headers['agent-signature'],
  method: req.method,
  path: req.url,
  body: rawRequestBody,
  publicKeyPem: lookUpPublicKeyFor(parsedKeyId)
});

if (!result.valid) {
  return res.status(401).json({ error: result.error });
}
// result.keyid, result.alg, result.ts are trustworthy.

API

FunctionPurpose
generateKeyPair()Fresh P-256 keypair as PEM strings.
signRequest(opts)Produce Agent-Signature header + components.
verifyRequest(opts)Verify a signed request; enforces clock skew and algorithm.
buildSigningString(method, path, ts, body)Low-level canonical string builder.
parseSignatureHeader(header)Structured parse of the header into its fields.

Full type definitions: see src/index.js.

Running the tests

node test/sign.test.js

20+ tests covering keypair generation, canonical signing-string shape, round-trip verification, tamper detection (body/path/method), clock-skew enforcement, algorithm enforcement, malformed header rejection.

What this library is NOT

This repo contains only the signing primitive. It does not include:

  • Trust scoring (L0–L4 agent reputation)
  • Sanctions screening (OFAC / UK HMT)
  • AML checks
  • Payment rail adapters (x402, Stripe, AP2, ACP, MPP, Mastercard Agent Pay, Visa TAP, L402)
  • Audit / hash-chain storage
  • Key management / CA / revocation

Those are the job of the full AgentPass SDK — the commercial library that layers trust, compliance, and multi-rail payment orchestration on top of this signing primitive.

Use caseLibrary
I need to sign/verify an Agent-Signature headerThis repo (Apache 2.0)
I need trust scoring, sanctions, AML, and rail adaptersAgentPass SDK (BSL 1.1)
I need MCP transport boundary securityMCPS (BSL 1.1)

Why this exists

To make the x-agent-trust signing scheme easy to adopt in any language and any stack, with no commercial dependency. Fork it, port it, vendor it — that's the point. If the primitive is everywhere, the ecosystem converges on one way to prove an agent authored a request.

If you're building a production agent-payment flow you almost certainly want the commercial SDK — signRequest() is the easy bit; the hard bits are sanctions, trust, rails, audit, and compliance.

Licence

Apache License, Version 2.0. See LICENSE.

Maintainer

Raza Sharif, FBCS, CISSP, CSSLP. Published author, Breach 20/20. CyberSecAI Ltd — contact@agentsign.dev