@payclaw/badge 0.7.1 → 0.8.0

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.
Files changed (41) hide show
  1. package/README.md +68 -2
  2. package/dist/api/client.js +1 -1
  3. package/dist/api/client.js.map +1 -1
  4. package/dist/index.d.ts +1 -1
  5. package/dist/index.js +24 -11
  6. package/dist/index.js.map +1 -1
  7. package/dist/lib/device-auth.js +11 -3
  8. package/dist/lib/device-auth.js.map +1 -1
  9. package/dist/lib/parse-outcome.js +1 -0
  10. package/dist/lib/parse-outcome.js.map +1 -1
  11. package/dist/lib/report-badge-presented-handler.d.ts +7 -1
  12. package/dist/lib/report-badge-presented-handler.js +13 -2
  13. package/dist/lib/report-badge-presented-handler.js.map +1 -1
  14. package/dist/lib/report-badge.d.ts +1 -1
  15. package/dist/lib/report-badge.js +3 -1
  16. package/dist/lib/report-badge.js.map +1 -1
  17. package/dist/lib/storage.d.ts +5 -0
  18. package/dist/lib/storage.js +28 -0
  19. package/dist/lib/storage.js.map +1 -1
  20. package/dist/lib/ucp-manifest.d.ts +32 -0
  21. package/dist/lib/ucp-manifest.js +117 -0
  22. package/dist/lib/ucp-manifest.js.map +1 -0
  23. package/dist/lib/ucp-manifest.test.d.ts +1 -0
  24. package/dist/lib/ucp-manifest.test.js +92 -0
  25. package/dist/lib/ucp-manifest.test.js.map +1 -0
  26. package/dist/sampling.d.ts +4 -0
  27. package/dist/sampling.js +43 -6
  28. package/dist/sampling.js.map +1 -1
  29. package/dist/sampling.test.d.ts +1 -0
  30. package/dist/sampling.test.js +150 -0
  31. package/dist/sampling.test.js.map +1 -0
  32. package/dist/tools/getAgentIdentity.d.ts +9 -1
  33. package/dist/tools/getAgentIdentity.js +67 -10
  34. package/dist/tools/getAgentIdentity.js.map +1 -1
  35. package/dist/verify.d.ts +34 -0
  36. package/dist/verify.js +161 -0
  37. package/dist/verify.js.map +1 -0
  38. package/dist/verify.test.d.ts +1 -0
  39. package/dist/verify.test.js +177 -0
  40. package/dist/verify.test.js.map +1 -0
  41. package/package.json +7 -3
