@devlab.group/agent-commerce 1.5.0 → 1.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +73 -71
- package/dist/ap2.d.ts +20 -23
- package/dist/ap2.js +53 -75
- package/dist/ap2.js.map +1 -1
- package/dist/authorization-BpbWGGrf.d.ts +115 -0
- package/dist/chunk-AFI2CEZS.js +10 -0
- package/dist/chunk-AFI2CEZS.js.map +1 -0
- package/dist/{chunk-PBYN7EK2.js → chunk-CBJIT7QP.js} +10 -9
- package/dist/chunk-CBJIT7QP.js.map +1 -0
- package/dist/{chunk-NKNXVDHN.js → chunk-JKEKKXRJ.js} +45 -66
- package/dist/chunk-JKEKKXRJ.js.map +1 -0
- package/dist/{chunk-5GEWKNIH.js → chunk-N5KRK7YA.js} +63 -27
- package/dist/chunk-N5KRK7YA.js.map +1 -0
- package/dist/{chunk-6D2EZ5ME.js → chunk-V2V2E7HX.js} +2 -2
- package/dist/{chunk-6D2EZ5ME.js.map → chunk-V2V2E7HX.js.map} +1 -1
- package/dist/{chunk-US622BKF.js → chunk-VKDXMXHL.js} +5 -8
- package/dist/chunk-VKDXMXHL.js.map +1 -0
- package/dist/cli/index.js +501 -494
- package/dist/cli/index.js.map +1 -1
- package/dist/{constants-6mypC60h.d.ts → constants-Bkq04FRZ.d.ts} +1 -3
- package/dist/guardrails-71XwtXlT.d.ts +31 -0
- package/dist/index.d.ts +230 -265
- package/dist/index.js +1050 -607
- package/dist/index.js.map +1 -1
- package/dist/mcp.d.ts +6 -59
- package/dist/mcp.js +61 -53
- package/dist/mcp.js.map +1 -1
- package/dist/mpp.d.ts +4 -4
- package/dist/mpp.js +21 -19
- package/dist/mpp.js.map +1 -1
- package/dist/protocol-adapter-DTkrXTev.d.ts +238 -0
- package/dist/runtime-CiYbgGpi.d.ts +303 -0
- package/dist/{types-CJtwLu1c.d.ts → types-O6lg3Q5V.d.ts} +17 -23
- package/dist/x402.d.ts +43 -75
- package/dist/x402.js +10 -9
- package/dist/x402.js.map +1 -1
- package/package.json +7 -5
- package/dist/authorization-DA7mjy_O.d.ts +0 -123
- package/dist/chunk-5GEWKNIH.js.map +0 -1
- package/dist/chunk-NKNXVDHN.js.map +0 -1
- package/dist/chunk-PBYN7EK2.js.map +0 -1
- package/dist/chunk-US622BKF.js.map +0 -1
- package/dist/guardrails-Dmwi63KB.d.ts +0 -38
- package/dist/protocol-adapter-APRjs1E2.d.ts +0 -273
- package/dist/runtime-DC5XQ9Cc.d.ts +0 -351
package/dist/ap2.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { AP2_CHECKOUT_MANDATE_VCT, AP2_SIGNING_ALGORITHM, AP2_DIGEST_ALGORITHM, AP2_CHECKOUT_PROFILE, AP2_SPEC_VERSION, AP2_KEY_TYPE, AP2_JWK_CURVE, openSqliteDatabase } from './chunk-
|
|
2
|
-
export { AP2_CHECKOUT_MANDATE_VCT, AP2_CHECKOUT_PROFILE, AP2_DEFAULT_CLOCK_SKEW_SECONDS, AP2_MAX_CLOCK_SKEW_SECONDS, AP2_SIGNING_ALGORITHM, AP2_SPEC_VERSION } from './chunk-
|
|
3
|
-
import { systemClock, NOOP_LOGGER, CommerceError, PACKAGE_VERSION } from './chunk-
|
|
4
|
-
import { SignJWT, importPKCS8, importJWK, jwtVerify } from 'jose';
|
|
1
|
+
import { AP2_CHECKOUT_MANDATE_VCT, AP2_SIGNING_ALGORITHM, AP2_DIGEST_ALGORITHM, AP2_CHECKOUT_PROFILE, AP2_SPEC_VERSION, AP2_KEY_TYPE, AP2_JWK_CURVE, openSqliteDatabase } from './chunk-VKDXMXHL.js';
|
|
2
|
+
export { AP2_CHECKOUT_MANDATE_VCT, AP2_CHECKOUT_PROFILE, AP2_DEFAULT_CLOCK_SKEW_SECONDS, AP2_MAX_CLOCK_SKEW_SECONDS, AP2_SIGNING_ALGORITHM, AP2_SPEC_VERSION } from './chunk-VKDXMXHL.js';
|
|
3
|
+
import { systemClock, NOOP_LOGGER, CommerceError, isRecord, PACKAGE_VERSION } from './chunk-N5KRK7YA.js';
|
|
4
|
+
import { SignJWT, importPKCS8, importJWK, jwtVerify, decodeProtectedHeader, decodeJwt } from 'jose';
|
|
5
5
|
import canonicalize from 'canonicalize';
|
|
6
|
+
import { createHash } from 'crypto';
|
|
6
7
|
import { decodeSdJwt, splitSdJwt, getClaims } from '@sd-jwt/core';
|
|
7
8
|
|
|
8
9
|
// src/authorization/ap2/errors.ts
|
|
@@ -11,7 +12,6 @@ var AP2_REJECTION_REASONS = [
|
|
|
11
12
|
"untrusted_issuer",
|
|
12
13
|
"unknown_key",
|
|
13
14
|
"invalid_signature",
|
|
14
|
-
"unsupported_algorithm",
|
|
15
15
|
"invalid_claims",
|
|
16
16
|
"expired",
|
|
17
17
|
"wrong_audience",
|
|
@@ -24,7 +24,6 @@ var MESSAGES = {
|
|
|
24
24
|
untrusted_issuer: "The mandate was issued by a party this merchant does not trust.",
|
|
25
25
|
unknown_key: "The mandate names a signing key this merchant does not trust.",
|
|
26
26
|
invalid_signature: "The mandate signature did not verify.",
|
|
27
|
-
unsupported_algorithm: "The mandate uses a signature or digest algorithm that is not accepted.",
|
|
28
27
|
invalid_claims: "The mandate is missing required claims or they are malformed.",
|
|
29
28
|
expired: "The mandate is expired or not yet valid.",
|
|
30
29
|
wrong_audience: "The mandate is addressed to a different audience.",
|
|
@@ -63,6 +62,9 @@ function ap2Unavailable(detail, context = {}) {
|
|
|
63
62
|
}
|
|
64
63
|
);
|
|
65
64
|
}
|
|
65
|
+
function sha256(data) {
|
|
66
|
+
return createHash("sha256").update(data).digest();
|
|
67
|
+
}
|
|
66
68
|
|
|
67
69
|
// src/authorization/ap2/profile.ts
|
|
68
70
|
var REQUIRED_PROFILE_CLAIMS = [
|
|
@@ -73,13 +75,12 @@ var REQUIRED_PROFILE_CLAIMS = [
|
|
|
73
75
|
"currency",
|
|
74
76
|
"payment_method"
|
|
75
77
|
];
|
|
76
|
-
|
|
78
|
+
function computeInputHash(input) {
|
|
77
79
|
const canonical = canonicalize(input ?? {});
|
|
78
80
|
if (canonical === void 0) {
|
|
79
|
-
throw new
|
|
81
|
+
throw new CommerceError("INTERNAL_ERROR", "resource input is not canonicalizable JSON");
|
|
80
82
|
}
|
|
81
|
-
|
|
82
|
-
return Buffer.from(digest).toString("base64url");
|
|
83
|
+
return sha256(canonical).toString("base64url");
|
|
83
84
|
}
|
|
84
85
|
var EVM_ADDRESS = /^0x[0-9a-f]{40}$/i;
|
|
85
86
|
function sameCoordinate(declared, expected) {
|
|
@@ -90,12 +91,9 @@ function sameCoordinate(declared, expected) {
|
|
|
90
91
|
}
|
|
91
92
|
return declared === expected;
|
|
92
93
|
}
|
|
93
|
-
function asRecord(value) {
|
|
94
|
-
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
|
|
95
|
-
}
|
|
96
94
|
async function bindMandateToPurchase(mandate, context, errorContext) {
|
|
97
|
-
const profile =
|
|
98
|
-
if (profile
|
|
95
|
+
const profile = mandate.checkoutClaims["agent_commerce"];
|
|
96
|
+
if (!isRecord(profile)) throw ap2Rejected("purchase_mismatch", errorContext);
|
|
99
97
|
for (const claim of REQUIRED_PROFILE_CLAIMS) {
|
|
100
98
|
const value = profile[claim];
|
|
101
99
|
if (typeof value !== "string" || value.length === 0) {
|
|
@@ -103,7 +101,7 @@ async function bindMandateToPurchase(mandate, context, errorContext) {
|
|
|
103
101
|
}
|
|
104
102
|
}
|
|
105
103
|
const requirement = context.requirement;
|
|
106
|
-
const expectedInputHash =
|
|
104
|
+
const expectedInputHash = computeInputHash(context.input);
|
|
107
105
|
const mustMatch = [
|
|
108
106
|
["profile", AP2_CHECKOUT_PROFILE],
|
|
109
107
|
["resource_id", context.resourceId],
|
|
@@ -126,12 +124,6 @@ async function bindMandateToPurchase(mandate, context, errorContext) {
|
|
|
126
124
|
if (declared === void 0 && expected === void 0) continue;
|
|
127
125
|
if (!sameCoordinate(declared, expected)) throw ap2Rejected("purchase_mismatch", errorContext);
|
|
128
126
|
}
|
|
129
|
-
return {
|
|
130
|
-
resourceId: profile["resource_id"],
|
|
131
|
-
amount: profile["amount"],
|
|
132
|
-
currency: profile["currency"],
|
|
133
|
-
paymentMethod: profile["payment_method"]
|
|
134
|
-
};
|
|
135
127
|
}
|
|
136
128
|
|
|
137
129
|
// src/authorization/ap2/checkout-signer.ts
|
|
@@ -193,7 +185,7 @@ async function createCheckoutJwt(options) {
|
|
|
193
185
|
const agentCommerce = {
|
|
194
186
|
profile: AP2_CHECKOUT_PROFILE,
|
|
195
187
|
resource_id: resourceId,
|
|
196
|
-
input_hash:
|
|
188
|
+
input_hash: computeInputHash(options.input),
|
|
197
189
|
amount,
|
|
198
190
|
currency,
|
|
199
191
|
payment_method: paymentMethod,
|
|
@@ -218,8 +210,7 @@ var AP2_CAPABILITIES = [
|
|
|
218
210
|
"replay-defence"
|
|
219
211
|
];
|
|
220
212
|
var AP2_UNSUPPORTED = [
|
|
221
|
-
// Mandate kinds. Open mandates
|
|
222
|
-
// evaluates, so accepting one would tell a buyer their limits were checked.
|
|
213
|
+
// Mandate kinds. Open mandates are refused: see AP2_CHECKOUT_MANDATE_VCT
|
|
223
214
|
"autonomous mode",
|
|
224
215
|
"open checkout mandates (mandate.checkout.open.1)",
|
|
225
216
|
"intent mandates",
|
|
@@ -358,16 +349,6 @@ function migrate(db) {
|
|
|
358
349
|
});
|
|
359
350
|
apply();
|
|
360
351
|
}
|
|
361
|
-
function decodeSegment(jwt, index) {
|
|
362
|
-
const segment = jwt.split(".")[index];
|
|
363
|
-
if (segment === void 0) return void 0;
|
|
364
|
-
try {
|
|
365
|
-
const parsed = JSON.parse(Buffer.from(segment, "base64url").toString("utf8"));
|
|
366
|
-
return typeof parsed === "object" && parsed !== null && !Array.isArray(parsed) ? parsed : void 0;
|
|
367
|
-
} catch {
|
|
368
|
-
return void 0;
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
352
|
async function verifyCheckoutJwt(mandateClaims, deps, context) {
|
|
372
353
|
const compact = mandateClaims["checkout_jwt"];
|
|
373
354
|
const expectedHash = mandateClaims["checkout_hash"];
|
|
@@ -377,17 +358,16 @@ async function verifyCheckoutJwt(mandateClaims, deps, context) {
|
|
|
377
358
|
if (typeof expectedHash !== "string" || expectedHash.length === 0) {
|
|
378
359
|
throw ap2Rejected("invalid_claims", context);
|
|
379
360
|
}
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
361
|
+
requireMatchingHash(compact, expectedHash, context);
|
|
362
|
+
let header;
|
|
363
|
+
let unverifiedPayload;
|
|
364
|
+
try {
|
|
365
|
+
header = decodeProtectedHeader(compact);
|
|
366
|
+
unverifiedPayload = decodeJwt(compact);
|
|
367
|
+
} catch (cause) {
|
|
368
|
+
throw ap2Rejected("checkout_binding_failed", { ...context, cause });
|
|
385
369
|
}
|
|
386
|
-
const { issuer, key } = await deps.trust.resolve(
|
|
387
|
-
unverifiedPayload["iss"],
|
|
388
|
-
header["kid"],
|
|
389
|
-
context
|
|
390
|
-
);
|
|
370
|
+
const { issuer, key } = await deps.trust.resolve(unverifiedPayload.iss, header.kid, context);
|
|
391
371
|
const options = {
|
|
392
372
|
algorithms: [AP2_SIGNING_ALGORITHM],
|
|
393
373
|
issuer: issuer.issuer,
|
|
@@ -415,20 +395,15 @@ async function verifyCheckoutJwt(mandateClaims, deps, context) {
|
|
|
415
395
|
if (iat > nowSeconds + deps.clockSkewSeconds) throw ap2Rejected("expired", context);
|
|
416
396
|
return { issuer: issuer.issuer, jwtId: jti, claims };
|
|
417
397
|
}
|
|
418
|
-
|
|
419
|
-
const
|
|
420
|
-
const actual = Buffer.from(digest).toString("base64url");
|
|
398
|
+
function requireMatchingHash(compact, expected, context) {
|
|
399
|
+
const actual = sha256(compact).toString("base64url");
|
|
421
400
|
if (actual !== expected) throw ap2Rejected("checkout_binding_failed", context);
|
|
422
401
|
}
|
|
423
|
-
|
|
402
|
+
function hasher(data, algorithm) {
|
|
424
403
|
if (algorithm.toLowerCase() !== AP2_DIGEST_ALGORITHM) {
|
|
425
|
-
throw
|
|
404
|
+
throw ap2Rejected("malformed_presentation");
|
|
426
405
|
}
|
|
427
|
-
|
|
428
|
-
return new Uint8Array(await crypto.subtle.digest("SHA-256", bytes));
|
|
429
|
-
}
|
|
430
|
-
function asRecord2(value) {
|
|
431
|
-
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
|
|
406
|
+
return sha256(typeof data === "string" ? data : new Uint8Array(data));
|
|
432
407
|
}
|
|
433
408
|
async function verifyMandate(presentation, deps, context) {
|
|
434
409
|
let decoded;
|
|
@@ -442,26 +417,25 @@ async function verifyMandate(presentation, deps, context) {
|
|
|
442
417
|
if (decoded.kbJwt !== void 0) {
|
|
443
418
|
throw ap2Rejected("unsupported_mandate_type", context);
|
|
444
419
|
}
|
|
445
|
-
const rawPayload =
|
|
446
|
-
const header =
|
|
447
|
-
if (rawPayload
|
|
420
|
+
const rawPayload = decoded.jwt.payload;
|
|
421
|
+
const header = decoded.jwt.header;
|
|
422
|
+
if (!isRecord(rawPayload) || !isRecord(header)) {
|
|
448
423
|
throw ap2Rejected("malformed_presentation", context);
|
|
449
424
|
}
|
|
450
425
|
const { issuer, key } = await deps.trust.resolve(rawPayload["iss"], header["kid"], context);
|
|
451
426
|
const options = {
|
|
452
|
-
// Redundant
|
|
453
|
-
// a forged HMAC
|
|
454
|
-
//
|
|
427
|
+
// Redundant with one resolved EC key, which already refuses `alg: none` and
|
|
428
|
+
// a forged HMAC. It stops the header picking the algorithm if a key set is
|
|
429
|
+
// ever resolved instead.
|
|
455
430
|
algorithms: [AP2_SIGNING_ALGORITHM],
|
|
456
|
-
// Also redundant,
|
|
457
|
-
//
|
|
458
|
-
//
|
|
459
|
-
//
|
|
460
|
-
// presenter's claim, checked against what the operator configured.
|
|
431
|
+
// Also redundant, since the key was resolved *from* `iss`, and kept as a
|
|
432
|
+
// backstop for a resolver that matches on something else. `audience` is
|
|
433
|
+
// not redundant: `aud` is the presenter's claim, checked against the
|
|
434
|
+
// configured value.
|
|
461
435
|
issuer: issuer.issuer,
|
|
462
436
|
audience: issuer.audience,
|
|
463
437
|
clockTolerance: deps.clockSkewSeconds,
|
|
464
|
-
// Injected clock, not jose's `Date.now()`, so expiry
|
|
438
|
+
// Injected clock, not jose's `Date.now()`, so expiry is testable
|
|
465
439
|
currentDate: deps.clock.now()
|
|
466
440
|
};
|
|
467
441
|
let verifiedPayload;
|
|
@@ -544,9 +518,8 @@ function createTrustStore(issuers) {
|
|
|
544
518
|
}
|
|
545
519
|
|
|
546
520
|
// src/authorization/ap2/verifier.ts
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
return `sha256:${Buffer.from(digest).toString("base64url")}`;
|
|
521
|
+
function mandateReference(signedToken) {
|
|
522
|
+
return `sha256:${sha256(signedToken).toString("base64url")}`;
|
|
550
523
|
}
|
|
551
524
|
function createAp2MandateVerifier(options) {
|
|
552
525
|
const mandateTrust = createTrustStore(options.config.trust.mandateIssuers);
|
|
@@ -564,12 +537,11 @@ function createAp2MandateVerifier(options) {
|
|
|
564
537
|
context
|
|
565
538
|
);
|
|
566
539
|
return {
|
|
567
|
-
reference:
|
|
540
|
+
reference: mandateReference(mandate.signedToken),
|
|
568
541
|
mandateIssuer: mandate.issuer,
|
|
569
542
|
checkoutIssuer: checkout.issuer,
|
|
570
543
|
checkoutJwtId: checkout.jwtId,
|
|
571
|
-
checkoutClaims: checkout.claims
|
|
572
|
-
mandateClaims: mandate.claims
|
|
544
|
+
checkoutClaims: checkout.claims
|
|
573
545
|
};
|
|
574
546
|
},
|
|
575
547
|
trustedIssuers() {
|
|
@@ -616,6 +588,8 @@ function createAp2AuthorizationProvider(options) {
|
|
|
616
588
|
status: "verified",
|
|
617
589
|
method: "ap2",
|
|
618
590
|
reference: mandate.reference,
|
|
591
|
+
// The reservation handle is the reference itself, so the two can never
|
|
592
|
+
// name different mandates
|
|
619
593
|
reservationId: mandate.reference,
|
|
620
594
|
// Opaque identifiers an operator can reconcile with. Never a claim from
|
|
621
595
|
// the mandate: those carry the buyer's purchase and their personal data.
|
|
@@ -651,14 +625,18 @@ function createAp2AuthorizationProvider(options) {
|
|
|
651
625
|
},
|
|
652
626
|
async health() {
|
|
653
627
|
const startedAt = clock.monotonicMs();
|
|
654
|
-
const trusted = verifier.trustedIssuers();
|
|
655
628
|
const checkedAt = clock.nowIso();
|
|
656
|
-
|
|
629
|
+
let available = true;
|
|
657
630
|
try {
|
|
658
631
|
replay.stateOf("health-probe");
|
|
659
632
|
} catch {
|
|
633
|
+
available = false;
|
|
634
|
+
}
|
|
635
|
+
const durationMs = Math.round(clock.monotonicMs() - startedAt);
|
|
636
|
+
if (!available) {
|
|
660
637
|
return { status: "fail", checkedAt, durationMs, detail: "replay-store-unavailable" };
|
|
661
638
|
}
|
|
639
|
+
const trusted = verifier.trustedIssuers();
|
|
662
640
|
return {
|
|
663
641
|
status: "pass",
|
|
664
642
|
checkedAt,
|
package/dist/ap2.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/authorization/ap2/errors.ts","../src/authorization/ap2/profile.ts","../src/authorization/ap2/checkout-signer.ts","../src/authorization/ap2/descriptor.ts","../src/authorization/ap2/replay-store.ts","../src/authorization/ap2/checkout-jwt.ts","../src/authorization/ap2/sd-jwt.ts","../src/authorization/ap2/trust.ts","../src/authorization/ap2/verifier.ts","../src/authorization/ap2/provider.ts"],"names":["asRecord","jwtVerify"],"mappings":"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","file":"ap2.js","sourcesContent":["/**\n * Every failure the AP2 verifier can report.\n *\n * `CommerceError.message` reaches the client, and a mandate carries the\n * buyer's purchase and often personal data, so messages are fixed phrases from\n * the list below. The machine-readable code goes in `details.reason` and the\n * original exception on `cause`, which is never serialised.\n *\n * Three codes: AUTHORIZATION_INVALID when the buyer's mandate is bad,\n * AUTHORIZATION_REPLAYED when it is good but spent, and\n * AUTHORIZATION_PROVIDER_UNAVAILABLE when our verifier never reached a\n * verdict. Blaming the buyer for our outage refuses a good mandate.\n */\nimport { CommerceError } from '../../core/index.js';\n\n/**\n * Coarse on purpose: a client learns roughly where its mandate was refused,\n * not which check failed. Finer detail is an oracle for probing trust policy.\n */\nexport const AP2_REJECTION_REASONS = [\n 'malformed_presentation',\n 'untrusted_issuer',\n 'unknown_key',\n 'invalid_signature',\n 'unsupported_algorithm',\n 'invalid_claims',\n 'expired',\n 'wrong_audience',\n 'unsupported_mandate_type',\n 'checkout_binding_failed',\n 'purchase_mismatch',\n] as const;\n\nexport type Ap2RejectionReason = (typeof AP2_REJECTION_REASONS)[number];\n\nconst MESSAGES: Readonly<Record<Ap2RejectionReason, string>> = {\n malformed_presentation: 'The authorization is not a well-formed SD-JWT presentation.',\n untrusted_issuer: 'The mandate was issued by a party this merchant does not trust.',\n unknown_key: 'The mandate names a signing key this merchant does not trust.',\n invalid_signature: 'The mandate signature did not verify.',\n unsupported_algorithm: 'The mandate uses a signature or digest algorithm that is not accepted.',\n invalid_claims: 'The mandate is missing required claims or they are malformed.',\n expired: 'The mandate is expired or not yet valid.',\n wrong_audience: 'The mandate is addressed to a different audience.',\n unsupported_mandate_type: 'The mandate is not a closed Direct Checkout Mandate.',\n checkout_binding_failed: 'The merchant checkout document bound to the mandate did not verify.',\n purchase_mismatch: 'The mandate does not authorize this purchase.',\n};\n\nexport interface Ap2ErrorContext {\n readonly requestId?: string;\n readonly resourceId?: string;\n readonly cause?: unknown;\n}\n\n/** The buyer's mandate is bad. Fail closed */\nexport function ap2Rejected(\n reason: Ap2RejectionReason,\n context: Ap2ErrorContext = {},\n): CommerceError {\n return new CommerceError('AUTHORIZATION_INVALID', MESSAGES[reason], {\n details: { method: 'ap2', reason },\n ...(context.requestId !== undefined ? { requestId: context.requestId } : {}),\n ...(context.resourceId !== undefined ? { resourceId: context.resourceId } : {}),\n ...(context.cause !== undefined ? { cause: context.cause } : {}),\n });\n}\n\n/**\n * The mandate verified but has already been presented. A separate code from\n * a bad mandate: nothing is wrong with this proof except that it is spent\n */\nexport function ap2Replayed(state: string, context: Ap2ErrorContext = {}): CommerceError {\n return new CommerceError(\n 'AUTHORIZATION_REPLAYED',\n 'This mandate has already been presented and cannot authorize another purchase.',\n {\n details: { method: 'ap2', reason: 'replayed', state },\n ...(context.requestId !== undefined ? { requestId: context.requestId } : {}),\n ...(context.resourceId !== undefined ? { resourceId: context.resourceId } : {}),\n },\n );\n}\n\n/**\n * The check never ran (a configured key that will not import, say). Retryable,\n * and never recorded against the payer: the mandate may be perfectly good.\n */\nexport function ap2Unavailable(detail: string, context: Ap2ErrorContext = {}): CommerceError {\n return new CommerceError(\n 'AUTHORIZATION_PROVIDER_UNAVAILABLE',\n 'Authorization could not be verified right now. This is a merchant-side fault, not a problem with the presented mandate.',\n {\n details: { method: 'ap2', reason: 'verifier_unavailable', detail },\n ...(context.requestId !== undefined ? { requestId: context.requestId } : {}),\n ...(context.resourceId !== undefined ? { resourceId: context.resourceId } : {}),\n ...(context.cause !== undefined ? { cause: context.cause } : {}),\n },\n );\n}\n","/**\n * Binds a verified mandate to the purchase in front of us.\n *\n * A perfect mandate authorises exactly one purchase; without this comparison a\n * mandate approved for a $0.01 report would settle a $500 one.\n *\n * Everything is compared against the ALREADY RESOLVED request. Nothing is\n * taken from the mandate and used to shape the purchase, which would invert\n * the control.\n */\nimport canonicalize from 'canonicalize';\nimport type { AuthorizationVerificationContext } from '../../core/index.js';\nimport { AP2_CHECKOUT_PROFILE } from './constants.js';\nimport { type Ap2ErrorContext, ap2Rejected } from './errors.js';\nimport type { VerifiedCheckoutMandate } from './types.js';\n\n/**\n * All required. Absent is a mismatch, never a skipped check: a mandate that\n * will not say which resource or how much authorises nothing in particular.\n */\nconst REQUIRED_PROFILE_CLAIMS = [\n 'profile',\n 'resource_id',\n 'input_hash',\n 'amount',\n 'currency',\n 'payment_method',\n] as const;\n\n/**\n * RFC 8785 (JCS) digest of the validated resource input.\n *\n * Binds a mandate to the exact request, not just to a resource and a price:\n * without it, one mandate for `translate` would authorise any translation.\n *\n * `canonicalize` rather than a sorted-key `JSON.stringify`, which differs\n * exactly where it matters. The merchant's signer computes this same digest,\n * probably in another language, and the two agree only if both follow RFC\n * 8785's number formatting and UTF-16 key ordering.\n *\n * The caller passes what the backend will receive: validated, reserved fields\n * stripped, no request id or transport metadata (the buyer could not have\n * known those when they approved).\n */\nexport async function computeInputHash(input: unknown): Promise<string> {\n const canonical = canonicalize(input ?? {});\n // undefined means JSON cannot represent it. Input has already passed schema\n // validation, so this is something exotic getting past it, not a buyer error.\n if (canonical === undefined) {\n throw new TypeError('resource input is not canonicalizable JSON');\n }\n const digest = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(canonical));\n return Buffer.from(digest).toString('base64url');\n}\n\n/** What the mandate turned out to authorise, once it matched */\nexport interface BoundPurchase {\n readonly resourceId: string;\n readonly amount: string;\n readonly currency: string;\n readonly paymentMethod: string;\n}\n\nconst EVM_ADDRESS = /^0x[0-9a-f]{40}$/i;\n\n// EIP-55 encodes an address checksum through letter casing, so lowercase and\n// checksummed forms identify the same account. Other values compare exactly.\nfunction sameCoordinate(declared: unknown, expected: string | undefined): boolean {\n if (typeof declared === 'string' && expected !== undefined) {\n if (EVM_ADDRESS.test(declared) && EVM_ADDRESS.test(expected)) {\n return declared.toLowerCase() === expected.toLowerCase();\n }\n }\n return declared === expected;\n}\n\nfunction asRecord(value: unknown): Record<string, unknown> | undefined {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : undefined;\n}\n\n/**\n * Throws on the first mismatch with one coarse reason. Which field disagreed\n * is not reported: a caller able to ask about one field at a time can read a\n * mandate's contents out of the gateway by elimination.\n */\nexport async function bindMandateToPurchase(\n mandate: VerifiedCheckoutMandate,\n context: AuthorizationVerificationContext,\n errorContext: Ap2ErrorContext,\n): Promise<BoundPurchase> {\n const profile = asRecord(mandate.checkoutClaims['agent_commerce']);\n if (profile === undefined) throw ap2Rejected('purchase_mismatch', errorContext);\n\n for (const claim of REQUIRED_PROFILE_CLAIMS) {\n const value = profile[claim];\n if (typeof value !== 'string' || value.length === 0) {\n throw ap2Rejected('purchase_mismatch', errorContext);\n }\n }\n\n const requirement = context.requirement;\n const expectedInputHash = await computeInputHash(context.input);\n\n const mustMatch: readonly (readonly [string, unknown])[] = [\n ['profile', AP2_CHECKOUT_PROFILE],\n ['resource_id', context.resourceId],\n ['input_hash', expectedInputHash],\n // Decimal strings on both sides. Comparing numerically would make \"0.10\"\n // and \"0.1\" equal, and a mandate says what it says.\n ['amount', requirement.amount],\n ['currency', requirement.currency],\n ['payment_method', requirement.provider],\n ];\n\n for (const [claim, expected] of mustMatch) {\n if (profile[claim] !== expected) throw ap2Rejected('purchase_mismatch', errorContext);\n }\n\n // Checked whenever EITHER side names one, which is the fail-closed reading.\n // A mandate silent about the chain must not unlock a mainnet settlement, and\n // one naming a chain the requirement lacks was approved for another rail.\n for (const [claim, expected] of [\n ['destination', requirement.destination],\n ['network', requirement.network],\n ['asset', requirement.asset],\n ] as const) {\n const declared = profile[claim];\n if (declared === undefined && expected === undefined) continue;\n if (!sameCoordinate(declared, expected)) throw ap2Rejected('purchase_mismatch', errorContext);\n }\n\n return {\n resourceId: profile['resource_id'] as string,\n amount: profile['amount'] as string,\n currency: profile['currency'] as string,\n paymentMethod: profile['payment_method'] as string,\n };\n}\n","/**\n * Merchant-side helper: mint the checkout JWT a Checkout Mandate binds.\n *\n * The gateway only verifies. This is what a merchant runs in their own\n * process, with their own key, to produce the document the buyer approves. It\n * never calls the gateway and the gateway never calls it - the mirror of\n * `createPaymentProof`, which a buyer runs to produce a payment proof.\n *\n * It exists for `input_hash`, an RFC 8785 digest. A signer reaching for a\n * sorted-key `JSON.stringify` agrees on most inputs and disagrees on floats\n * and non-ASCII keys, and the mandate is then refused with a reason that does\n * not say which field disagreed.\n */\nimport { importPKCS8, type JWK, SignJWT } from 'jose';\nimport {\n AP2_CHECKOUT_PROFILE,\n AP2_JWK_CURVE,\n AP2_KEY_TYPE,\n AP2_SIGNING_ALGORITHM,\n} from './constants.js';\nimport { computeInputHash } from './profile.js';\n\n/**\n * A private ES256 key: either a private JWK (the pair of the public one in the\n * gateway's `checkoutIssuers`) or a PKCS#8 PEM, as `openssl` emits it.\n */\nexport type Ap2SigningKey = Readonly<Record<string, unknown>> | string;\n\nexport interface CreateCheckoutJwtOptions {\n readonly privateKey: Ap2SigningKey;\n /** Must match a `kid` configured under the gateway's `checkoutIssuers` */\n readonly kid: string;\n /** Must match that issuer's configured `issuer` */\n readonly issuer: string;\n /** Must match that issuer's configured `audience` */\n readonly audience: string;\n\n readonly resourceId: string;\n /**\n * The resource input this purchase is for, exactly as the buyer will send\n * it: no reserved fields, no request id, no transport metadata.\n */\n readonly input: unknown;\n\n /**\n * Decimal string, never a number, and compared as a string: `0.10` and `0.1`\n * are different mandates. Take it from your own catalogue rather than from\n * whatever the agent asked for.\n */\n readonly amount: string;\n readonly currency: string;\n /** The rail that will settle, e.g. `x402` */\n readonly paymentMethod: string;\n\n /**\n * Settlement coordinates. Required whenever the gateway's requirement names\n * them, which under x402 is always. A mandate silent about the chain will\n * not unlock a settlement on one.\n */\n readonly destination?: string;\n readonly network?: string;\n readonly asset?: string;\n\n /** Defaults to a random UUID. Recorded on the receipt and used for replay defence */\n readonly jwtId?: string;\n /** Defaults to 900: a human approval sits inside this window */\n readonly expiresInSeconds?: number;\n /** Injectable so a test need not move the wall clock */\n readonly now?: Date;\n}\n\nconst DEFAULT_EXPIRES_IN_SECONDS = 900;\n\nfunction requireText(value: unknown, field: string): string {\n if (typeof value !== 'string' || value.length === 0) {\n throw new TypeError(\n `createCheckoutJwt: ${field} must be a non-empty string, received ${describe(value)}`,\n );\n }\n return value;\n}\n\nfunction describe(value: unknown): string {\n return value === null ? 'null' : typeof value;\n}\n\n/**\n * Every rejection here is a mistake that would otherwise surface as an opaque\n * verification failure much later: the public half of the pair, the wrong key\n * type, or a PEM that is not PKCS#8.\n */\nasync function resolveKey(\n key: Ap2SigningKey,\n): Promise<JWK | Awaited<ReturnType<typeof importPKCS8>>> {\n if (typeof key === 'string') {\n if (!key.includes('BEGIN PRIVATE KEY')) {\n throw new TypeError(\n 'createCheckoutJwt: a string privateKey must be a PKCS#8 PEM beginning \"-----BEGIN PRIVATE KEY-----\"',\n );\n }\n return importPKCS8(key, AP2_SIGNING_ALGORITHM);\n }\n if (typeof key !== 'object' || key === null) {\n throw new TypeError('createCheckoutJwt: privateKey must be a private JWK or a PKCS#8 PEM');\n }\n if (key['d'] === undefined) {\n throw new TypeError(\n 'createCheckoutJwt: privateKey is a public JWK (no \"d\"). Use the private half of the pair whose public key is configured under checkoutIssuers',\n );\n }\n if (key['kty'] !== AP2_KEY_TYPE || key['crv'] !== AP2_JWK_CURVE) {\n throw new TypeError(\n `createCheckoutJwt: privateKey must be ${AP2_KEY_TYPE}/${AP2_JWK_CURVE}, the pair ${AP2_SIGNING_ALGORITHM} implies`,\n );\n }\n return key as JWK;\n}\n\n/**\n * Returns the compact JWT to hand to the agent, which wraps it in the Checkout\n * Mandate the buyer signs.\n */\nexport async function createCheckoutJwt(options: CreateCheckoutJwtOptions): Promise<string> {\n const kid = requireText(options.kid, 'kid');\n const issuer = requireText(options.issuer, 'issuer');\n const audience = requireText(options.audience, 'audience');\n const resourceId = requireText(options.resourceId, 'resourceId');\n const currency = requireText(options.currency, 'currency');\n const paymentMethod = requireText(options.paymentMethod, 'paymentMethod');\n\n if (typeof options.amount === 'number') {\n throw new TypeError(\n 'createCheckoutJwt: amount must be a decimal string, not a number. It is compared as a string, so 0.1 and \"0.10\" are different mandates',\n );\n }\n const amount = requireText(options.amount, 'amount');\n\n const key = await resolveKey(options.privateKey);\n const issuedAt = Math.floor((options.now ?? new Date()).getTime() / 1000);\n const expiresIn = options.expiresInSeconds ?? DEFAULT_EXPIRES_IN_SECONDS;\n if (!Number.isInteger(expiresIn) || expiresIn <= 0) {\n throw new TypeError('createCheckoutJwt: expiresInSeconds must be a positive whole number');\n }\n\n const agentCommerce: Record<string, string> = {\n profile: AP2_CHECKOUT_PROFILE,\n resource_id: resourceId,\n input_hash: await computeInputHash(options.input),\n amount,\n currency,\n payment_method: paymentMethod,\n ...(options.destination !== undefined ? { destination: options.destination } : {}),\n ...(options.network !== undefined ? { network: options.network } : {}),\n ...(options.asset !== undefined ? { asset: options.asset } : {}),\n };\n\n return new SignJWT({ agent_commerce: agentCommerce })\n .setProtectedHeader({ alg: AP2_SIGNING_ALGORITHM, kid, typ: 'JWT' })\n .setIssuer(issuer)\n .setAudience(audience)\n .setIssuedAt(issuedAt)\n .setExpirationTime(issuedAt + expiresIn)\n .setJti(options.jwtId ?? crypto.randomUUID())\n .sign(key);\n}\n","/**\n * Adapter self-description.\n *\n * Imports nothing but core types and the pins, so `doctor` can report AP2\n * without pulling `jose` or `@sd-jwt/core` into the CLI bundle.\n */\nimport type { AdapterDescriptor } from '../../core/index.js';\nimport {\n AP2_CHECKOUT_MANDATE_VCT,\n AP2_CHECKOUT_PROFILE,\n AP2_DIGEST_ALGORITHM,\n AP2_SIGNING_ALGORITHM,\n AP2_SPEC_VERSION,\n} from './constants.js';\n\n/** What this provider actually verifies */\nexport const AP2_CAPABILITIES: readonly string[] = [\n 'direct-mode',\n AP2_CHECKOUT_MANDATE_VCT,\n 'sd-jwt-presentation',\n AP2_SIGNING_ALGORITHM,\n AP2_DIGEST_ALGORITHM,\n 'static-inline-trust',\n 'merchant-checkout-jwt-binding',\n AP2_CHECKOUT_PROFILE,\n 'purchase-binding',\n 'replay-defence',\n];\n\n/**\n * Everything an AP2 client may reasonably expect and will not get here.\n * Complete on purpose: a short list reads as \"mostly compatible\", which is the\n * blanket claim alpha honesty forbids.\n */\nexport const AP2_UNSUPPORTED: readonly string[] = [\n // Mandate kinds. Open mandates carry spending constraints nothing here\n // evaluates, so accepting one would tell a buyer their limits were checked.\n 'autonomous mode',\n 'open checkout mandates (mandate.checkout.open.1)',\n 'intent mandates',\n 'cart mandates',\n 'spending constraint evaluation',\n 'cnf-bound agent keys',\n // Key handling. Every key is written into config by an operator\n 'JWKS and any key discovery by URL (jku, x5u)',\n 'issuer metadata fetching',\n 'key rotation without a config change',\n // Algorithms\n 'signature algorithms other than ES256',\n 'digest algorithms other than sha-256',\n // Roles this gateway does not play\n 'mandate issuance',\n 'AP2 over the ACP checkout adapter',\n];\n\nexport function buildAp2Descriptor(implementationVersion: string): AdapterDescriptor {\n return {\n name: 'ap2',\n kind: 'authorization',\n implementationVersion,\n supportedSpec: `ap2/v${AP2_SPEC_VERSION} mode=direct`,\n capabilities: AP2_CAPABILITIES,\n status: 'experimental',\n unsupported: AP2_UNSUPPORTED,\n };\n}\n","/**\n * Durable record of which mandates have been spent.\n *\n * Its own table in its own file: an x402 payment replay key expires with its\n * on-chain authorisation, while a consumed mandate must stay consumed for as\n * long as the merchant can be asked what they delivered. Hence no retention\n * sweep here, unlike the ACP idempotency store next door - deleting a\n * `consumed` row makes that mandate spendable again. If the table ever needs\n * bounding, archive `released` rows and leave the rest.\n *\n * Settlement and a local commit are not one transaction. If the process dies\n * between them the row stays `reserved` and that mandate is refused from then\n * on: a refused retry costs a round trip, the other direction costs a second\n * payment.\n */\nimport type { Database } from 'better-sqlite3';\nimport { type Logger, NOOP_LOGGER } from '../../core/index.js';\nimport { openSqliteDatabase } from '../../storage/sqlite.js';\n\n/**\n * `released` is \"nothing happened\" and the only state a mandate can be\n * presented from again. `uncertain` is a settlement whose outcome we never\n * learned: not reusable, but findable by an operator reconciling by hand.\n */\nexport type Ap2AuthorizationState = 'reserved' | 'consumed' | 'released' | 'uncertain';\n\n/**\n * A digest and a few identifiers: everything replay defence needs, and nothing\n * a leaked database would hand an attacker\n */\nexport interface Ap2ReservationRequest {\n /**\n * Digest of the ISSUER-SIGNED TOKEN, not of the presentation. Selective\n * disclosure gives one mandate many presentation strings, so keying on the\n * presentation would let it be spent once per disclosed subset.\n */\n readonly reference: string;\n /** `jti` of the merchant checkout JWT the mandate binds */\n readonly checkoutJti: string;\n readonly mandateIssuer: string;\n readonly checkoutIssuer: string;\n readonly resourceId: string;\n readonly requestId: string;\n}\n\nexport type Ap2ReservationResult =\n | { readonly kind: 'reserved' }\n /** Already reserved, consumed, or of uncertain outcome. Never re-spendable */\n | { readonly kind: 'replayed'; readonly state: Ap2AuthorizationState };\n\nexport interface Ap2ReplayStore {\n /** Atomically claim a mandate, or report that something already holds it */\n reserve(request: Ap2ReservationRequest): Ap2ReservationResult;\n /** Settlement succeeded: spend it permanently */\n consume(reference: string): void;\n /** Nothing happened: hand it back so a corrected retry can use it */\n release(reference: string): void;\n /** Settlement outcome unknown. Not reusable, and flagged for a human */\n markUncertain(reference: string): void;\n /** Current state, for tests and diagnostics */\n stateOf(reference: string): Ap2AuthorizationState | undefined;\n close(): void;\n}\n\nexport interface Ap2ReplayStoreOptions {\n /** File path, or ':memory:' for tests */\n readonly path: string;\n readonly logger?: Logger;\n /** Injectable so tests need not move the wall clock */\n readonly now?: () => number;\n}\n\ninterface StateRow {\n state: string;\n}\n\nexport function createAp2ReplayStore(options: Ap2ReplayStoreOptions): Ap2ReplayStore {\n const logger = options.logger ?? NOOP_LOGGER;\n const now = options.now ?? (() => Date.now());\n\n const db: Database = openSqliteDatabase({\n path: options.path,\n label: 'AP2 authorization database',\n logger,\n });\n migrate(db);\n\n const selectByReference = db.prepare<[string], StateRow>(\n 'SELECT state FROM ap2_authorizations WHERE reference = ?',\n );\n // Two mandates can bind one checkout document, giving two references, so\n // the reference alone would not catch the second one\n const selectLiveByJti = db.prepare<[string, string], StateRow>(\n `SELECT state FROM ap2_authorizations\n WHERE checkout_jti = ? AND reference != ? AND state != 'released'`,\n );\n const insert = db.prepare(\n `INSERT INTO ap2_authorizations\n (reference, checkout_jti, mandate_issuer, checkout_issuer, resource_id, request_id,\n state, created_at, updated_at)\n VALUES (@reference, @checkout_jti, @mandate_issuer, @checkout_issuer, @resource_id,\n @request_id, 'reserved', @at, @at)`,\n );\n const reReserve = db.prepare(\n `UPDATE ap2_authorizations\n SET state = 'reserved', request_id = @request_id, updated_at = @at\n WHERE reference = @reference AND state = 'released'`,\n );\n // Guarded on `reserved`: releasing a `consumed` row would hand back a\n // mandate whose money has already moved\n const transition = db.prepare(\n `UPDATE ap2_authorizations SET state = @state, updated_at = @at\n WHERE reference = @reference AND state = 'reserved'`,\n );\n\n const reserveTx = db.transaction((request: Ap2ReservationRequest): Ap2ReservationResult => {\n const at = new Date(now()).toISOString();\n\n const existing = selectByReference.get(request.reference);\n if (existing !== undefined && existing.state !== 'released') {\n return { kind: 'replayed', state: existing.state as Ap2AuthorizationState };\n }\n\n // Checked for a released reference too: another mandate may have reserved\n // or spent the same checkout while this one was released\n const sameCheckout = selectLiveByJti.get(request.checkoutJti, request.reference);\n if (sameCheckout !== undefined) {\n return { kind: 'replayed', state: sameCheckout.state as Ap2AuthorizationState };\n }\n\n if (existing !== undefined) {\n reReserve.run({ reference: request.reference, request_id: request.requestId, at });\n return { kind: 'reserved' };\n }\n\n insert.run({\n reference: request.reference,\n checkout_jti: request.checkoutJti,\n mandate_issuer: request.mandateIssuer,\n checkout_issuer: request.checkoutIssuer,\n resource_id: request.resourceId,\n request_id: request.requestId,\n at,\n });\n return { kind: 'reserved' };\n });\n\n const move = (reference: string, state: Ap2AuthorizationState): void => {\n transition.run({ reference, state, at: new Date(now()).toISOString() });\n };\n\n let closed = false;\n return {\n reserve(request) {\n return reserveTx(request);\n },\n consume(reference) {\n move(reference, 'consumed');\n },\n release(reference) {\n move(reference, 'released');\n },\n markUncertain(reference) {\n move(reference, 'uncertain');\n },\n stateOf(reference) {\n return selectByReference.get(reference)?.state as Ap2AuthorizationState | undefined;\n },\n close() {\n if (closed) return;\n closed = true;\n db.close();\n },\n };\n}\n\n// `PRAGMA user_version`, so reopening an existing file is a no-op check\nfunction migrate(db: Database): void {\n const current = db.pragma('user_version', { simple: true }) as number;\n if (current >= 1) return;\n const apply = db.transaction(() => {\n db.exec(`\n CREATE TABLE IF NOT EXISTS ap2_authorizations (\n reference TEXT PRIMARY KEY,\n checkout_jti TEXT NOT NULL,\n mandate_issuer TEXT NOT NULL,\n checkout_issuer TEXT NOT NULL,\n resource_id TEXT NOT NULL,\n request_id TEXT NOT NULL,\n state TEXT NOT NULL\n CHECK (state IN ('reserved', 'consumed', 'released', 'uncertain')),\n created_at TEXT NOT NULL,\n updated_at TEXT NOT NULL\n );\n CREATE INDEX IF NOT EXISTS idx_ap2_authorizations_checkout_jti\n ON ap2_authorizations(checkout_jti);\n `);\n db.pragma('user_version = 1');\n });\n apply();\n}\n","/**\n * Stage two: the merchant checkout JWT the mandate binds.\n *\n * Two things have to hold. The hash proves the buyer approved *this* document;\n * the signature proves the merchant issued it. Hash alone accepts a document\n * the buyer wrote themselves; signature alone accepts a genuine merchant\n * document this mandate never covered.\n */\nimport { type JWTVerifyOptions, jwtVerify } from 'jose';\nimport type { Clock } from '../../core/index.js';\nimport { AP2_SIGNING_ALGORITHM } from './constants.js';\nimport { type Ap2ErrorContext, ap2Rejected } from './errors.js';\nimport type { TrustStore } from './trust.js';\n\nexport interface VerifiedCheckoutJwt {\n readonly issuer: string;\n readonly jwtId: string;\n readonly claims: Readonly<Record<string, unknown>>;\n}\n\nfunction decodeSegment(jwt: string, index: 0 | 1): Record<string, unknown> | undefined {\n const segment = jwt.split('.')[index];\n if (segment === undefined) return undefined;\n try {\n const parsed: unknown = JSON.parse(Buffer.from(segment, 'base64url').toString('utf8'));\n return typeof parsed === 'object' && parsed !== null && !Array.isArray(parsed)\n ? (parsed as Record<string, unknown>)\n : undefined;\n } catch {\n return undefined;\n }\n}\n\n/**\n * `mandateClaims` must come from an already-verified mandate: `checkout_hash`\n * is worth nothing unless the issuer signed it\n */\nexport async function verifyCheckoutJwt(\n mandateClaims: Readonly<Record<string, unknown>>,\n deps: { readonly trust: TrustStore; readonly clock: Clock; readonly clockSkewSeconds: number },\n context: Ap2ErrorContext,\n): Promise<VerifiedCheckoutJwt> {\n const compact = mandateClaims['checkout_jwt'];\n const expectedHash = mandateClaims['checkout_hash'];\n if (typeof compact !== 'string' || compact.length === 0) {\n throw ap2Rejected('invalid_claims', context);\n }\n if (typeof expectedHash !== 'string' || expectedHash.length === 0) {\n throw ap2Rejected('invalid_claims', context);\n }\n\n await requireMatchingHash(compact, expectedHash, context);\n\n const header = decodeSegment(compact, 0);\n const unverifiedPayload = decodeSegment(compact, 1);\n if (header === undefined || unverifiedPayload === undefined) {\n throw ap2Rejected('checkout_binding_failed', context);\n }\n\n const { issuer, key } = await deps.trust.resolve(\n unverifiedPayload['iss'],\n header['kid'],\n context,\n );\n\n const options: JWTVerifyOptions = {\n algorithms: [AP2_SIGNING_ALGORITHM],\n issuer: issuer.issuer,\n audience: issuer.audience,\n clockTolerance: deps.clockSkewSeconds,\n currentDate: deps.clock.now(),\n };\n\n let claims: Record<string, unknown>;\n try {\n const result = await jwtVerify(compact, key, options);\n claims = result.payload as Record<string, unknown>;\n } catch (cause) {\n throw ap2Rejected('checkout_binding_failed', { ...context, cause });\n }\n\n const exp = claims['exp'];\n const iat = claims['iat'];\n const jti = claims['jti'];\n // jose validates a time claim only when present, so requiring them is ours\n if (typeof exp !== 'number' || typeof iat !== 'number') {\n throw ap2Rejected('invalid_claims', context);\n }\n // `jti` is what replay defence and the receipt record, so it is required\n if (typeof jti !== 'string' || jti.length === 0) {\n throw ap2Rejected('invalid_claims', context);\n }\n const nowSeconds = Math.floor(deps.clock.now().getTime() / 1000);\n if (iat > nowSeconds + deps.clockSkewSeconds) throw ap2Rejected('expired', context);\n\n return { issuer: issuer.issuer, jwtId: jti, claims };\n}\n\n/**\n * Hashed as the bytes that arrived, never re-encoded from parsed claims: a\n * re-serialised payload has a different digest, and normalising first would\n * hash a document other than the one being verified\n */\nasync function requireMatchingHash(\n compact: string,\n expected: string,\n context: Ap2ErrorContext,\n): Promise<void> {\n // sha-256 only: `_sd_alg` was already pinned to it upstream\n const digest = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(compact));\n const actual = Buffer.from(digest).toString('base64url');\n // Plain comparison: both sides are public to anyone holding the\n // presentation, so there is no secret for timing to leak\n if (actual !== expected) throw ap2Rejected('checkout_binding_failed', context);\n}\n","/**\n * Stage one: parse the presentation, verify the issuer's signature, resolve\n * the disclosures.\n *\n * Disclosure mechanics come from `@sd-jwt/core`, which refuses the three\n * attacks that live in that algorithm: an appended disclosure nothing\n * references, the same disclosure twice, and one that will not decode.\n * Cryptography is `jose`'s. This file supplies the policy: which key, which\n * algorithm, which audience, what counts as fresh.\n */\nimport { decodeSdJwt, getClaims, splitSdJwt } from '@sd-jwt/core';\nimport { type JWTVerifyOptions, jwtVerify } from 'jose';\nimport type { Clock } from '../../core/index.js';\nimport {\n AP2_CHECKOUT_MANDATE_VCT,\n AP2_DIGEST_ALGORITHM,\n AP2_SIGNING_ALGORITHM,\n} from './constants.js';\nimport { type Ap2ErrorContext, ap2Rejected } from './errors.js';\nimport type { TrustStore } from './trust.js';\n\nexport interface VerifiedMandate {\n readonly issuer: string;\n /** Every claim, with the presented disclosures resolved into place */\n readonly claims: Readonly<Record<string, unknown>>;\n /**\n * The issuer-signed token on its own, without the disclosures.\n *\n * This, not the presentation string, is the stable identity of a mandate:\n * disclosing or withholding an optional claim rewrites the presentation and\n * leaves the signed token untouched. Replay defence keys on a digest of it.\n */\n readonly signedToken: string;\n}\n\n/**\n * `@sd-jwt/core` passes the algorithm it read from `_sd_alg`, so this is also\n * where a presentation declaring anything but sha-256 is refused\n */\nasync function hasher(data: string | ArrayBuffer, algorithm: string): Promise<Uint8Array> {\n if (algorithm.toLowerCase() !== AP2_DIGEST_ALGORITHM) {\n throw new Error(`unsupported digest algorithm ${algorithm}`);\n }\n const bytes = typeof data === 'string' ? new TextEncoder().encode(data) : new Uint8Array(data);\n return new Uint8Array(await crypto.subtle.digest('SHA-256', bytes));\n}\n\nfunction asRecord(value: unknown): Record<string, unknown> | undefined {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : undefined;\n}\n\n/**\n * Order is the security boundary here: nothing is trusted until `jwtVerify`\n * returns. `kid` and `iss` are read before that only to pick which configured\n * key to try, and picking wrong just makes the signature fail.\n */\nexport async function verifyMandate(\n presentation: string,\n deps: { readonly trust: TrustStore; readonly clock: Clock; readonly clockSkewSeconds: number },\n context: Ap2ErrorContext,\n): Promise<VerifiedMandate> {\n let decoded: Awaited<ReturnType<typeof decodeSdJwt>>;\n let encodedJws: string;\n try {\n // Covers a malformed base JWT, a disclosure that will not decode, a\n // duplicate digest, and an `_sd_alg` this release does not implement\n decoded = await decodeSdJwt(presentation, hasher);\n encodedJws = splitSdJwt(presentation).jwt;\n } catch (cause) {\n throw ap2Rejected('malformed_presentation', { ...context, cause });\n }\n\n // Direct mode issues no key-bound mandates, so one arriving here belongs to\n // a flow we do not verify. Ignoring it would mean silently not checking a\n // proof that was sent.\n if (decoded.kbJwt !== undefined) {\n throw ap2Rejected('unsupported_mandate_type', context);\n }\n\n const rawPayload = asRecord(decoded.jwt.payload);\n const header = asRecord(decoded.jwt.header);\n if (rawPayload === undefined || header === undefined) {\n throw ap2Rejected('malformed_presentation', context);\n }\n\n const { issuer, key } = await deps.trust.resolve(rawPayload['iss'], header['kid'], context);\n\n const options: JWTVerifyOptions = {\n // Redundant today (the key is EC, so jose already refuses `alg: none` and\n // a forged HMAC) and kept for the day this resolves a key set instead of\n // one key, where the header would get to pick\n algorithms: [AP2_SIGNING_ALGORITHM],\n // Also redundant, and for the same reason: the key was resolved *from*\n // `iss` against the configured allowlist, so nothing reaching here can\n // carry a different one. It backstops a future resolver that matches on\n // something else. `audience` below is not redundant - `aud` is the\n // presenter's claim, checked against what the operator configured.\n issuer: issuer.issuer,\n audience: issuer.audience,\n clockTolerance: deps.clockSkewSeconds,\n // Injected clock, not jose's `Date.now()`, so expiry tests are tests\n currentDate: deps.clock.now(),\n };\n\n let verifiedPayload: Record<string, unknown>;\n try {\n const result = await jwtVerify(encodedJws, key, options);\n verifiedPayload = result.payload as Record<string, unknown>;\n } catch (cause) {\n throw ap2Rejected(classifyJoseFailure(cause), { ...context, cause });\n }\n\n requireFreshness(verifiedPayload, deps, context);\n\n let claims: Record<string, unknown>;\n try {\n // Against the VERIFIED payload: the decoded one would match disclosures\n // against digests nobody signed\n claims = (await getClaims(verifiedPayload, decoded.disclosures, hasher)) as Record<\n string,\n unknown\n >;\n } catch (cause) {\n // Where an appended disclosure that no digest references is refused\n throw ap2Rejected('malformed_presentation', { ...context, cause });\n }\n\n requireClosedCheckoutMandate(claims, context);\n\n return { issuer: issuer.issuer, claims, signedToken: encodedJws };\n}\n\n/**\n * Matched on jose's stable error `code`, not its message. A client is owed\n * \"expired\" versus \"did not verify\"; anything finer describes our checks back\n * to whoever is probing them.\n */\nfunction classifyJoseFailure(cause: unknown): 'expired' | 'wrong_audience' | 'invalid_signature' {\n const code = (cause as { code?: unknown })?.code;\n if (code === 'ERR_JWT_EXPIRED') return 'expired';\n if (code === 'ERR_JWT_CLAIM_VALIDATION_FAILED') {\n const claim = (cause as { claim?: unknown }).claim;\n if (claim === 'aud') return 'wrong_audience';\n if (claim === 'nbf' || claim === 'exp') return 'expired';\n }\n return 'invalid_signature';\n}\n\n/**\n * Required, not merely checked when present: jose validates a time claim only\n * if it is there, so a mandate omitting `exp` would verify and never expire\n */\nfunction requireFreshness(\n payload: Record<string, unknown>,\n deps: { readonly clock: Clock; readonly clockSkewSeconds: number },\n context: Ap2ErrorContext,\n): void {\n const exp = payload['exp'];\n const iat = payload['iat'];\n if (typeof exp !== 'number' || typeof iat !== 'number') {\n throw ap2Rejected('invalid_claims', context);\n }\n const nowSeconds = Math.floor(deps.clock.now().getTime() / 1000);\n // A future `iat` is a broken signer, or a mandate minted to outlive its own\n // expiry window\n if (iat > nowSeconds + deps.clockSkewSeconds) throw ap2Rejected('expired', context);\n}\n\n// Exactly `mandate.checkout.1`; see AP2_CHECKOUT_MANDATE_VCT for why\nfunction requireClosedCheckoutMandate(\n claims: Record<string, unknown>,\n context: Ap2ErrorContext,\n): void {\n if (claims['vct'] !== AP2_CHECKOUT_MANDATE_VCT) {\n throw ap2Rejected('unsupported_mandate_type', context);\n }\n}\n","/**\n * Static key resolution.\n *\n * Every key was written into `config.yaml` by an operator. No JWKS fetch, no\n * `jku`, no `x5u`. A mandate's `iss` and `kid` only choose *which* trusted key\n * verifies it; an unrecognised pair is refused, so a mandate can never\n * nominate its own signer.\n *\n * Not a \"try every key\" loop: that would make `kid` advisory and accept a\n * mandate that named a key it was not signed with.\n */\nimport { importJWK, type JWK } from 'jose';\nimport { AP2_SIGNING_ALGORITHM } from './constants.js';\nimport { type Ap2ErrorContext, ap2Rejected, ap2Unavailable } from './errors.js';\nimport type { Ap2TrustedIssuer } from './types.js';\n\n/** Named off `importJWK` because `CryptoKey` is a DOM type we do not load */\nexport type VerificationKey = Awaited<ReturnType<typeof importJWK>>;\n\nexport interface ResolvedKey {\n readonly issuer: Ap2TrustedIssuer;\n readonly key: VerificationKey;\n}\n\n/**\n * Resolves `(iss, kid)` against one configured issuer list. Caches the import\n * promise, not the key, so concurrent requests for a cold key share one import.\n */\nexport function createTrustStore(issuers: readonly Ap2TrustedIssuer[]) {\n const byIssuer = new Map(issuers.map((entry) => [entry.issuer, entry]));\n const imported = new Map<string, Promise<VerificationKey>>();\n\n return {\n /** Every trusted issuer id, for diagnostics. Never the keys themselves */\n issuerIds(): readonly string[] {\n return [...byIssuer.keys()];\n },\n\n async resolve(iss: unknown, kid: unknown, context: Ap2ErrorContext): Promise<ResolvedKey> {\n if (typeof iss !== 'string' || iss.length === 0) {\n throw ap2Rejected('invalid_claims', context);\n }\n const issuer = byIssuer.get(iss);\n if (issuer === undefined) throw ap2Rejected('untrusted_issuer', context);\n\n // Not defaulted to the issuer's only key: mid-rotation there are two,\n // and the gateway should not guess which one signed this\n if (typeof kid !== 'string' || kid.length === 0) {\n throw ap2Rejected('unknown_key', context);\n }\n const trusted = issuer.keys.find((candidate) => candidate.kid === kid);\n if (trusted === undefined) throw ap2Rejected('unknown_key', context);\n\n // JSON, not a joined string: both halves are operator-chosen and could\n // contain whatever separator we picked\n const cacheKey = JSON.stringify([iss, kid]);\n let pending = imported.get(cacheKey);\n if (pending === undefined) {\n pending = importJWK(trusted.jwk as JWK, AP2_SIGNING_ALGORITHM);\n imported.set(cacheKey, pending);\n }\n\n try {\n return { issuer, key: await pending };\n } catch (cause) {\n // Config already checked this JWK member by member, so reaching here\n // means our config is broken, not the mandate. Drop the cached\n // rejection so a fixed config is not still failing against it.\n imported.delete(cacheKey);\n throw ap2Unavailable('configured verification key could not be imported', {\n ...context,\n cause,\n });\n }\n },\n };\n}\n\nexport type TrustStore = ReturnType<typeof createTrustStore>;\n","/**\n * The Direct Checkout Mandate verifier: mandate signature first, then the\n * merchant checkout JWT it binds. Either stage failing is a refusal.\n *\n * What this proves is narrow. A trusted issuer signed this mandate, it has not\n * expired, it is addressed to us, and it binds a checkout document the\n * merchant signed. It does NOT prove the mandate authorises the purchase in\n * front of us: that is profile.ts, and a caller treating this as permission to\n * settle has skipped it.\n */\nimport type { Clock } from '../../core/index.js';\nimport { verifyCheckoutJwt } from './checkout-jwt.js';\nimport { type Ap2ErrorContext, ap2Rejected } from './errors.js';\nimport { verifyMandate } from './sd-jwt.js';\nimport { createTrustStore } from './trust.js';\nimport type { EnabledAp2Config, VerifiedCheckoutMandate } from './types.js';\n\nexport interface Ap2VerifierOptions {\n readonly config: EnabledAp2Config;\n readonly clock: Clock;\n}\n\nexport interface Ap2MandateVerifier {\n verify(presentation: string, context?: Ap2ErrorContext): Promise<VerifiedCheckoutMandate>;\n /** Trusted issuer ids, for `doctor`. Counts and names only, never keys */\n trustedIssuers(): { readonly mandate: readonly string[]; readonly checkout: readonly string[] };\n}\n\n/**\n * Algorithm-prefixed so a future digest change is visible in stored references\n * rather than silently producing unequal values for one mandate\n */\nasync function mandateReference(signedToken: string): Promise<string> {\n const digest = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(signedToken));\n return `sha256:${Buffer.from(digest).toString('base64url')}`;\n}\n\nexport function createAp2MandateVerifier(options: Ap2VerifierOptions): Ap2MandateVerifier {\n // Two stores, not one list: signing the merchant's checkout documents must\n // not confer the power to issue mandates\n const mandateTrust = createTrustStore(options.config.trust.mandateIssuers);\n const checkoutTrust = createTrustStore(options.config.trust.checkoutIssuers);\n const deps = { clock: options.clock, clockSkewSeconds: options.config.clockSkewSeconds };\n\n return {\n async verify(\n presentation: string,\n context: Ap2ErrorContext = {},\n ): Promise<VerifiedCheckoutMandate> {\n if (typeof presentation !== 'string' || presentation.length === 0) {\n throw ap2Rejected('malformed_presentation', context);\n }\n\n const mandate = await verifyMandate(presentation, { ...deps, trust: mandateTrust }, context);\n const checkout = await verifyCheckoutJwt(\n mandate.claims,\n { ...deps, trust: checkoutTrust },\n context,\n );\n\n return {\n reference: await mandateReference(mandate.signedToken),\n mandateIssuer: mandate.issuer,\n checkoutIssuer: checkout.issuer,\n checkoutJwtId: checkout.jwtId,\n checkoutClaims: checkout.claims,\n mandateClaims: mandate.claims,\n };\n },\n\n trustedIssuers() {\n return { mandate: mandateTrust.issuerIds(), checkout: checkoutTrust.issuerIds() };\n },\n };\n}\n","/**\n * The AP2 authorization provider: the seam between core's generic contract and\n * the mandate machinery.\n *\n * The provider owns its replay store. The caller that creates the provider must\n * call `close()`; `createGateway` does not close authorization providers.\n */\nimport type {\n AdapterHealth,\n AuthorizationFinalizeContext,\n AuthorizationProvider,\n AuthorizationRequirement,\n AuthorizationVerification,\n AuthorizationVerificationContext,\n Clock,\n Logger,\n} from '../../core/index.js';\nimport { NOOP_LOGGER, systemClock } from '../../core/index.js';\nimport { PACKAGE_VERSION } from '../../version.js';\nimport { AP2_CHECKOUT_PROFILE, AP2_SPEC_VERSION } from './constants.js';\nimport { buildAp2Descriptor } from './descriptor.js';\nimport { type Ap2ErrorContext, ap2Replayed, ap2Unavailable } from './errors.js';\nimport { bindMandateToPurchase } from './profile.js';\nimport { type Ap2ReplayStore, createAp2ReplayStore } from './replay-store.js';\nimport type { EnabledAp2Config } from './types.js';\nimport { createAp2MandateVerifier } from './verifier.js';\n\nexport interface Ap2AuthorizationProviderOptions {\n readonly config: EnabledAp2Config;\n readonly clock?: Clock;\n readonly logger?: Logger;\n /** Injectable so tests need not touch the filesystem */\n readonly replayStore?: Ap2ReplayStore;\n}\n\nexport interface Ap2AuthorizationProvider extends AuthorizationProvider {\n /** Closes the replay store */\n close(): void;\n}\n\n/**\n * A reservation is keyed by the mandate reference, so the handle and the\n * receipt's identity are the same digest. Kept as one name rather than two\n * fields that must never disagree.\n */\nexport function createAp2AuthorizationProvider(\n options: Ap2AuthorizationProviderOptions,\n): Ap2AuthorizationProvider {\n const clock = options.clock ?? systemClock;\n const logger = options.logger ?? NOOP_LOGGER;\n\n const verifier = createAp2MandateVerifier({ config: options.config, clock });\n const replay =\n options.replayStore ?? createAp2ReplayStore({ path: options.config.replay.path, logger });\n\n const requirement: AuthorizationRequirement = {\n method: 'ap2',\n version: AP2_SPEC_VERSION,\n profile: AP2_CHECKOUT_PROFILE,\n };\n\n async function verifyAndReserve(\n context: AuthorizationVerificationContext,\n ): Promise<AuthorizationVerification> {\n const errorContext: Ap2ErrorContext = {\n requestId: context.requestId,\n resourceId: context.resourceId,\n };\n\n const mandate = await verifier.verify(context.submission.payload, errorContext);\n // Before reserving, not after: a mandate that does not authorize this\n // purchase must stay spendable on the purchase it does authorize\n await bindMandateToPurchase(mandate, context, errorContext);\n\n let reservation: ReturnType<Ap2ReplayStore['reserve']>;\n try {\n reservation = replay.reserve({\n reference: mandate.reference,\n checkoutJti: mandate.checkoutJwtId,\n mandateIssuer: mandate.mandateIssuer,\n checkoutIssuer: mandate.checkoutIssuer,\n resourceId: context.resourceId,\n requestId: context.requestId,\n });\n } catch (cause) {\n throw ap2Unavailable('replay store could not be written', { ...errorContext, cause });\n }\n\n if (reservation.kind === 'replayed') {\n throw ap2Replayed(reservation.state, errorContext);\n }\n\n return {\n status: 'verified',\n method: 'ap2',\n reference: mandate.reference,\n reservationId: mandate.reference,\n // Opaque identifiers an operator can reconcile with. Never a claim from\n // the mandate: those carry the buyer's purchase and their personal data.\n // `checkoutId`, not `checkoutJwtId` - the receipt store redacts any key\n // that reads as secret-shaped, and \"jwt\" is on that list.\n metadata: {\n mandateIssuer: mandate.mandateIssuer,\n checkoutIssuer: mandate.checkoutIssuer,\n checkoutId: mandate.checkoutJwtId,\n },\n };\n }\n\n const finalize = (\n action: 'consume' | 'release' | 'markUncertain',\n reservationId: string,\n context: AuthorizationFinalizeContext,\n ): void => {\n try {\n replay[action](reservationId);\n } catch (cause) {\n throw ap2Unavailable(`replay store could not record ${action}`, { ...context, cause });\n }\n };\n\n return {\n name: 'ap2',\n descriptor: buildAp2Descriptor(PACKAGE_VERSION),\n requirement,\n verifyAndReserve,\n\n async consume(reservationId, context) {\n finalize('consume', reservationId, context);\n },\n async release(reservationId, context) {\n finalize('release', reservationId, context);\n },\n async markUncertain(reservationId, context) {\n finalize('markUncertain', reservationId, context);\n },\n\n async health(): Promise<AdapterHealth> {\n const startedAt = clock.monotonicMs();\n const trusted = verifier.trustedIssuers();\n const checkedAt = clock.nowIso();\n const durationMs = Math.round(clock.monotonicMs() - startedAt);\n try {\n // A read against the real table, so a database that opened but cannot\n // be queried is caught here rather than on the first purchase\n replay.stateOf('health-probe');\n } catch {\n // A fixed token, never a sentence built from the caught error\n return { status: 'fail', checkedAt, durationMs, detail: 'replay-store-unavailable' };\n }\n return {\n status: 'pass',\n checkedAt,\n durationMs,\n detail: `mandate-issuers=${trusted.mandate.length} checkout-issuers=${trusted.checkout.length}`,\n };\n },\n\n close() {\n replay.close();\n },\n };\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/authorization/ap2/errors.ts","../src/authorization/ap2/sha256.ts","../src/authorization/ap2/profile.ts","../src/authorization/ap2/checkout-signer.ts","../src/authorization/ap2/descriptor.ts","../src/authorization/ap2/replay-store.ts","../src/authorization/ap2/checkout-jwt.ts","../src/authorization/ap2/sd-jwt.ts","../src/authorization/ap2/trust.ts","../src/authorization/ap2/verifier.ts","../src/authorization/ap2/provider.ts"],"names":["jwtVerify"],"mappings":"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","file":"ap2.js","sourcesContent":["/**\n * Every failure the AP2 verifier can report.\n *\n * `CommerceError.message` reaches the client, and a mandate carries the\n * buyer's purchase and often personal data, so messages are fixed phrases from\n * the list below. The machine-readable code goes in `details.reason` and the\n * original exception on `cause`, which is never serialized.\n *\n * Three codes: AUTHORIZATION_INVALID when the buyer's mandate is bad,\n * AUTHORIZATION_REPLAYED when it is good but spent, and\n * AUTHORIZATION_PROVIDER_UNAVAILABLE when our verifier never reached a\n * verdict. Blaming the buyer for our outage refuses a good mandate.\n */\nimport { CommerceError } from '../../core';\n\n/**\n * Coarse on purpose: a client learns roughly where its mandate was refused,\n * not which check failed. Finer detail is an oracle for probing trust policy,\n * so a mandate signed with a disallowed algorithm reports `invalid_signature`\n * and one declaring a digest other than sha-256 `malformed_presentation`.\n */\nexport const AP2_REJECTION_REASONS = [\n 'malformed_presentation',\n 'untrusted_issuer',\n 'unknown_key',\n 'invalid_signature',\n 'invalid_claims',\n 'expired',\n 'wrong_audience',\n 'unsupported_mandate_type',\n 'checkout_binding_failed',\n 'purchase_mismatch',\n] as const;\n\nexport type Ap2RejectionReason = (typeof AP2_REJECTION_REASONS)[number];\n\nconst MESSAGES: Readonly<Record<Ap2RejectionReason, string>> = {\n malformed_presentation: 'The authorization is not a well-formed SD-JWT presentation.',\n untrusted_issuer: 'The mandate was issued by a party this merchant does not trust.',\n unknown_key: 'The mandate names a signing key this merchant does not trust.',\n invalid_signature: 'The mandate signature did not verify.',\n invalid_claims: 'The mandate is missing required claims or they are malformed.',\n expired: 'The mandate is expired or not yet valid.',\n wrong_audience: 'The mandate is addressed to a different audience.',\n unsupported_mandate_type: 'The mandate is not a closed Direct Checkout Mandate.',\n checkout_binding_failed: 'The merchant checkout document bound to the mandate did not verify.',\n purchase_mismatch: 'The mandate does not authorize this purchase.',\n};\n\nexport interface Ap2ErrorContext {\n readonly requestId?: string;\n readonly resourceId?: string;\n readonly cause?: unknown;\n}\n\n/** The buyer's mandate is bad. Fail closed */\nexport function ap2Rejected(\n reason: Ap2RejectionReason,\n context: Ap2ErrorContext = {},\n): CommerceError {\n return new CommerceError('AUTHORIZATION_INVALID', MESSAGES[reason], {\n details: { method: 'ap2', reason },\n ...(context.requestId !== undefined ? { requestId: context.requestId } : {}),\n ...(context.resourceId !== undefined ? { resourceId: context.resourceId } : {}),\n ...(context.cause !== undefined ? { cause: context.cause } : {}),\n });\n}\n\n/**\n * The mandate verified but has already been presented. A separate code from\n * a bad mandate: nothing is wrong with this mandate except that it is spent.\n */\nexport function ap2Replayed(state: string, context: Ap2ErrorContext = {}): CommerceError {\n return new CommerceError(\n 'AUTHORIZATION_REPLAYED',\n 'This mandate has already been presented and cannot authorize another purchase.',\n {\n details: { method: 'ap2', reason: 'replayed', state },\n ...(context.requestId !== undefined ? { requestId: context.requestId } : {}),\n ...(context.resourceId !== undefined ? { resourceId: context.resourceId } : {}),\n },\n );\n}\n\n/**\n * The check never ran (a configured key that will not import, say). Retryable,\n * and never recorded against the payer: the mandate may be perfectly good.\n */\nexport function ap2Unavailable(detail: string, context: Ap2ErrorContext = {}): CommerceError {\n return new CommerceError(\n 'AUTHORIZATION_PROVIDER_UNAVAILABLE',\n 'Authorization could not be verified right now. This is a merchant-side fault, not a problem with the presented mandate.',\n {\n details: { method: 'ap2', reason: 'verifier_unavailable', detail },\n ...(context.requestId !== undefined ? { requestId: context.requestId } : {}),\n ...(context.resourceId !== undefined ? { resourceId: context.resourceId } : {}),\n ...(context.cause !== undefined ? { cause: context.cause } : {}),\n },\n );\n}\n","import { createHash } from 'node:crypto';\n\n/** SHA-256, the only digest AP2 verification and signing use. A string is hashed as UTF-8 */\nexport function sha256(data: string | Uint8Array): Buffer {\n return createHash('sha256').update(data).digest();\n}\n","/**\n * Binds a verified mandate to the purchase in front of us. Without this\n * comparison a mandate approved for a $0.01 report would settle a $500 one.\n *\n * Everything is compared against the ALREADY RESOLVED request. Nothing is\n * taken from the mandate to shape the purchase, which would invert the\n * control.\n */\nimport canonicalize from 'canonicalize';\nimport { type AuthorizationVerificationContext, CommerceError } from '../../core';\nimport { isRecord } from '../../core/is-record';\nimport { AP2_CHECKOUT_PROFILE } from './constants';\nimport { type Ap2ErrorContext, ap2Rejected } from './errors';\nimport { sha256 } from './sha256';\nimport type { VerifiedCheckoutMandate } from './types';\n\n/**\n * All required. Absent is a mismatch, never a skipped check: a mandate that\n * will not say which resource or how much authorizes nothing in particular.\n */\nconst REQUIRED_PROFILE_CLAIMS = [\n 'profile',\n 'resource_id',\n 'input_hash',\n 'amount',\n 'currency',\n 'payment_method',\n] as const;\n\n/**\n * RFC 8785 (JCS) digest of the validated resource input.\n *\n * Binds a mandate to the exact request, not just to a resource and a price:\n * without it, one mandate for `translate` would authorize any translation.\n *\n * The merchant's signer, possibly in another language, agrees with this digest\n * only if it follows RFC 8785's number formatting and UTF-16 key ordering too;\n * sorting keys is not enough.\n *\n * The caller passes what the backend will receive: validated, reserved fields\n * stripped, no request id or transport metadata (the buyer could not have\n * known those when they approved).\n */\nexport function computeInputHash(input: unknown): string {\n const canonical = canonicalize(input ?? {});\n // undefined means JSON cannot represent the value (a function, say). On the\n // gateway path the input already passed schema validation, so this is not a\n // buyer error.\n if (canonical === undefined) {\n throw new CommerceError('INTERNAL_ERROR', 'resource input is not canonicalizable JSON');\n }\n return sha256(canonical).toString('base64url');\n}\n\nconst EVM_ADDRESS = /^0x[0-9a-f]{40}$/i;\n\n// EIP-55 encodes an address checksum through letter casing, so lowercase and\n// checksummed forms identify the same account. Other values compare exactly.\nfunction sameCoordinate(declared: unknown, expected: string | undefined): boolean {\n if (typeof declared === 'string' && expected !== undefined) {\n if (EVM_ADDRESS.test(declared) && EVM_ADDRESS.test(expected)) {\n return declared.toLowerCase() === expected.toLowerCase();\n }\n }\n return declared === expected;\n}\n\n/**\n * Throws on the first mismatch with one coarse reason. Which field disagreed\n * is not reported: a caller able to ask about one field at a time can read a\n * mandate's contents out of the gateway by elimination.\n */\nexport async function bindMandateToPurchase(\n mandate: VerifiedCheckoutMandate,\n context: AuthorizationVerificationContext,\n errorContext: Ap2ErrorContext,\n): Promise<void> {\n const profile = mandate.checkoutClaims['agent_commerce'];\n if (!isRecord(profile)) throw ap2Rejected('purchase_mismatch', errorContext);\n\n for (const claim of REQUIRED_PROFILE_CLAIMS) {\n const value = profile[claim];\n if (typeof value !== 'string' || value.length === 0) {\n throw ap2Rejected('purchase_mismatch', errorContext);\n }\n }\n\n const requirement = context.requirement;\n const expectedInputHash = computeInputHash(context.input);\n\n const mustMatch: readonly (readonly [string, unknown])[] = [\n ['profile', AP2_CHECKOUT_PROFILE],\n ['resource_id', context.resourceId],\n ['input_hash', expectedInputHash],\n // Decimal strings on both sides. Comparing numerically would make \"0.10\"\n // and \"0.1\" equal, and a mandate says what it says.\n ['amount', requirement.amount],\n ['currency', requirement.currency],\n ['payment_method', requirement.provider],\n ];\n\n for (const [claim, expected] of mustMatch) {\n if (profile[claim] !== expected) throw ap2Rejected('purchase_mismatch', errorContext);\n }\n\n // Checked whenever EITHER side names one, which is the fail-closed reading.\n // A mandate silent about the chain must not unlock a mainnet settlement, and\n // one naming a chain the requirement lacks was approved for another rail.\n for (const [claim, expected] of [\n ['destination', requirement.destination],\n ['network', requirement.network],\n ['asset', requirement.asset],\n ] as const) {\n const declared = profile[claim];\n if (declared === undefined && expected === undefined) continue;\n if (!sameCoordinate(declared, expected)) throw ap2Rejected('purchase_mismatch', errorContext);\n }\n}\n","/**\n * Merchant-side helper: mints the checkout JWT a Checkout Mandate binds.\n *\n * A merchant runs it in their own process, with their own key, to produce the\n * document the buyer approves; the gateway never calls it. It mirrors\n * `createPaymentProof`, which a buyer runs to produce a payment proof.\n *\n * It exists mainly for `input_hash`, an RFC 8785 digest. A serializer that\n * only sorts keys, as many non-JavaScript JSON libraries do, can disagree with\n * it on floats and non-ASCII keys, and the mandate is then refused with a\n * reason that does not name the field.\n */\nimport { importPKCS8, type JWK, SignJWT } from 'jose';\nimport {\n AP2_CHECKOUT_PROFILE,\n AP2_JWK_CURVE,\n AP2_KEY_TYPE,\n AP2_SIGNING_ALGORITHM,\n} from './constants';\nimport { computeInputHash } from './profile';\n\n/**\n * A private ES256 key: either a private JWK (the pair of the public one in the\n * gateway's `checkoutIssuers`) or a PKCS#8 PEM, as `openssl` emits it\n */\nexport type Ap2SigningKey = Readonly<Record<string, unknown>> | string;\n\nexport interface CreateCheckoutJwtOptions {\n readonly privateKey: Ap2SigningKey;\n /** Must match a `kid` configured under the gateway's `checkoutIssuers` */\n readonly kid: string;\n /** Must match that issuer's configured `issuer` */\n readonly issuer: string;\n /** Must match that issuer's configured `audience` */\n readonly audience: string;\n\n readonly resourceId: string;\n /**\n * The resource input this purchase is for, exactly as the buyer will send\n * it: no reserved fields, no request id, no transport metadata\n */\n readonly input: unknown;\n\n /**\n * Decimal string, never a number, and compared as a string: `0.10` and `0.1`\n * are different mandates. Take it from your own catalog rather than from\n * whatever the agent asked for.\n */\n readonly amount: string;\n readonly currency: string;\n /** The rail that will settle, e.g. `x402` */\n readonly paymentMethod: string;\n\n /**\n * Settlement coordinates. Required whenever the gateway's requirement names\n * them, which under x402 is always. A mandate silent about the chain will\n * not unlock a settlement on one.\n */\n readonly destination?: string;\n readonly network?: string;\n readonly asset?: string;\n\n /** Defaults to a random UUID. Recorded on the receipt and used for replay defense */\n readonly jwtId?: string;\n /** Defaults to 900: a human approval sits inside this window */\n readonly expiresInSeconds?: number;\n /** Injectable so a test need not move the wall clock */\n readonly now?: Date;\n}\n\nconst DEFAULT_EXPIRES_IN_SECONDS = 900;\n\nfunction requireText(value: unknown, field: string): string {\n if (typeof value !== 'string' || value.length === 0) {\n throw new TypeError(\n `createCheckoutJwt: ${field} must be a non-empty string, received ${describe(value)}`,\n );\n }\n return value;\n}\n\nfunction describe(value: unknown): string {\n return value === null ? 'null' : typeof value;\n}\n\n/**\n * Every rejection here is a mistake that would otherwise surface as an opaque\n * verification failure much later: the public half of the pair, the wrong key\n * type, or a PEM that is not PKCS#8\n */\nasync function resolveKey(\n key: Ap2SigningKey,\n): Promise<JWK | Awaited<ReturnType<typeof importPKCS8>>> {\n if (typeof key === 'string') {\n if (!key.includes('BEGIN PRIVATE KEY')) {\n throw new TypeError(\n 'createCheckoutJwt: a string privateKey must be a PKCS#8 PEM beginning \"-----BEGIN PRIVATE KEY-----\"',\n );\n }\n return importPKCS8(key, AP2_SIGNING_ALGORITHM);\n }\n if (typeof key !== 'object' || key === null) {\n throw new TypeError('createCheckoutJwt: privateKey must be a private JWK or a PKCS#8 PEM');\n }\n if (key['d'] === undefined) {\n throw new TypeError(\n 'createCheckoutJwt: privateKey is a public JWK (no \"d\"). Use the private half of the pair whose public key is configured under checkoutIssuers',\n );\n }\n if (key['kty'] !== AP2_KEY_TYPE || key['crv'] !== AP2_JWK_CURVE) {\n throw new TypeError(\n `createCheckoutJwt: privateKey must be ${AP2_KEY_TYPE}/${AP2_JWK_CURVE}, the pair ${AP2_SIGNING_ALGORITHM} implies`,\n );\n }\n return key as JWK;\n}\n\n/**\n * Returns the compact JWT to hand to the agent, which wraps it in the Checkout\n * Mandate the buyer signs\n */\nexport async function createCheckoutJwt(options: CreateCheckoutJwtOptions): Promise<string> {\n const kid = requireText(options.kid, 'kid');\n const issuer = requireText(options.issuer, 'issuer');\n const audience = requireText(options.audience, 'audience');\n const resourceId = requireText(options.resourceId, 'resourceId');\n const currency = requireText(options.currency, 'currency');\n const paymentMethod = requireText(options.paymentMethod, 'paymentMethod');\n\n if (typeof options.amount === 'number') {\n throw new TypeError(\n 'createCheckoutJwt: amount must be a decimal string, not a number. It is compared as a string, so 0.1 and \"0.10\" are different mandates',\n );\n }\n const amount = requireText(options.amount, 'amount');\n\n const key = await resolveKey(options.privateKey);\n const issuedAt = Math.floor((options.now ?? new Date()).getTime() / 1000);\n const expiresIn = options.expiresInSeconds ?? DEFAULT_EXPIRES_IN_SECONDS;\n if (!Number.isInteger(expiresIn) || expiresIn <= 0) {\n throw new TypeError('createCheckoutJwt: expiresInSeconds must be a positive whole number');\n }\n\n const agentCommerce: Record<string, string> = {\n profile: AP2_CHECKOUT_PROFILE,\n resource_id: resourceId,\n input_hash: computeInputHash(options.input),\n amount,\n currency,\n payment_method: paymentMethod,\n ...(options.destination !== undefined ? { destination: options.destination } : {}),\n ...(options.network !== undefined ? { network: options.network } : {}),\n ...(options.asset !== undefined ? { asset: options.asset } : {}),\n };\n\n return new SignJWT({ agent_commerce: agentCommerce })\n .setProtectedHeader({ alg: AP2_SIGNING_ALGORITHM, kid, typ: 'JWT' })\n .setIssuer(issuer)\n .setAudience(audience)\n .setIssuedAt(issuedAt)\n .setExpirationTime(issuedAt + expiresIn)\n .setJti(options.jwtId ?? crypto.randomUUID())\n .sign(key);\n}\n","/**\n * Adapter self-description.\n *\n * Imports nothing but core types and the pins, so `doctor` can report AP2\n * without pulling `jose` or `@sd-jwt/core` into the CLI bundle.\n */\nimport type { AdapterDescriptor } from '../../core';\nimport {\n AP2_CHECKOUT_MANDATE_VCT,\n AP2_CHECKOUT_PROFILE,\n AP2_DIGEST_ALGORITHM,\n AP2_SIGNING_ALGORITHM,\n AP2_SPEC_VERSION,\n} from './constants';\n\n/** What this provider actually verifies */\nexport const AP2_CAPABILITIES: readonly string[] = [\n 'direct-mode',\n AP2_CHECKOUT_MANDATE_VCT,\n 'sd-jwt-presentation',\n AP2_SIGNING_ALGORITHM,\n AP2_DIGEST_ALGORITHM,\n 'static-inline-trust',\n 'merchant-checkout-jwt-binding',\n AP2_CHECKOUT_PROFILE,\n 'purchase-binding',\n 'replay-defence',\n];\n\n/**\n * Major AP2 features this provider does not support, published in its\n * descriptor and printed by `doctor`, so no client assumes full protocol\n * support\n */\nexport const AP2_UNSUPPORTED: readonly string[] = [\n // Mandate kinds. Open mandates are refused: see AP2_CHECKOUT_MANDATE_VCT\n 'autonomous mode',\n 'open checkout mandates (mandate.checkout.open.1)',\n 'intent mandates',\n 'cart mandates',\n 'spending constraint evaluation',\n 'cnf-bound agent keys',\n // Key handling. Every key is written into config by an operator\n 'JWKS and any key discovery by URL (jku, x5u)',\n 'issuer metadata fetching',\n 'key rotation without a config change',\n // Algorithms\n 'signature algorithms other than ES256',\n 'digest algorithms other than sha-256',\n // Roles this gateway does not play\n 'mandate issuance',\n 'AP2 over the ACP checkout adapter',\n];\n\nexport function buildAp2Descriptor(implementationVersion: string): AdapterDescriptor {\n return {\n name: 'ap2',\n kind: 'authorization',\n implementationVersion,\n supportedSpec: `ap2/v${AP2_SPEC_VERSION} mode=direct`,\n capabilities: AP2_CAPABILITIES,\n status: 'experimental',\n unsupported: AP2_UNSUPPORTED,\n };\n}\n","/**\n * Durable record of which mandates have been spent.\n *\n * Its own table in its own file: a payment replay key is needed only until its\n * authorization's `validBefore`, after which it cannot settle, while a consumed\n * mandate must stay consumed for as long as the merchant can be asked what they\n * delivered. Hence no retention sweep, unlike the ACP idempotency store:\n * deleting a `consumed` row makes that mandate spendable again. If the table\n * ever needs bounding, archive `released` rows and leave the rest.\n *\n * Settlement and a local commit are not one transaction. If the process dies\n * between them the row stays `reserved` and that mandate is refused from then\n * on: a refused retry costs a round trip, the other direction costs a second\n * payment.\n */\nimport type { Database } from 'better-sqlite3';\nimport { type Logger, NOOP_LOGGER } from '../../core';\nimport { openSqliteDatabase } from '../../storage/sqlite';\n\n/**\n * `released` is \"nothing happened\" and the only state a mandate can be\n * presented from again. `uncertain` is a settlement whose outcome we never\n * learned: not reusable, but findable by an operator reconciling by hand.\n */\nexport type Ap2AuthorizationState = 'reserved' | 'consumed' | 'released' | 'uncertain';\n\n/**\n * A digest and a few identifiers: everything replay defense needs, and nothing\n * a leaked database would hand an attacker\n */\nexport interface Ap2ReservationRequest {\n /**\n * Digest of the ISSUER-SIGNED TOKEN, not of the presentation. Selective\n * disclosure gives one mandate many presentation strings, so keying on the\n * presentation would let it be spent once per disclosed subset.\n */\n readonly reference: string;\n /** `jti` of the merchant checkout JWT the mandate binds */\n readonly checkoutJti: string;\n readonly mandateIssuer: string;\n readonly checkoutIssuer: string;\n readonly resourceId: string;\n readonly requestId: string;\n}\n\nexport type Ap2ReservationResult =\n | { readonly kind: 'reserved' }\n /** Already reserved, consumed, or of uncertain outcome. Never re-spendable */\n | { readonly kind: 'replayed'; readonly state: Ap2AuthorizationState };\n\nexport interface Ap2ReplayStore {\n /** Atomically claim a mandate, or report that something already holds it */\n reserve(request: Ap2ReservationRequest): Ap2ReservationResult;\n /** Settlement succeeded: spend it permanently */\n consume(reference: string): void;\n /** Nothing happened: hand it back so a corrected retry can use it */\n release(reference: string): void;\n /** Settlement outcome unknown. Not reusable, and flagged for a human */\n markUncertain(reference: string): void;\n /** Current state, for tests and diagnostics */\n stateOf(reference: string): Ap2AuthorizationState | undefined;\n close(): void;\n}\n\nexport interface Ap2ReplayStoreOptions {\n /** File path, or ':memory:' for tests */\n readonly path: string;\n readonly logger?: Logger;\n /** Injectable so tests need not move the wall clock */\n readonly now?: () => number;\n}\n\ninterface StateRow {\n state: string;\n}\n\nexport function createAp2ReplayStore(options: Ap2ReplayStoreOptions): Ap2ReplayStore {\n const logger = options.logger ?? NOOP_LOGGER;\n const now = options.now ?? (() => Date.now());\n\n const db: Database = openSqliteDatabase({\n path: options.path,\n label: 'AP2 authorization database',\n logger,\n });\n migrate(db);\n\n const selectByReference = db.prepare<[string], StateRow>(\n 'SELECT state FROM ap2_authorizations WHERE reference = ?',\n );\n // Two mandates can bind one checkout document, giving two references, so\n // the reference alone would not catch the second one\n const selectLiveByJti = db.prepare<[string, string], StateRow>(\n `SELECT state FROM ap2_authorizations\n WHERE checkout_jti = ? AND reference != ? AND state != 'released'`,\n );\n const insert = db.prepare(\n `INSERT INTO ap2_authorizations\n (reference, checkout_jti, mandate_issuer, checkout_issuer, resource_id, request_id,\n state, created_at, updated_at)\n VALUES (@reference, @checkout_jti, @mandate_issuer, @checkout_issuer, @resource_id,\n @request_id, 'reserved', @at, @at)`,\n );\n const reReserve = db.prepare(\n `UPDATE ap2_authorizations\n SET state = 'reserved', request_id = @request_id, updated_at = @at\n WHERE reference = @reference AND state = 'released'`,\n );\n // Guarded on `reserved`: releasing a `consumed` row would hand back a\n // mandate whose money has already moved\n const transition = db.prepare(\n `UPDATE ap2_authorizations SET state = @state, updated_at = @at\n WHERE reference = @reference AND state = 'reserved'`,\n );\n\n const reserveTx = db.transaction((request: Ap2ReservationRequest): Ap2ReservationResult => {\n const at = new Date(now()).toISOString();\n\n const existing = selectByReference.get(request.reference);\n if (existing !== undefined && existing.state !== 'released') {\n return { kind: 'replayed', state: existing.state as Ap2AuthorizationState };\n }\n\n // Checked for a released reference too: another mandate may have reserved\n // or spent the same checkout while this one was released\n const sameCheckout = selectLiveByJti.get(request.checkoutJti, request.reference);\n if (sameCheckout !== undefined) {\n return { kind: 'replayed', state: sameCheckout.state as Ap2AuthorizationState };\n }\n\n if (existing !== undefined) {\n reReserve.run({ reference: request.reference, request_id: request.requestId, at });\n return { kind: 'reserved' };\n }\n\n insert.run({\n reference: request.reference,\n checkout_jti: request.checkoutJti,\n mandate_issuer: request.mandateIssuer,\n checkout_issuer: request.checkoutIssuer,\n resource_id: request.resourceId,\n request_id: request.requestId,\n at,\n });\n return { kind: 'reserved' };\n });\n\n const move = (reference: string, state: Ap2AuthorizationState): void => {\n transition.run({ reference, state, at: new Date(now()).toISOString() });\n };\n\n let closed = false;\n return {\n reserve(request) {\n return reserveTx(request);\n },\n consume(reference) {\n move(reference, 'consumed');\n },\n release(reference) {\n move(reference, 'released');\n },\n markUncertain(reference) {\n move(reference, 'uncertain');\n },\n stateOf(reference) {\n return selectByReference.get(reference)?.state as Ap2AuthorizationState | undefined;\n },\n close() {\n if (closed) return;\n closed = true;\n db.close();\n },\n };\n}\n\n// `PRAGMA user_version`, so reopening an existing file is a no-op check\nfunction migrate(db: Database): void {\n const current = db.pragma('user_version', { simple: true }) as number;\n if (current >= 1) return;\n const apply = db.transaction(() => {\n db.exec(`\n CREATE TABLE IF NOT EXISTS ap2_authorizations (\n reference TEXT PRIMARY KEY,\n checkout_jti TEXT NOT NULL,\n mandate_issuer TEXT NOT NULL,\n checkout_issuer TEXT NOT NULL,\n resource_id TEXT NOT NULL,\n request_id TEXT NOT NULL,\n state TEXT NOT NULL\n CHECK (state IN ('reserved', 'consumed', 'released', 'uncertain')),\n created_at TEXT NOT NULL,\n updated_at TEXT NOT NULL\n );\n CREATE INDEX IF NOT EXISTS idx_ap2_authorizations_checkout_jti\n ON ap2_authorizations(checkout_jti);\n `);\n db.pragma('user_version = 1');\n });\n apply();\n}\n","/**\n * Stage two: the merchant checkout JWT the mandate binds.\n *\n * Two things have to hold. The hash proves the buyer approved *this* document;\n * the signature proves the merchant issued it. Hash alone accepts a document\n * the buyer wrote themselves; signature alone accepts a genuine merchant\n * document this mandate never covered.\n */\nimport { decodeJwt, decodeProtectedHeader, type JWTVerifyOptions, jwtVerify } from 'jose';\nimport type { Clock } from '../../core';\nimport { AP2_SIGNING_ALGORITHM } from './constants';\nimport { type Ap2ErrorContext, ap2Rejected } from './errors';\nimport { sha256 } from './sha256';\nimport type { TrustStore } from './trust';\n\nexport interface VerifiedCheckoutJwt {\n readonly issuer: string;\n readonly jwtId: string;\n readonly claims: Readonly<Record<string, unknown>>;\n}\n\n/**\n * `mandateClaims` must come from an already-verified mandate: `checkout_hash`\n * is worth nothing unless the issuer signed it\n */\nexport async function verifyCheckoutJwt(\n mandateClaims: Readonly<Record<string, unknown>>,\n deps: { readonly trust: TrustStore; readonly clock: Clock; readonly clockSkewSeconds: number },\n context: Ap2ErrorContext,\n): Promise<VerifiedCheckoutJwt> {\n const compact = mandateClaims['checkout_jwt'];\n const expectedHash = mandateClaims['checkout_hash'];\n if (typeof compact !== 'string' || compact.length === 0) {\n throw ap2Rejected('invalid_claims', context);\n }\n if (typeof expectedHash !== 'string' || expectedHash.length === 0) {\n throw ap2Rejected('invalid_claims', context);\n }\n\n requireMatchingHash(compact, expectedHash, context);\n\n // Unverified, and read only to pick which configured key to try\n let header: ReturnType<typeof decodeProtectedHeader>;\n let unverifiedPayload: ReturnType<typeof decodeJwt>;\n try {\n header = decodeProtectedHeader(compact);\n unverifiedPayload = decodeJwt(compact);\n } catch (cause) {\n throw ap2Rejected('checkout_binding_failed', { ...context, cause });\n }\n\n const { issuer, key } = await deps.trust.resolve(unverifiedPayload.iss, header.kid, context);\n\n const options: JWTVerifyOptions = {\n algorithms: [AP2_SIGNING_ALGORITHM],\n issuer: issuer.issuer,\n audience: issuer.audience,\n clockTolerance: deps.clockSkewSeconds,\n currentDate: deps.clock.now(),\n };\n\n let claims: Record<string, unknown>;\n try {\n const result = await jwtVerify(compact, key, options);\n claims = result.payload as Record<string, unknown>;\n } catch (cause) {\n throw ap2Rejected('checkout_binding_failed', { ...context, cause });\n }\n\n const exp = claims['exp'];\n const iat = claims['iat'];\n const jti = claims['jti'];\n // jose validates a time claim only when present, so requiring them is ours\n if (typeof exp !== 'number' || typeof iat !== 'number') {\n throw ap2Rejected('invalid_claims', context);\n }\n // `jti` is what replay defense and the receipt record, so it is required\n if (typeof jti !== 'string' || jti.length === 0) {\n throw ap2Rejected('invalid_claims', context);\n }\n const nowSeconds = Math.floor(deps.clock.now().getTime() / 1000);\n if (iat > nowSeconds + deps.clockSkewSeconds) throw ap2Rejected('expired', context);\n\n return { issuer: issuer.issuer, jwtId: jti, claims };\n}\n\n/**\n * Hashes the compact JWT as it arrived. Re-encoding the parsed claims would\n * hash a different document from the one being verified.\n */\nfunction requireMatchingHash(compact: string, expected: string, context: Ap2ErrorContext): void {\n // sha-256 only: `_sd_alg` was already pinned to it upstream\n const actual = sha256(compact).toString('base64url');\n // Plain comparison: both sides are public to anyone holding the\n // presentation, so there is no secret for timing to leak\n if (actual !== expected) throw ap2Rejected('checkout_binding_failed', context);\n}\n","/**\n * Stage one: parse the presentation, verify the issuer's signature, resolve\n * the disclosures.\n *\n * Disclosure mechanics come from `@sd-jwt/core`, which refuses the three\n * attacks that live in that algorithm: an appended disclosure nothing\n * references, the same disclosure twice, and one that will not decode.\n * Cryptography is `jose`'s. This file supplies the policy: which key, which\n * algorithm, which audience, what counts as fresh.\n */\nimport { decodeSdJwt, getClaims, splitSdJwt } from '@sd-jwt/core';\nimport { type JWTVerifyOptions, jwtVerify } from 'jose';\nimport type { Clock } from '../../core';\nimport { isRecord } from '../../core/is-record';\nimport { AP2_CHECKOUT_MANDATE_VCT, AP2_DIGEST_ALGORITHM, AP2_SIGNING_ALGORITHM } from './constants';\nimport { type Ap2ErrorContext, ap2Rejected } from './errors';\nimport { sha256 } from './sha256';\nimport type { TrustStore } from './trust';\n\nexport interface VerifiedMandate {\n readonly issuer: string;\n /** Every claim, with the presented disclosures resolved into place */\n readonly claims: Readonly<Record<string, unknown>>;\n /**\n * The issuer-signed token on its own, without the disclosures.\n *\n * This, not the presentation string, is the stable identity of a mandate:\n * disclosing or withholding an optional claim rewrites the presentation and\n * leaves the signed token untouched. Replay defense keys on a digest of it.\n */\n readonly signedToken: string;\n}\n\n/**\n * `@sd-jwt/core` passes the algorithm it read from `_sd_alg`, so this is also\n * where a presentation declaring anything but sha-256 is refused\n */\nfunction hasher(data: string | ArrayBuffer, algorithm: string): Uint8Array {\n if (algorithm.toLowerCase() !== AP2_DIGEST_ALGORITHM) {\n throw ap2Rejected('malformed_presentation');\n }\n return sha256(typeof data === 'string' ? data : new Uint8Array(data));\n}\n\n/**\n * Order is the security boundary here: nothing is trusted until `jwtVerify`\n * returns. `kid` and `iss` are read before that only to pick which configured\n * key to try, and picking wrong just makes the signature fail.\n */\nexport async function verifyMandate(\n presentation: string,\n deps: { readonly trust: TrustStore; readonly clock: Clock; readonly clockSkewSeconds: number },\n context: Ap2ErrorContext,\n): Promise<VerifiedMandate> {\n let decoded: Awaited<ReturnType<typeof decodeSdJwt>>;\n let encodedJws: string;\n try {\n // Covers a malformed base JWT, a disclosure that will not decode, a\n // duplicate digest, and an `_sd_alg` other than sha-256\n decoded = await decodeSdJwt(presentation, hasher);\n encodedJws = splitSdJwt(presentation).jwt;\n } catch (cause) {\n throw ap2Rejected('malformed_presentation', { ...context, cause });\n }\n\n // Direct mode issues no key-bound mandates, so one arriving here belongs to\n // a flow we do not verify. Ignoring it would mean silently not checking a\n // proof that was sent.\n if (decoded.kbJwt !== undefined) {\n throw ap2Rejected('unsupported_mandate_type', context);\n }\n\n const rawPayload = decoded.jwt.payload;\n const header = decoded.jwt.header;\n if (!isRecord(rawPayload) || !isRecord(header)) {\n throw ap2Rejected('malformed_presentation', context);\n }\n\n const { issuer, key } = await deps.trust.resolve(rawPayload['iss'], header['kid'], context);\n\n const options: JWTVerifyOptions = {\n // Redundant with one resolved EC key, which already refuses `alg: none` and\n // a forged HMAC. It stops the header picking the algorithm if a key set is\n // ever resolved instead.\n algorithms: [AP2_SIGNING_ALGORITHM],\n // Also redundant, since the key was resolved *from* `iss`, and kept as a\n // backstop for a resolver that matches on something else. `audience` is\n // not redundant: `aud` is the presenter's claim, checked against the\n // configured value.\n issuer: issuer.issuer,\n audience: issuer.audience,\n clockTolerance: deps.clockSkewSeconds,\n // Injected clock, not jose's `Date.now()`, so expiry is testable\n currentDate: deps.clock.now(),\n };\n\n let verifiedPayload: Record<string, unknown>;\n try {\n const result = await jwtVerify(encodedJws, key, options);\n verifiedPayload = result.payload as Record<string, unknown>;\n } catch (cause) {\n throw ap2Rejected(classifyJoseFailure(cause), { ...context, cause });\n }\n\n requireFreshness(verifiedPayload, deps, context);\n\n let claims: Record<string, unknown>;\n try {\n // Against the VERIFIED payload: the decoded one would match disclosures\n // against digests nobody signed\n claims = (await getClaims(verifiedPayload, decoded.disclosures, hasher)) as Record<\n string,\n unknown\n >;\n } catch (cause) {\n // Where an appended disclosure that no digest references is refused\n throw ap2Rejected('malformed_presentation', { ...context, cause });\n }\n\n requireClosedCheckoutMandate(claims, context);\n\n return { issuer: issuer.issuer, claims, signedToken: encodedJws };\n}\n\n/**\n * Matched on jose's stable error `code`, not its message. A client is owed\n * \"expired\" versus \"did not verify\"; anything finer describes our checks back\n * to whoever is probing them.\n */\nfunction classifyJoseFailure(cause: unknown): 'expired' | 'wrong_audience' | 'invalid_signature' {\n const code = (cause as { code?: unknown })?.code;\n if (code === 'ERR_JWT_EXPIRED') return 'expired';\n if (code === 'ERR_JWT_CLAIM_VALIDATION_FAILED') {\n const claim = (cause as { claim?: unknown }).claim;\n if (claim === 'aud') return 'wrong_audience';\n if (claim === 'nbf' || claim === 'exp') return 'expired';\n }\n return 'invalid_signature';\n}\n\n/**\n * Required, not merely checked when present: jose validates a time claim only\n * if it is there, so a mandate omitting `exp` would verify and never expire\n */\nfunction requireFreshness(\n payload: Record<string, unknown>,\n deps: { readonly clock: Clock; readonly clockSkewSeconds: number },\n context: Ap2ErrorContext,\n): void {\n const exp = payload['exp'];\n const iat = payload['iat'];\n if (typeof exp !== 'number' || typeof iat !== 'number') {\n throw ap2Rejected('invalid_claims', context);\n }\n const nowSeconds = Math.floor(deps.clock.now().getTime() / 1000);\n // A future `iat` is a broken signer, or a mandate minted to outlive its own\n // expiry window\n if (iat > nowSeconds + deps.clockSkewSeconds) throw ap2Rejected('expired', context);\n}\n\n// Exactly `mandate.checkout.1`; see AP2_CHECKOUT_MANDATE_VCT for why\nfunction requireClosedCheckoutMandate(\n claims: Record<string, unknown>,\n context: Ap2ErrorContext,\n): void {\n if (claims['vct'] !== AP2_CHECKOUT_MANDATE_VCT) {\n throw ap2Rejected('unsupported_mandate_type', context);\n }\n}\n","/**\n * Static key resolution.\n *\n * Every key was written into `config.yaml` by an operator. No JWKS fetch, no\n * `jku`, no `x5u`. A mandate's `iss` and `kid` only choose *which* trusted key\n * verifies it; an unrecognized pair is refused, so a mandate can never\n * nominate its own signer.\n *\n * Not a \"try every key\" loop: that would make `kid` advisory and accept a\n * mandate that named a key it was not signed with.\n */\nimport { importJWK, type JWK } from 'jose';\nimport { AP2_SIGNING_ALGORITHM } from './constants';\nimport { type Ap2ErrorContext, ap2Rejected, ap2Unavailable } from './errors';\nimport type { Ap2TrustedIssuer } from './types';\n\n/** Named off `importJWK` because `CryptoKey` is a DOM type we do not load */\nexport type VerificationKey = Awaited<ReturnType<typeof importJWK>>;\n\nexport interface ResolvedKey {\n readonly issuer: Ap2TrustedIssuer;\n readonly key: VerificationKey;\n}\n\n/**\n * Resolves `(iss, kid)` against one configured issuer list. Caches the import\n * promise, not the key, so concurrent requests for a cold key share one import.\n */\nexport function createTrustStore(issuers: readonly Ap2TrustedIssuer[]) {\n const byIssuer = new Map(issuers.map((entry) => [entry.issuer, entry]));\n const imported = new Map<string, Promise<VerificationKey>>();\n\n return {\n /** Every trusted issuer id, for diagnostics. Never the keys themselves */\n issuerIds(): readonly string[] {\n return [...byIssuer.keys()];\n },\n\n async resolve(iss: unknown, kid: unknown, context: Ap2ErrorContext): Promise<ResolvedKey> {\n if (typeof iss !== 'string' || iss.length === 0) {\n throw ap2Rejected('invalid_claims', context);\n }\n const issuer = byIssuer.get(iss);\n if (issuer === undefined) throw ap2Rejected('untrusted_issuer', context);\n\n // Not defaulted to the issuer's only key: mid-rotation there are two,\n // and the gateway should not guess which one signed this\n if (typeof kid !== 'string' || kid.length === 0) {\n throw ap2Rejected('unknown_key', context);\n }\n const trusted = issuer.keys.find((candidate) => candidate.kid === kid);\n if (trusted === undefined) throw ap2Rejected('unknown_key', context);\n\n // JSON, not a joined string: both halves are operator-chosen and could\n // contain whatever separator we picked\n const cacheKey = JSON.stringify([iss, kid]);\n let pending = imported.get(cacheKey);\n if (pending === undefined) {\n pending = importJWK(trusted.jwk as JWK, AP2_SIGNING_ALGORITHM);\n imported.set(cacheKey, pending);\n }\n\n try {\n return { issuer, key: await pending };\n } catch (cause) {\n // Config already checked this JWK member by member, so reaching here\n // means our config is broken, not the mandate. Drop the cached\n // rejection so the next request retries the import.\n imported.delete(cacheKey);\n throw ap2Unavailable('configured verification key could not be imported', {\n ...context,\n cause,\n });\n }\n },\n };\n}\n\nexport type TrustStore = ReturnType<typeof createTrustStore>;\n","/**\n * The Direct Checkout Mandate verifier: mandate signature first, then the\n * merchant checkout JWT it binds. Either stage failing is a refusal.\n *\n * What this proves is narrow. A trusted issuer signed this mandate, it has not\n * expired, it is addressed to us, and it binds a checkout document the\n * merchant signed. It does NOT prove the mandate authorizes the purchase in\n * front of us: that is `bindMandateToPurchase`, and a caller treating this as\n * permission to settle has skipped it.\n */\nimport type { Clock } from '../../core';\nimport { verifyCheckoutJwt } from './checkout-jwt';\nimport { type Ap2ErrorContext, ap2Rejected } from './errors';\nimport { verifyMandate } from './sd-jwt';\nimport { sha256 } from './sha256';\nimport { createTrustStore } from './trust';\nimport type { EnabledAp2Config, VerifiedCheckoutMandate } from './types';\n\nexport interface Ap2VerifierOptions {\n readonly config: EnabledAp2Config;\n readonly clock: Clock;\n}\n\nexport interface Ap2MandateVerifier {\n verify(presentation: string, context?: Ap2ErrorContext): Promise<VerifiedCheckoutMandate>;\n /** Trusted issuer ids, for the provider's health detail. Never keys */\n trustedIssuers(): { readonly mandate: readonly string[]; readonly checkout: readonly string[] };\n}\n\n/**\n * Algorithm-prefixed so a future digest change is visible in stored references\n * rather than silently producing unequal values for one mandate\n */\nfunction mandateReference(signedToken: string): string {\n return `sha256:${sha256(signedToken).toString('base64url')}`;\n}\n\nexport function createAp2MandateVerifier(options: Ap2VerifierOptions): Ap2MandateVerifier {\n // Two stores, not one list: signing the merchant's checkout documents must\n // not confer the power to issue mandates\n const mandateTrust = createTrustStore(options.config.trust.mandateIssuers);\n const checkoutTrust = createTrustStore(options.config.trust.checkoutIssuers);\n const deps = { clock: options.clock, clockSkewSeconds: options.config.clockSkewSeconds };\n\n return {\n async verify(\n presentation: string,\n context: Ap2ErrorContext = {},\n ): Promise<VerifiedCheckoutMandate> {\n if (typeof presentation !== 'string' || presentation.length === 0) {\n throw ap2Rejected('malformed_presentation', context);\n }\n\n const mandate = await verifyMandate(presentation, { ...deps, trust: mandateTrust }, context);\n const checkout = await verifyCheckoutJwt(\n mandate.claims,\n { ...deps, trust: checkoutTrust },\n context,\n );\n\n return {\n reference: mandateReference(mandate.signedToken),\n mandateIssuer: mandate.issuer,\n checkoutIssuer: checkout.issuer,\n checkoutJwtId: checkout.jwtId,\n checkoutClaims: checkout.claims,\n };\n },\n\n trustedIssuers() {\n return { mandate: mandateTrust.issuerIds(), checkout: checkoutTrust.issuerIds() };\n },\n };\n}\n","/**\n * The AP2 authorization provider: the seam between core's generic contract and\n * the mandate machinery.\n *\n * It owns its replay store, so whoever creates it must call `close()`:\n * `createGateway` does not close authorization providers.\n */\nimport type {\n AdapterHealth,\n AuthorizationFinalizeContext,\n AuthorizationProvider,\n AuthorizationRequirement,\n AuthorizationVerification,\n AuthorizationVerificationContext,\n Clock,\n Logger,\n} from '../../core';\nimport { NOOP_LOGGER, systemClock } from '../../core';\nimport { PACKAGE_VERSION } from '../../version';\nimport { AP2_CHECKOUT_PROFILE, AP2_SPEC_VERSION } from './constants';\nimport { buildAp2Descriptor } from './descriptor';\nimport { type Ap2ErrorContext, ap2Replayed, ap2Unavailable } from './errors';\nimport { bindMandateToPurchase } from './profile';\nimport { type Ap2ReplayStore, createAp2ReplayStore } from './replay-store';\nimport type { EnabledAp2Config } from './types';\nimport { createAp2MandateVerifier } from './verifier';\n\nexport interface Ap2AuthorizationProviderOptions {\n readonly config: EnabledAp2Config;\n readonly clock?: Clock;\n readonly logger?: Logger;\n /** Injectable so tests need not touch the filesystem */\n readonly replayStore?: Ap2ReplayStore;\n}\n\nexport interface Ap2AuthorizationProvider extends AuthorizationProvider {\n /** Closes the replay store */\n close(): void;\n}\n\nexport function createAp2AuthorizationProvider(\n options: Ap2AuthorizationProviderOptions,\n): Ap2AuthorizationProvider {\n const clock = options.clock ?? systemClock;\n const logger = options.logger ?? NOOP_LOGGER;\n\n const verifier = createAp2MandateVerifier({ config: options.config, clock });\n const replay =\n options.replayStore ?? createAp2ReplayStore({ path: options.config.replay.path, logger });\n\n const requirement: AuthorizationRequirement = {\n method: 'ap2',\n version: AP2_SPEC_VERSION,\n profile: AP2_CHECKOUT_PROFILE,\n };\n\n async function verifyAndReserve(\n context: AuthorizationVerificationContext,\n ): Promise<AuthorizationVerification> {\n const errorContext: Ap2ErrorContext = {\n requestId: context.requestId,\n resourceId: context.resourceId,\n };\n\n const mandate = await verifier.verify(context.submission.payload, errorContext);\n // Before reserving, not after: a mandate that does not authorize this\n // purchase must stay spendable on the purchase it does authorize\n await bindMandateToPurchase(mandate, context, errorContext);\n\n let reservation: ReturnType<Ap2ReplayStore['reserve']>;\n try {\n reservation = replay.reserve({\n reference: mandate.reference,\n checkoutJti: mandate.checkoutJwtId,\n mandateIssuer: mandate.mandateIssuer,\n checkoutIssuer: mandate.checkoutIssuer,\n resourceId: context.resourceId,\n requestId: context.requestId,\n });\n } catch (cause) {\n throw ap2Unavailable('replay store could not be written', { ...errorContext, cause });\n }\n\n if (reservation.kind === 'replayed') {\n throw ap2Replayed(reservation.state, errorContext);\n }\n\n return {\n status: 'verified',\n method: 'ap2',\n reference: mandate.reference,\n // The reservation handle is the reference itself, so the two can never\n // name different mandates\n reservationId: mandate.reference,\n // Opaque identifiers an operator can reconcile with. Never a claim from\n // the mandate: those carry the buyer's purchase and their personal data.\n // `checkoutId`, not `checkoutJwtId` - the receipt store redacts any key\n // that reads as secret-shaped, and \"jwt\" is on that list.\n metadata: {\n mandateIssuer: mandate.mandateIssuer,\n checkoutIssuer: mandate.checkoutIssuer,\n checkoutId: mandate.checkoutJwtId,\n },\n };\n }\n\n const finalize = (\n action: 'consume' | 'release' | 'markUncertain',\n reservationId: string,\n context: AuthorizationFinalizeContext,\n ): void => {\n try {\n replay[action](reservationId);\n } catch (cause) {\n throw ap2Unavailable(`replay store could not record ${action}`, { ...context, cause });\n }\n };\n\n return {\n name: 'ap2',\n descriptor: buildAp2Descriptor(PACKAGE_VERSION),\n requirement,\n verifyAndReserve,\n\n async consume(reservationId, context) {\n finalize('consume', reservationId, context);\n },\n async release(reservationId, context) {\n finalize('release', reservationId, context);\n },\n async markUncertain(reservationId, context) {\n finalize('markUncertain', reservationId, context);\n },\n\n async health(): Promise<AdapterHealth> {\n const startedAt = clock.monotonicMs();\n const checkedAt = clock.nowIso();\n let available = true;\n try {\n // A read against the real table, so a database that opened but cannot\n // be queried is caught here rather than on the first purchase\n replay.stateOf('health-probe');\n } catch {\n available = false;\n }\n const durationMs = Math.round(clock.monotonicMs() - startedAt);\n if (!available) {\n // A fixed token, never a sentence built from the caught error\n return { status: 'fail', checkedAt, durationMs, detail: 'replay-store-unavailable' };\n }\n const trusted = verifier.trustedIssuers();\n return {\n status: 'pass',\n checkedAt,\n durationMs,\n detail: `mandate-issuers=${trusted.mandate.length} checkout-issuers=${trusted.checkout.length}`,\n };\n },\n\n close() {\n replay.close();\n },\n };\n}\n"]}
|