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.
Install
npm install @oid4pay/oid4ac-merchant
# or
pnpm add @oid4pay/oid4ac-merchantAPI 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
| Class | Codes |
|---|---|
MandateVerifyError | invalid_mandate_format, audience_mismatch, jwks_fetch_failed |
OfferVerifyError | offer_signature_malformed |
NetworkError | Raised 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.