package/dist/verify.js ADDED
@@ -0,0 +1,161 @@
1
+ /**
2
+ * verify() — merchant-side Badge JWT verification.
3
+ *
4
+ * Import: `import { verify } from '@payclaw/badge/verify'`
5
+ *
6
+ * Fetches PayClaw's JWKS once, caches it, verifies ES256 signature locally.
7
+ * Returns decoded identity or null. Never throws.
8
+ * Works in Node.js 18+ and Cloudflare Workers (Web Crypto API only).
9
+ * Zero runtime dependencies.
10
+ */
11
+ let jwksCache = null;
12
+ let jwksCacheUri = null;
13
+ // ── Helpers ──
14
+ function base64urlDecode(str) {
15
+ const padded = str.replace(/-/g, "+").replace(/_/g, "/");
16
+ const padding = "=".repeat((4 - (padded.length % 4)) % 4);
17
+ const binary = atob(padded + padding);
18
+ const bytes = new Uint8Array(binary.length);
19
+ for (let i = 0; i < binary.length; i++) {
20
+ bytes[i] = binary.charCodeAt(i);
21
+ }
22
+ return bytes;
23
+ }
24
+ function decodeJWT(token) {
25
+ const parts = token.split(".");
26
+ if (parts.length !== 3)
27
+ return null;
28
+ try {
29
+ const header = JSON.parse(new TextDecoder().decode(base64urlDecode(parts[0])));
30
+ const payload = JSON.parse(new TextDecoder().decode(base64urlDecode(parts[1])));
31
+ const signatureBytes = base64urlDecode(parts[2]);
32
+ const signedPart = `${parts[0]}.${parts[1]}`;
33
+ return { header, payload, signatureBytes, signedPart };
34
+ }
35
+ catch {
36
+ return null;
37
+ }
38
+ }
39
+ async function importJWK(jwk) {
40
+ try {
41
+ return await globalThis.crypto.subtle.importKey("jwk", { kty: jwk.kty, crv: jwk.crv, x: jwk.x, y: jwk.y }, { name: "ECDSA", namedCurve: "P-256" }, false, ["verify"]);
42
+ }
43
+ catch {
44
+ return null;
45
+ }
46
+ }
47
+ async function fetchJWKS(uri) {
48
+ const keys = new Map();
49
+ let res;
50
+ try {
51
+ res = await fetch(uri, { signal: AbortSignal.timeout(5000) });
52
+ }
53
+ catch (e) {
54
+ console.warn("[PayClaw verify] JWKS fetch failed:", e);
55
+ return keys;
56
+ }
57
+ if (!res.ok) {
58
+ console.warn(`[PayClaw verify] JWKS fetch returned ${res.status}`);
59
+ return keys;
60
+ }
61
+ let data;
62
+ try {
63
+ data = await res.json();
64
+ }
65
+ catch {
66
+ console.warn("[PayClaw verify] JWKS response is not valid JSON");
67
+ return keys;
68
+ }
69
+ // Extract signing_keys[] from UCP profile or keys[] from standard JWKS
70
+ const rawKeys = (Array.isArray(data.signing_keys) ? data.signing_keys :
71
+ Array.isArray(data.keys) ? data.keys :
72
+ []);
73
+ for (const jwk of rawKeys) {
74
+ if (typeof jwk.kid !== "string" || jwk.kty !== "EC" || jwk.crv !== "P-256")
75
+ continue;
76
+ const cryptoKey = await importJWK(jwk);
77
+ if (cryptoKey)
78
+ keys.set(jwk.kid, cryptoKey);
79
+ }
80
+ return keys;
81
+ }
82
+ async function getCachedKeys(uri, cacheTtlMs) {
83
+ const now = Date.now();
84
+ if (jwksCache && jwksCacheUri === uri && (now - jwksCache.fetchedAt) < cacheTtlMs) {
85
+ return jwksCache.keys;
86
+ }
87
+ const keys = await fetchJWKS(uri);
88
+ if (keys.size > 0) {
89
+ jwksCache = { keys, fetchedAt: now };
90
+ jwksCacheUri = uri;
91
+ }
92
+ return keys;
93
+ }
94
+ // ── Main ──
95
+ const DEFAULT_JWKS_URI = "https://payclaw.io/.well-known/ucp";
96
+ const DEFAULT_CACHE_TTL_MS = 3600000; // 1 hour
97
+ const DEFAULT_CLOCK_TOLERANCE_SEC = 30;
98
+ export async function verify(token, options) {
99
+ try {
100
+ if (!token || typeof token !== "string")
101
+ return null;
102
+ const decoded = decodeJWT(token);
103
+ if (!decoded)
104
+ return null;
105
+ const { header, payload, signatureBytes, signedPart } = decoded;
106
+ // Extract kid
107
+ const kid = header.kid;
108
+ if (typeof kid !== "string") {
109
+ console.warn("[PayClaw verify] Token has no kid in header");
110
+ return null;
111
+ }
112
+ // Check alg
113
+ if (header.alg !== "ES256")
114
+ return null;
115
+ // Get keys
116
+ const jwksUri = options?.jwksUri ?? DEFAULT_JWKS_URI;
117
+ const cacheTtlMs = options?.cacheTtlMs ?? DEFAULT_CACHE_TTL_MS;
118
+ const keys = await getCachedKeys(jwksUri, cacheTtlMs);
119
+ const key = keys.get(kid);
120
+ if (!key)
121
+ return null;
122
+ // Verify signature
123
+ const signedData = new TextEncoder().encode(signedPart);
124
+ const sigBuf = new ArrayBuffer(signatureBytes.byteLength);
125
+ new Uint8Array(sigBuf).set(signatureBytes);
126
+ const dataBuf = new ArrayBuffer(signedData.byteLength);
127
+ new Uint8Array(dataBuf).set(signedData);
128
+ const valid = await globalThis.crypto.subtle.verify({ name: "ECDSA", hash: "SHA-256" }, key, sigBuf, dataBuf);
129
+ if (!valid)
130
+ return null;
131
+ // Check expiry
132
+ const clockToleranceSec = options?.clockToleranceSec ?? DEFAULT_CLOCK_TOLERANCE_SEC;
133
+ const now = Math.floor(Date.now() / 1000);
134
+ const exp = payload.exp;
135
+ if (typeof exp === "number" && now > exp + clockToleranceSec)
136
+ return null;
137
+ // Build identity
138
+ return {
139
+ userId: String(payload.sub ?? ""),
140
+ agentId: String(payload.agent_id ?? payload.agentId ?? ""),
141
+ intent: String(payload.intent ?? ""),
142
+ scopes: Array.isArray(payload.scopes) ? payload.scopes.map(String) : [],
143
+ merchantDomain: typeof payload.merchant_domain === "string" ? payload.merchant_domain : undefined,
144
+ issuedAt: typeof payload.iat === "number" ? payload.iat : 0,
145
+ expiresAt: typeof payload.exp === "number" ? payload.exp : 0,
146
+ kid,
147
+ };
148
+ }
149
+ catch {
150
+ return null;
151
+ }
152
+ }
153
+ /**
154
+ * Reset the JWKS cache. Useful for testing.
155
+ * @internal
156
+ */
157
+ export function _resetCache() {
158
+ jwksCache = null;
159
+ jwksCacheUri = null;
160
+ }
161
+ //# sourceMappingURL=verify.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verify.js","sourceRoot":"","sources":["../src/verify.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,177 @@
1
+ import { describe, it, expect, beforeAll, beforeEach, afterEach, vi } from "vitest";
2
+ import { verify, _resetCache } from "./verify.js";
3
+ // ── Key pair generation ──
4
+ let privateKey;
5
+ let publicJWK;
6
+ const KID = "test-key-v1";
7
+ beforeAll(async () => {
8
+ const pair = await globalThis.crypto.subtle.generateKey({ name: "ECDSA", namedCurve: "P-256" }, true, ["sign", "verify"]);
9
+ privateKey = pair.privateKey;
10
+ const pubExported = await globalThis.crypto.subtle.exportKey("jwk", pair.publicKey);
11
+ publicJWK = { ...pubExported, kid: KID, use: "sig", alg: "ES256" };
12
+ });
13
+ // ── JWT helpers ──
14
+ function base64urlEncode(data) {
15
+ const bytes = typeof data === "string" ? new TextEncoder().encode(data) : data;
16
+ let binary = "";
17
+ for (const b of bytes)
18
+ binary += String.fromCharCode(b);
19
+ return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
20
+ }
21
+ async function signJWT(payload, options) {
22
+ const header = { alg: options?.alg ?? "ES256", typ: "JWT", kid: options?.kid ?? KID };
23
+ const headerB64 = base64urlEncode(JSON.stringify(header));
24
+ const payloadB64 = base64urlEncode(JSON.stringify(payload));
25
+ const signedPart = `${headerB64}.${payloadB64}`;
26
+ const data = new TextEncoder().encode(signedPart);
27
+ const dataBuf = new ArrayBuffer(data.byteLength);
28
+ new Uint8Array(dataBuf).set(data);
29
+ const sig = await globalThis.crypto.subtle.sign({ name: "ECDSA", hash: "SHA-256" }, privateKey, dataBuf);
30
+ const sigB64 = base64urlEncode(new Uint8Array(sig));
31
+ return `${signedPart}.${sigB64}`;
32
+ }
33
+ function validPayload(overrides) {
34
+ const now = Math.floor(Date.now() / 1000);
35
+ return {
36
+ sub: "user-123",
37
+ agent_id: "agent-456",
38
+ intent: "buy coffee",
39
+ scopes: ["checkout:complete"],
40
+ merchant_domain: "starbucks.com",
41
+ iat: now - 60,
42
+ exp: now + 300,
43
+ ...overrides,
44
+ };
45
+ }
46
+ // ── Mock fetch ──
47
+ function mockFetchJWKS() {
48
+ return vi.spyOn(globalThis, "fetch").mockResolvedValue(new Response(JSON.stringify({ signing_keys: [publicJWK] }), { status: 200 }));
49
+ }
50
+ // ── Tests ──
51
+ describe("verify()", () => {
52
+ beforeEach(() => {
53
+ _resetCache();
54
+ });
55
+ afterEach(() => {
56
+ vi.restoreAllMocks();
57
+ });
58
+ it("verifies a valid token and returns PayClawIdentity", async () => {
59
+ const fetchMock = mockFetchJWKS();
60
+ const token = await signJWT(validPayload());
61
+ const result = await verify(token, { jwksUri: "https://test.local/.well-known/ucp" });
62
+ expect(result).not.toBeNull();
63
+ const identity = result;
64
+ expect(identity.userId).toBe("user-123");
65
+ expect(identity.agentId).toBe("agent-456");
66
+ expect(identity.intent).toBe("buy coffee");
67
+ expect(identity.scopes).toEqual(["checkout:complete"]);
68
+ expect(identity.merchantDomain).toBe("starbucks.com");
69
+ expect(identity.kid).toBe(KID);
70
+ expect(identity.issuedAt).toBeGreaterThan(0);
71
+ expect(identity.expiresAt).toBeGreaterThan(0);
72
+ expect(fetchMock).toHaveBeenCalledOnce();
73
+ });
74
+ it("returns null for expired token", async () => {
75
+ mockFetchJWKS();
76
+ const token = await signJWT(validPayload({ exp: Math.floor(Date.now() / 1000) - 120 }));
77
+ const result = await verify(token, { jwksUri: "https://test.local/.well-known/ucp" });
78
+ expect(result).toBeNull();
79
+ });
80
+ it("returns null for tampered token", async () => {
81
+ mockFetchJWKS();
82
+ const token = await signJWT(validPayload());
83
+ // Tamper with the payload (change sub) but keep original signature
84
+ const parts = token.split(".");
85
+ const tamperedPayload = base64urlEncode(JSON.stringify({ ...validPayload(), sub: "hacker" }));
86
+ const tampered = `${parts[0]}.${tamperedPayload}.${parts[2]}`;
87
+ const result = await verify(tampered, { jwksUri: "https://test.local/.well-known/ucp" });
88
+ expect(result).toBeNull();
89
+ });
90
+ it("returns null for unknown kid", async () => {
91
+ mockFetchJWKS();
92
+ const token = await signJWT(validPayload(), { kid: "unknown-kid" });
93
+ const result = await verify(token, { jwksUri: "https://test.local/.well-known/ucp" });
94
+ expect(result).toBeNull();
95
+ });
96
+ it("returns null for undefined input", async () => {
97
+ const result = await verify(undefined);
98
+ expect(result).toBeNull();
99
+ });
100
+ it("returns null for empty string input", async () => {
101
+ const result = await verify("");
102
+ expect(result).toBeNull();
103
+ });
104
+ it("returns null for malformed JWT (not 3 segments)", async () => {
105
+ mockFetchJWKS();
106
+ const result = await verify("not.a.valid.jwt.token", { jwksUri: "https://test.local/.well-known/ucp" });
107
+ expect(result).toBeNull();
108
+ });
109
+ it("returns null for malformed JWT (2 segments)", async () => {
110
+ const result = await verify("header.payload");
111
+ expect(result).toBeNull();
112
+ });
113
+ it("caches JWKS — does not re-fetch on second call", async () => {
114
+ const fetchMock = mockFetchJWKS();
115
+ const token1 = await signJWT(validPayload());
116
+ const token2 = await signJWT(validPayload({ sub: "user-789" }));
117
+ await verify(token1, { jwksUri: "https://test.local/.well-known/ucp" });
118
+ await verify(token2, { jwksUri: "https://test.local/.well-known/ucp" });
119
+ expect(fetchMock).toHaveBeenCalledOnce();
120
+ });
121
+ it("re-fetches JWKS after cache expires", async () => {
122
+ const fetchMock = mockFetchJWKS();
123
+ const token = await signJWT(validPayload());
124
+ // First call with very short TTL
125
+ await verify(token, { jwksUri: "https://test.local/.well-known/ucp", cacheTtlMs: 1 });
126
+ // Wait for cache to expire
127
+ await new Promise((r) => setTimeout(r, 10));
128
+ await verify(token, { jwksUri: "https://test.local/.well-known/ucp", cacheTtlMs: 1 });
129
+ expect(fetchMock).toHaveBeenCalledTimes(2);
130
+ });
131
+ it("returns null when JWKS endpoint is unreachable", async () => {
132
+ vi.spyOn(globalThis, "fetch").mockRejectedValue(new Error("network error"));
133
+ const token = await signJWT(validPayload());
134
+ const result = await verify(token, { jwksUri: "https://test.local/.well-known/ucp" });
135
+ expect(result).toBeNull();
136
+ });
137
+ it("returns null for token with no kid in header", async () => {
138
+ mockFetchJWKS();
139
+ // Build a JWT manually without kid
140
+ const header = { alg: "ES256", typ: "JWT" };
141
+ const payload = validPayload();
142
+ const headerB64 = base64urlEncode(JSON.stringify(header));
143
+ const payloadB64 = base64urlEncode(JSON.stringify(payload));
144
+ const signedPart = `${headerB64}.${payloadB64}`;
145
+ const data = new TextEncoder().encode(signedPart);
146
+ const dataBuf = new ArrayBuffer(data.byteLength);
147
+ new Uint8Array(dataBuf).set(data);
148
+ const sig = await globalThis.crypto.subtle.sign({ name: "ECDSA", hash: "SHA-256" }, privateKey, dataBuf);
149
+ const token = `${signedPart}.${base64urlEncode(new Uint8Array(sig))}`;
150
+ const result = await verify(token, { jwksUri: "https://test.local/.well-known/ucp" });
151
+ expect(result).toBeNull();
152
+ });
153
+ it("respects clockToleranceSec for recently expired tokens", async () => {
154
+ mockFetchJWKS();
155
+ // Token expired 10 seconds ago, tolerance is 30
156
+ const token = await signJWT(validPayload({ exp: Math.floor(Date.now() / 1000) - 10 }));
157
+ const result = await verify(token, {
158
+ jwksUri: "https://test.local/.well-known/ucp",
159
+ clockToleranceSec: 30,
160
+ });
161
+ expect(result).not.toBeNull();
162
+ });
163
+ it("returns identity with merchantDomain when present", async () => {
164
+ mockFetchJWKS();
165
+ const token = await signJWT(validPayload({ merchant_domain: "example.com" }));
166
+ const result = await verify(token, { jwksUri: "https://test.local/.well-known/ucp" });
167
+ expect(result?.merchantDomain).toBe("example.com");
168
+ });
169
+ it("returns identity without merchantDomain when absent", async () => {
170
+ mockFetchJWKS();
171
+ const { merchant_domain: _, ...payloadNoMerchant } = validPayload();
172
+ const token = await signJWT(payloadNoMerchant);
173
+ const result = await verify(token, { jwksUri: "https://test.local/.well-known/ucp" });
174
+ expect(result?.merchantDomain).toBeUndefined();
175
+ });
176
+ });
177
+ //# sourceMappingURL=verify.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verify.test.js","sourceRoot":"","sources":["../src/verify.test.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,9 +1,13 @@
1
1
  {
2
2
  "name": "@payclaw/badge",
3
- "version": "0.7.1",
3
+ "version": "0.8.0",
4
4
  "description": "Prove your agent is an authorized actor, not a bot. MCP-native identity declaration for agent commerce.",
5
5
  "bin": "dist/index.js",
6
6
  "main": "dist/index.js",
7
+ "exports": {
8
+ ".": "./dist/index.js",
9
+ "./verify": "./dist/verify.js"
10
+ },
7
11
  "type": "module",
8
12
  "engines": {
9
13
  "node": ">=20.0.0"
@@ -20,8 +24,8 @@
20
24
  "prepublishOnly": "npm run build"
21
25
  },
22
26
  "dependencies": {
23
- "@modelcontextprotocol/sdk": "^1.0.0",
24
- "zod": "^4.3.6"
27
+ "@modelcontextprotocol/sdk": "^1.27.1",
28
+ "zod": "^3.24.0 || ^4.0.0"
25
29
  },
26
30
  "devDependencies": {
27
31
  "@types/node": "^20.0.0",