Skip to main content

Node SDK: @oid4pay/oid4ac-merchant

The Node SDK ships ESM + CJS bundles. Node 18.18+ is required (Web Crypto Ed25519). TypeScript types are bundled.

Install

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

API reference

verifyOffer(body, headers, jwks, options?)

Verifies an RFC 9421 signed offer body against a merchant JWKS. Throws OfferVerifyError with one of the offer_signature_expired, offer_keyid_unknown, offer_body_digest_mismatch, offer_target_uri_mismatch, offer_alg_rejected codes on failure. Returns { keyid, alg, created, expires, bodyDigest, method, targetUri, authority } on success.

verifyMandate(sdJwtVc, kbJwt, asJwks, options?)

Verifies an SD-JWT VC mandate + KB-JWT pair against the AS JWKS. Throws MandateVerifyError with one of the mandate_signature_invalid, mandate_kb_audience_mismatch, mandate_kb_nonce_mismatch, mandate_status_revoked codes on failure.

charge({ accessToken, dpopKey, offerDigest, idempotencyKey })

Settles a charge against the AS by presenting the JWT-AT and a fresh DPoP proof. The DPoP key MUST be the same key whose jkt appears in the JWT-AT's cnf claim. Returns { charge_id, mandate_id, stripe_payment_intent_id }.

Example: verify-and-charge in one storefront route

import { verifyOffer, charge } from "@oid4pay/oid4ac-merchant";

export async function POST(request) {
  const { offerBody, signedHeaders, accessToken, dpopProof } =
    await request.json();
  const merchantJwks = await fetchJwks(merchantId);

  const v = await verifyOffer(offerBody, signedHeaders, merchantJwks, {
    expectedTargetUri: `https://shop.example.com/oid4ac/offer/${offerBody.sku}`,
  });

  const result = await charge({
    accessToken,
    dpopProof,
    offerDigest: v.bodyDigest,
    idempotencyKey: crypto.randomUUID(),
  });

  return Response.json(result);
}

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. JWT-AT verification accepts EdDSA only, per the algorithm whitelist.