From e13cbe5f437df82e1cd56630b60a04628da68847 Mon Sep 17 00:00:00 2001 From: Radovenchyk Date: Tue, 6 Oct 2026 08:27:22 +0300 Subject: [PATCH 1/4] docs: fix same undefined variable in ack-id package README --- packages/ack-id/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ack-id/README.md b/packages/ack-id/README.md index 395fa1b..e271389 100644 --- a/packages/ack-id/README.md +++ b/packages/ack-id/README.md @@ -49,7 +49,7 @@ const resolver = getDidResolver() // Verify the credential using verification logic from vc package. try { - await verifyParsedCredential(controllerCredential, { + await verifyParsedCredential(credential, { resolver, verifiers: [verifier], trustedIssuers: [controllerDid], // Optional: list of trusted issuers From 76f6534a32964398b2281cfc4ecbbdb3ce9a84cb Mon Sep 17 00:00:00 2001 From: Radovenchyk Date: Tue, 6 Oct 2026 12:16:59 +0000 Subject: [PATCH 2/4] docs(ack-id): sign and parse the credential before verifying it createControllerCredential returns an unsigned credential, and the documented flow did not sign or parse it before verification. verifyParsedCredential requires a proof and throws InvalidProofError otherwise. Sign the credential with signCredential, pass the returned JWT to parseJwtCredential, then verify the parsed credential. Addresses CodeRabbit review on #242. --- packages/ack-id/README.md | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/packages/ack-id/README.md b/packages/ack-id/README.md index e271389..3247e27 100644 --- a/packages/ack-id/README.md +++ b/packages/ack-id/README.md @@ -41,15 +41,27 @@ const credential = createControllerCredential({ ```ts import { getControllerClaimVerifier } from "@agentcommercekit/ack-id" import { getDidResolver } from "@agentcommercekit/did" -import { verifyParsedCredential } from "@agentcommercekit/vc" +import { createJwtSigner } from "@agentcommercekit/jwt" +import { generateKeypair } from "@agentcommercekit/keys" +import { + parseJwtCredential, + signCredential, + verifyParsedCredential, +} from "@agentcommercekit/vc" // Get the verifier for controller credentials const verifier = getControllerClaimVerifier() const resolver = getDidResolver() +// Sign the credential, then parse the resulting JWT back into a +// verifiable credential — verifyParsedCredential requires a proof. +const keypair = await generateKeypair("secp256k1") +const jwt = await signCredential(credential, createJwtSigner(keypair)) +const parsedCredential = await parseJwtCredential(jwt, resolver) + // Verify the credential using verification logic from vc package. try { - await verifyParsedCredential(credential, { + await verifyParsedCredential(parsedCredential, { resolver, verifiers: [verifier], trustedIssuers: [controllerDid], // Optional: list of trusted issuers From 9e6d95e90de35ac7d8f446865e0061ec548fef1b Mon Sep 17 00:00:00 2001 From: Radovenchyk Date: Wed, 7 Oct 2026 06:01:37 +0000 Subject: [PATCH 3/4] docs(ack-id): derive controller DID from keypair and register it Pass a proper Signer object ({did, signer, alg}) to signCredential instead of a bare JwtSigner function. Also derive controllerDid from the signing keypair via createDidWebDocumentFromKeypair and register the resulting DID document with resolver.addToCache before parsing the JWT, so the resolver can find the verification key. Addresses CodeRabbit review comments on #242. --- packages/ack-id/README.md | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/packages/ack-id/README.md b/packages/ack-id/README.md index 3247e27..c42f0ee 100644 --- a/packages/ack-id/README.md +++ b/packages/ack-id/README.md @@ -20,10 +20,17 @@ pnpm add @agentcommercekit/ack-id ```ts import { createControllerCredential } from "@agentcommercekit/ack-id" -import { createDidWebUri } from "@agentcommercekit/did" +import { createDidWebDocumentFromKeypair, createDidWebUri } from "@agentcommercekit/did" +import { generateKeypair } from "@agentcommercekit/keys" -// Create DIDs for agent and controller -const controllerDid = createDidWebUri("https://controller.example.com") +// Create a keypair and a did:web document for the controller, and a +// plain DID for the agent (no keypair needed on this side for this example) +const controllerKeypair = await generateKeypair("secp256k1") +const { did: controllerDid, didDocument: controllerDidDocument } = + createDidWebDocumentFromKeypair({ + keypair: controllerKeypair, + baseUrl: "https://controller.example.com", + }) const agentDid = createDidWebUri("https://agent.example.com") // Create a credential establishing the controller relationship @@ -41,8 +48,7 @@ const credential = createControllerCredential({ ```ts import { getControllerClaimVerifier } from "@agentcommercekit/ack-id" import { getDidResolver } from "@agentcommercekit/did" -import { createJwtSigner } from "@agentcommercekit/jwt" -import { generateKeypair } from "@agentcommercekit/keys" +import { createJwtSigner, curveToJwtAlgorithm } from "@agentcommercekit/jwt" import { parseJwtCredential, signCredential, @@ -53,10 +59,17 @@ import { const verifier = getControllerClaimVerifier() const resolver = getDidResolver() +// Register the controller's DID document so the resolver can find its +// key when verifying the signature below. +resolver.addToCache(controllerDid, controllerDidDocument) + // Sign the credential, then parse the resulting JWT back into a // verifiable credential — verifyParsedCredential requires a proof. -const keypair = await generateKeypair("secp256k1") -const jwt = await signCredential(credential, createJwtSigner(keypair)) +const jwt = await signCredential(credential, { + did: controllerDid, + signer: createJwtSigner(controllerKeypair), + alg: curveToJwtAlgorithm(controllerKeypair.curve), +}) const parsedCredential = await parseJwtCredential(jwt, resolver) // Verify the credential using verification logic from vc package. From b57669c6fae4f8e45d15d17207a074b2d8795988 Mon Sep 17 00:00:00 2001 From: Radovenchyk Date: Wed, 7 Oct 2026 11:33:04 +0000 Subject: [PATCH 4/4] docs(ack-id): give the agent a DID document declaring its controller MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit getControllerClaimVerifier resolves the credential subject's (agent's) DID document and requires it to declare a controller field. The example only registered the controller's document, so verification would fail resolving the agent's did:web URI. Every did:web document also requires a public key, so the agent needs its own keypair too — give it one and register its document alongside the controller's. Addresses CodeRabbit review comment on #242. --- packages/ack-id/README.md | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/packages/ack-id/README.md b/packages/ack-id/README.md index c42f0ee..d96bcdb 100644 --- a/packages/ack-id/README.md +++ b/packages/ack-id/README.md @@ -20,18 +20,25 @@ pnpm add @agentcommercekit/ack-id ```ts import { createControllerCredential } from "@agentcommercekit/ack-id" -import { createDidWebDocumentFromKeypair, createDidWebUri } from "@agentcommercekit/did" +import { createDidWebDocumentFromKeypair } from "@agentcommercekit/did" import { generateKeypair } from "@agentcommercekit/keys" -// Create a keypair and a did:web document for the controller, and a -// plain DID for the agent (no keypair needed on this side for this example) +// Create keypairs and did:web documents for the controller and agent. +// The agent's document declares controllerDid as its controller. const controllerKeypair = await generateKeypair("secp256k1") const { did: controllerDid, didDocument: controllerDidDocument } = createDidWebDocumentFromKeypair({ keypair: controllerKeypair, baseUrl: "https://controller.example.com", }) -const agentDid = createDidWebUri("https://agent.example.com") + +const agentKeypair = await generateKeypair("secp256k1") +const { did: agentDid, didDocument: agentDidDocument } = + createDidWebDocumentFromKeypair({ + keypair: agentKeypair, + baseUrl: "https://agent.example.com", + controller: controllerDid, + }) // Create a credential establishing the controller relationship const credential = createControllerCredential({ @@ -59,8 +66,9 @@ import { const verifier = getControllerClaimVerifier() const resolver = getDidResolver() -// Register the controller's DID document so the resolver can find its -// key when verifying the signature below. +// Register both DID documents so the resolver can find them when +// verifying the credential's subject (agent) and issuer (controller). +resolver.addToCache(agentDid, agentDidDocument) resolver.addToCache(controllerDid, controllerDidDocument) // Sign the credential, then parse the resulting JWT back into a