Skip to main content

Node SDK: @oid4pay/oid4ac-merchant

The Node SDK is a verify-only merchant library. It verifies SD-JWT VC mandates, RFC 9421 signed offers, and signed catalogs. It never settles a charge: settlement is performed by the Authorization Server over HTTP, not through an SDK call.

The package is ESM-only (version 0.1.0, MIT). Node 18.18.0 or newer is required. It depends on jose at runtime for JWT and JWS verification. OpenTelemetry packages are optional peer dependencies; install them only if you want the bundled OTel observability adapter. TypeScript types are bundled.

Not published yet. The packages are not on npm, PyPI or the Go module proxy yet, so the install commands on this page do not work today. They show the names the packages will ship under.

Install

npm install @oid4pay/oid4ac-merchant
# or
pnpm add @oid4pay/oid4ac-merchant

API reference

verifyMandate(presentation, merchantAudience, options?)

Verifies a complete SD-JWT VC mandate presentation against the issuer JWKS. The first argument is the whole compact presentation string (issuer SD-JWT VC, then disclosures, then the Key-Binding JWT). The second argument is your merchant audience, which must appear in the mandate's aud. Returns a VerifiedMandate on success and throws MandateVerifyError on failure.

VerifyMandateOptions fields: jwks, jwksUrl, jwksCache, expectedIssuer, expectedVct, expectedOid4acVersion, expectedNonce, expectedOfferDigest, iatToleranceSeconds. Supply the issuer keys through jwks (a pre-fetched JWKS document) or through jwksUrl (the SDK fetches it over HTTPS, optionally cached with jwksCache).

VerifiedMandate fields: mandateId, agentClientId, principalId, amountMinor (number or null), currency, merchant, lineItems, cnfJkt, audienceResolved, offerDigest, issuedAt, expiresAt, verifiedAt, issuerClaims, disclosedClaims.

verifyOffer(offerBody, signatureHeaders, merchantJwks, options?)

Verifies an RFC 9421 signed offer body against a merchant JWKS. Throws OfferVerifyError on failure. Returns { keyid, alg, created, expires, bodyDigest, method, targetUri, authority } on success. VerifyOfferOptions fields: expectedTargetUri, now, createdSkewSeconds.

canonicalOfferDigest(offerBody)

Computes the canonical SHA-256 digest of an offer body and returns it as a base64url string. Use it to pin expectedOfferDigest when verifying a mandate against a known offer.

Catalog helpers

verifyCatalog verifies a signed catalog page; serveCatalog assembles a catalog page for serving; pickCheapestMatching and pickInStock are selection helpers over catalog items.

JWKS helpers

fetchJwks(url) fetches a JWKS document over HTTPS. JWKSCache caches fetched documents for repeated verifications and is accepted by verifyMandate through the jwksCache option.

Example: verify-only storefront route

A storefront route verifies the offer and the mandate, then returns the verified result. Settlement is not an SDK call: the Authorization Server performs the charge over HTTP after verification succeeds.

import {
  verifyOffer,
  verifyMandate,
  canonicalOfferDigest,
  fetchJwks,
} from "@oid4pay/oid4ac-merchant";

export async function POST(request) {
  const { offerBody, offerHeaders, presentation } = await request.json();

  const ownJwks = await fetchJwks("https://shop.example.com/.well-known/jwks.json");
  const issuerJwksUrl = "https://as.oid4pay.com/.well-known/jwks.json";

  const offer = await verifyOffer(offerBody, offerHeaders, ownJwks, {
    expectedTargetUri: `https://shop.example.com/products/${offerBody.sku}`,
  });

  const mandate = await verifyMandate(presentation, "https://shop.example.com", {
    jwksUrl: issuerJwksUrl,
    expectedOfferDigest: canonicalOfferDigest(offerBody),
  });

  // Verification passed. The order is authorised for amountMinor in currency.
  // Settlement is performed by the Authorization Server over HTTP; the SDK
  // does not charge.
  return Response.json({
    mandateId: mandate.mandateId,
    principalId: mandate.principalId,
    amountMinor: mandate.amountMinor,
    currency: mandate.currency,
    offerDigest: offer.bodyDigest,
  });
}

Algorithm whitelist

The Node SDK accepts ed25519 and ecdsa-p256-sha256 for signed offers; it refuses HMAC, alg=none, and every other RFC 9421 algorithm. Mandate issuer signatures are verified as EdDSA only, per the algorithm whitelist.

Error reference

ClassCodes
MandateVerifyErrorinvalid_mandate_format, audience_mismatch, jwks_fetch_failed
OfferVerifyErroroffer_signature_malformed
NetworkErrorRaised on network-layer failures during JWKS fetches.

Source

The package lives at sdks/node-oid4ac-merchant/ in the OID4Pay repo. Releases follow SemVer; breaking wire-version bumps move the major. Subscribe to the changelog for advance notice.