@kya-os/mcp 1.6.1 → 1.9.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 (282) hide show
  1. package/CHANGELOG.md +117 -0
  2. package/README.md +228 -3
  3. package/dist/authz/index.d.ts +1 -0
  4. package/dist/authz/index.d.ts.map +1 -1
  5. package/dist/authz/index.js +1 -0
  6. package/dist/authz/index.js.map +1 -1
  7. package/dist/authz/oidc/oidc-adapter.d.ts +10 -2
  8. package/dist/authz/oidc/oidc-adapter.d.ts.map +1 -1
  9. package/dist/authz/oidc/oidc-adapter.js +18 -9
  10. package/dist/authz/oidc/oidc-adapter.js.map +1 -1
  11. package/dist/authz/oidc/pending-flow-store.d.ts +80 -0
  12. package/dist/authz/oidc/pending-flow-store.d.ts.map +1 -0
  13. package/dist/authz/oidc/pending-flow-store.js +82 -0
  14. package/dist/authz/oidc/pending-flow-store.js.map +1 -0
  15. package/dist/card/build.d.ts +41 -0
  16. package/dist/card/build.d.ts.map +1 -0
  17. package/dist/card/build.js +47 -0
  18. package/dist/card/build.js.map +1 -0
  19. package/dist/card/builder.d.ts +99 -0
  20. package/dist/card/builder.d.ts.map +1 -0
  21. package/dist/card/builder.js +147 -0
  22. package/dist/card/builder.js.map +1 -0
  23. package/dist/card/cimd.d.ts +92 -0
  24. package/dist/card/cimd.d.ts.map +1 -0
  25. package/dist/card/cimd.js +225 -0
  26. package/dist/card/cimd.js.map +1 -0
  27. package/dist/card/delegation.d.ts +145 -0
  28. package/dist/card/delegation.d.ts.map +1 -0
  29. package/dist/card/delegation.js +293 -0
  30. package/dist/card/delegation.js.map +1 -0
  31. package/dist/card/emit.d.ts +133 -0
  32. package/dist/card/emit.d.ts.map +1 -0
  33. package/dist/card/emit.js +127 -0
  34. package/dist/card/emit.js.map +1 -0
  35. package/dist/card/index.d.ts +43 -0
  36. package/dist/card/index.d.ts.map +1 -0
  37. package/dist/card/index.js +46 -0
  38. package/dist/card/index.js.map +1 -0
  39. package/dist/card/middleware.d.ts +112 -0
  40. package/dist/card/middleware.d.ts.map +1 -0
  41. package/dist/card/middleware.js +121 -0
  42. package/dist/card/middleware.js.map +1 -0
  43. package/dist/card/proof/build.d.ts +22 -0
  44. package/dist/card/proof/build.d.ts.map +1 -0
  45. package/dist/card/proof/build.js +55 -0
  46. package/dist/card/proof/build.js.map +1 -0
  47. package/dist/card/proof/canonical.d.ts +66 -0
  48. package/dist/card/proof/canonical.d.ts.map +1 -0
  49. package/dist/card/proof/canonical.js +131 -0
  50. package/dist/card/proof/canonical.js.map +1 -0
  51. package/dist/card/proof/http-sig.d.ts +69 -0
  52. package/dist/card/proof/http-sig.d.ts.map +1 -0
  53. package/dist/card/proof/http-sig.js +101 -0
  54. package/dist/card/proof/http-sig.js.map +1 -0
  55. package/dist/card/proof/index.d.ts +25 -0
  56. package/dist/card/proof/index.d.ts.map +1 -0
  57. package/dist/card/proof/index.js +25 -0
  58. package/dist/card/proof/index.js.map +1 -0
  59. package/dist/card/proof/nonce-cache.d.ts +67 -0
  60. package/dist/card/proof/nonce-cache.d.ts.map +1 -0
  61. package/dist/card/proof/nonce-cache.js +88 -0
  62. package/dist/card/proof/nonce-cache.js.map +1 -0
  63. package/dist/card/proof/signer.d.ts +32 -0
  64. package/dist/card/proof/signer.d.ts.map +1 -0
  65. package/dist/card/proof/signer.js +59 -0
  66. package/dist/card/proof/signer.js.map +1 -0
  67. package/dist/card/proof/types.d.ts +219 -0
  68. package/dist/card/proof/types.d.ts.map +1 -0
  69. package/dist/card/proof/types.js +87 -0
  70. package/dist/card/proof/types.js.map +1 -0
  71. package/dist/card/proof/verify.d.ts +27 -0
  72. package/dist/card/proof/verify.d.ts.map +1 -0
  73. package/dist/card/proof/verify.js +236 -0
  74. package/dist/card/proof/verify.js.map +1 -0
  75. package/dist/card/resolve.d.ts +97 -0
  76. package/dist/card/resolve.d.ts.map +1 -0
  77. package/dist/card/resolve.js +223 -0
  78. package/dist/card/resolve.js.map +1 -0
  79. package/dist/card/revocation.d.ts +96 -0
  80. package/dist/card/revocation.d.ts.map +1 -0
  81. package/dist/card/revocation.js +190 -0
  82. package/dist/card/revocation.js.map +1 -0
  83. package/dist/card/schema.d.ts +177 -0
  84. package/dist/card/schema.d.ts.map +1 -0
  85. package/dist/card/schema.js +119 -0
  86. package/dist/card/schema.js.map +1 -0
  87. package/dist/card/verify.d.ts +144 -0
  88. package/dist/card/verify.d.ts.map +1 -0
  89. package/dist/card/verify.js +132 -0
  90. package/dist/card/verify.js.map +1 -0
  91. package/dist/delegation/bitstring.d.ts +9 -7
  92. package/dist/delegation/bitstring.d.ts.map +1 -1
  93. package/dist/delegation/bitstring.js +70 -37
  94. package/dist/delegation/bitstring.js.map +1 -1
  95. package/dist/delegation/did-linkage.d.ts +23 -0
  96. package/dist/delegation/did-linkage.d.ts.map +1 -0
  97. package/dist/delegation/did-linkage.js +57 -0
  98. package/dist/delegation/did-linkage.js.map +1 -0
  99. package/dist/delegation/did-resolver-registry.d.ts +7 -0
  100. package/dist/delegation/did-resolver-registry.d.ts.map +1 -0
  101. package/dist/delegation/did-resolver-registry.js +20 -0
  102. package/dist/delegation/did-resolver-registry.js.map +1 -0
  103. package/dist/delegation/did-web-resolver.d.ts +29 -18
  104. package/dist/delegation/did-web-resolver.d.ts.map +1 -1
  105. package/dist/delegation/did-web-resolver.js +65 -35
  106. package/dist/delegation/did-web-resolver.js.map +1 -1
  107. package/dist/delegation/index.d.ts +3 -0
  108. package/dist/delegation/index.d.ts.map +1 -1
  109. package/dist/delegation/index.js +3 -0
  110. package/dist/delegation/index.js.map +1 -1
  111. package/dist/delegation/statuslist-manager.d.ts.map +1 -1
  112. package/dist/delegation/statuslist-manager.js +16 -1
  113. package/dist/delegation/statuslist-manager.js.map +1 -1
  114. package/dist/delegation/vc-jwt-verify.d.ts +61 -0
  115. package/dist/delegation/vc-jwt-verify.d.ts.map +1 -0
  116. package/dist/delegation/vc-jwt-verify.js +131 -0
  117. package/dist/delegation/vc-jwt-verify.js.map +1 -0
  118. package/dist/delegation/vc-verification-checks.d.ts +50 -0
  119. package/dist/delegation/vc-verification-checks.d.ts.map +1 -0
  120. package/dist/delegation/vc-verification-checks.js +212 -0
  121. package/dist/delegation/vc-verification-checks.js.map +1 -0
  122. package/dist/delegation/vc-verifier.d.ts +24 -61
  123. package/dist/delegation/vc-verifier.d.ts.map +1 -1
  124. package/dist/delegation/vc-verifier.js +57 -180
  125. package/dist/delegation/vc-verifier.js.map +1 -1
  126. package/dist/delegation/vc-verifier.types.d.ts +88 -0
  127. package/dist/delegation/vc-verifier.types.d.ts.map +1 -0
  128. package/dist/delegation/vc-verifier.types.js +9 -0
  129. package/dist/delegation/vc-verifier.types.js.map +1 -0
  130. package/dist/index.d.ts +8 -4
  131. package/dist/index.d.ts.map +1 -1
  132. package/dist/index.js +10 -3
  133. package/dist/index.js.map +1 -1
  134. package/dist/integrations/cheqd/dlr.d.ts +44 -0
  135. package/dist/integrations/cheqd/dlr.d.ts.map +1 -0
  136. package/dist/integrations/cheqd/dlr.js +86 -0
  137. package/dist/integrations/cheqd/dlr.js.map +1 -0
  138. package/dist/integrations/cheqd/index.d.ts +5 -0
  139. package/dist/integrations/cheqd/index.d.ts.map +1 -0
  140. package/dist/integrations/cheqd/index.js +5 -0
  141. package/dist/integrations/cheqd/index.js.map +1 -0
  142. package/dist/integrations/cheqd/linkage.d.ts +20 -0
  143. package/dist/integrations/cheqd/linkage.d.ts.map +1 -0
  144. package/dist/integrations/cheqd/linkage.js +32 -0
  145. package/dist/integrations/cheqd/linkage.js.map +1 -0
  146. package/dist/integrations/cheqd/registrar.d.ts +85 -0
  147. package/dist/integrations/cheqd/registrar.d.ts.map +1 -0
  148. package/dist/integrations/cheqd/registrar.js +304 -0
  149. package/dist/integrations/cheqd/registrar.js.map +1 -0
  150. package/dist/integrations/cheqd/resolver.d.ts +38 -0
  151. package/dist/integrations/cheqd/resolver.d.ts.map +1 -0
  152. package/dist/integrations/cheqd/resolver.js +156 -0
  153. package/dist/integrations/cheqd/resolver.js.map +1 -0
  154. package/dist/middleware/index.d.ts +2 -0
  155. package/dist/middleware/index.d.ts.map +1 -1
  156. package/dist/middleware/index.js +5 -0
  157. package/dist/middleware/index.js.map +1 -1
  158. package/dist/middleware/kya-os-transport.d.ts +2 -1
  159. package/dist/middleware/kya-os-transport.d.ts.map +1 -1
  160. package/dist/middleware/kya-os-transport.js +2 -1
  161. package/dist/middleware/kya-os-transport.js.map +1 -1
  162. package/dist/middleware/with-kya-os-server.d.ts +21 -4
  163. package/dist/middleware/with-kya-os-server.d.ts.map +1 -1
  164. package/dist/middleware/with-kya-os-server.js +4 -0
  165. package/dist/middleware/with-kya-os-server.js.map +1 -1
  166. package/dist/middleware/with-kya-os.config-types.d.ts +139 -0
  167. package/dist/middleware/with-kya-os.config-types.d.ts.map +1 -0
  168. package/dist/middleware/with-kya-os.config-types.js +9 -0
  169. package/dist/middleware/with-kya-os.config-types.js.map +1 -0
  170. package/dist/middleware/with-kya-os.d.ts +10 -238
  171. package/dist/middleware/with-kya-os.d.ts.map +1 -1
  172. package/dist/middleware/with-kya-os.delegation-gate.d.ts +19 -0
  173. package/dist/middleware/with-kya-os.delegation-gate.d.ts.map +1 -0
  174. package/dist/middleware/with-kya-os.delegation-gate.js +175 -0
  175. package/dist/middleware/with-kya-os.delegation-gate.js.map +1 -0
  176. package/dist/middleware/with-kya-os.delegation-verify.d.ts +51 -0
  177. package/dist/middleware/with-kya-os.delegation-verify.d.ts.map +1 -0
  178. package/dist/middleware/with-kya-os.delegation-verify.js +165 -0
  179. package/dist/middleware/with-kya-os.delegation-verify.js.map +1 -0
  180. package/dist/middleware/with-kya-os.deps.d.ts +40 -0
  181. package/dist/middleware/with-kya-os.deps.d.ts.map +1 -0
  182. package/dist/middleware/with-kya-os.deps.js +9 -0
  183. package/dist/middleware/with-kya-os.deps.js.map +1 -0
  184. package/dist/middleware/with-kya-os.grants.d.ts +30 -0
  185. package/dist/middleware/with-kya-os.grants.d.ts.map +1 -0
  186. package/dist/middleware/with-kya-os.grants.js +145 -0
  187. package/dist/middleware/with-kya-os.grants.js.map +1 -0
  188. package/dist/middleware/with-kya-os.helpers.d.ts +24 -0
  189. package/dist/middleware/with-kya-os.helpers.d.ts.map +1 -0
  190. package/dist/middleware/with-kya-os.helpers.js +57 -0
  191. package/dist/middleware/with-kya-os.helpers.js.map +1 -0
  192. package/dist/middleware/with-kya-os.js +65 -703
  193. package/dist/middleware/with-kya-os.js.map +1 -1
  194. package/dist/middleware/with-kya-os.policy-gate.d.ts +16 -0
  195. package/dist/middleware/with-kya-os.policy-gate.d.ts.map +1 -0
  196. package/dist/middleware/with-kya-os.policy-gate.js +98 -0
  197. package/dist/middleware/with-kya-os.policy-gate.js.map +1 -0
  198. package/dist/middleware/with-kya-os.protocol.d.ts +29 -0
  199. package/dist/middleware/with-kya-os.protocol.d.ts.map +1 -0
  200. package/dist/middleware/with-kya-os.protocol.js +121 -0
  201. package/dist/middleware/with-kya-os.protocol.js.map +1 -0
  202. package/dist/middleware/with-kya-os.session.d.ts +32 -0
  203. package/dist/middleware/with-kya-os.session.d.ts.map +1 -0
  204. package/dist/middleware/with-kya-os.session.js +201 -0
  205. package/dist/middleware/with-kya-os.session.js.map +1 -0
  206. package/dist/middleware/with-kya-os.types.d.ts +178 -0
  207. package/dist/middleware/with-kya-os.types.d.ts.map +1 -0
  208. package/dist/middleware/with-kya-os.types.js +13 -0
  209. package/dist/middleware/with-kya-os.types.js.map +1 -0
  210. package/dist/proof/generator.d.ts +21 -0
  211. package/dist/proof/generator.d.ts.map +1 -1
  212. package/dist/proof/generator.js +21 -0
  213. package/dist/proof/generator.js.map +1 -1
  214. package/dist/proof/index.d.ts +1 -1
  215. package/dist/proof/index.d.ts.map +1 -1
  216. package/dist/proof/index.js +1 -1
  217. package/dist/proof/index.js.map +1 -1
  218. package/dist/proof/verifier.d.ts +26 -3
  219. package/dist/proof/verifier.d.ts.map +1 -1
  220. package/dist/proof/verifier.js +54 -24
  221. package/dist/proof/verifier.js.map +1 -1
  222. package/dist/providers/grant-store.d.ts +10 -1
  223. package/dist/providers/grant-store.d.ts.map +1 -1
  224. package/dist/providers/grant-store.js.map +1 -1
  225. package/dist/providers/runtime-fetch.d.ts +8 -0
  226. package/dist/providers/runtime-fetch.d.ts.map +1 -1
  227. package/dist/providers/runtime-fetch.js +17 -0
  228. package/dist/providers/runtime-fetch.js.map +1 -1
  229. package/dist/providers/web-crypto.d.ts.map +1 -1
  230. package/dist/providers/web-crypto.js +15 -7
  231. package/dist/providers/web-crypto.js.map +1 -1
  232. package/dist/session/index.d.ts +1 -0
  233. package/dist/session/index.d.ts.map +1 -1
  234. package/dist/session/index.js +1 -0
  235. package/dist/session/index.js.map +1 -1
  236. package/dist/session/manager.d.ts +17 -6
  237. package/dist/session/manager.d.ts.map +1 -1
  238. package/dist/session/manager.js +16 -26
  239. package/dist/session/manager.js.map +1 -1
  240. package/dist/session/session-store.d.ts +78 -0
  241. package/dist/session/session-store.d.ts.map +1 -0
  242. package/dist/session/session-store.js +79 -0
  243. package/dist/session/session-store.js.map +1 -0
  244. package/dist/types/protocol.d.ts +9 -3
  245. package/dist/types/protocol.d.ts.map +1 -1
  246. package/dist/types/protocol.js.map +1 -1
  247. package/dist/utils/guards.d.ts +2 -0
  248. package/dist/utils/guards.d.ts.map +1 -0
  249. package/dist/utils/guards.js +4 -0
  250. package/dist/utils/guards.js.map +1 -0
  251. package/dist/utils/index.d.ts +3 -0
  252. package/dist/utils/index.d.ts.map +1 -1
  253. package/dist/utils/index.js +3 -0
  254. package/dist/utils/index.js.map +1 -1
  255. package/dist/utils/ip-classifier.d.ts +12 -0
  256. package/dist/utils/ip-classifier.d.ts.map +1 -0
  257. package/dist/utils/ip-classifier.js +153 -0
  258. package/dist/utils/ip-classifier.js.map +1 -0
  259. package/dist/utils/safe-fetch-transports.d.ts +40 -0
  260. package/dist/utils/safe-fetch-transports.d.ts.map +1 -0
  261. package/dist/utils/safe-fetch-transports.js +121 -0
  262. package/dist/utils/safe-fetch-transports.js.map +1 -0
  263. package/dist/utils/safe-fetch-types.d.ts +66 -0
  264. package/dist/utils/safe-fetch-types.d.ts.map +1 -0
  265. package/dist/utils/safe-fetch-types.js +10 -0
  266. package/dist/utils/safe-fetch-types.js.map +1 -0
  267. package/dist/utils/safe-fetch.d.ts +40 -0
  268. package/dist/utils/safe-fetch.d.ts.map +1 -0
  269. package/dist/utils/safe-fetch.js +188 -0
  270. package/dist/utils/safe-fetch.js.map +1 -0
  271. package/dist/utils/statuslist-purpose.d.ts +12 -0
  272. package/dist/utils/statuslist-purpose.d.ts.map +1 -0
  273. package/dist/utils/statuslist-purpose.js +19 -0
  274. package/dist/utils/statuslist-purpose.js.map +1 -0
  275. package/dist/utils/url.d.ts +2 -0
  276. package/dist/utils/url.d.ts.map +1 -0
  277. package/dist/utils/url.js +8 -0
  278. package/dist/utils/url.js.map +1 -0
  279. package/package.json +25 -5
  280. package/schemas/README.md +2 -1
  281. package/schemas/card-delegation-credential.json +239 -0
  282. package/schemas/kya-os-card.schema.json +284 -0
package/CHANGELOG.md CHANGED
@@ -7,6 +7,123 @@ Versioning: https://semver.org/spec/v2.0.0.html
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [1.9.0] - 2026-07-07
11
+
12
+ Entity Card (`@kya-os/mcp/card`) — a typed, DID-anchored, per-request
13
+ holder-of-key identity layer that rides existing rails (MCP server-card `_meta`,
14
+ A2A extension, NANDA AgentFacts) instead of a new well-known doc. Additive.
15
+
16
+ First npm release since 1.7.0 (the prepared 1.8.0 was never published). See the
17
+ BREAKING status-list note below — persisted 1.x status lists MUST be
18
+ regenerated on upgrade.
19
+
20
+ ### Added
21
+
22
+ - **`./card`** — the `card()` builder, `withKyaOsCard` / `requireProof`
23
+ middleware, and `buildCard` / `resolveCard` / `verifyCard`. Conformance is
24
+ recomputed on verify, never self-claimed.
25
+ - **Stateless proof (`org.kya-os/proof@1`)** and a **VC 2.0 / ZCAP-LD**
26
+ delegation profile with Bitstring Status List v1.0 revocation. Both run
27
+ alongside the legacy session proof + delegation for all of 1.x; the legacy
28
+ paths drop at 2.0.
29
+ - **CIMD L1 on-ramp** — `client_id ⇄ did:web`, so an OAuth `private_key_jwt`
30
+ doubles as a DID-key proof (RFC 9449 `cnf.jkt` sender-constrains it).
31
+ - Conformance vectors + a cross-language verifier folded into the existing
32
+ `conformance/` harness (new `card-proof` / `entity-card` categories).
33
+ - **Proof crypto agility (`ES256`)** — the per-request proof now accepts an
34
+ ALLOW-LIST of two signing algorithms, `EdDSA` (Ed25519) and `ES256` (ECDSA
35
+ P-256, FIPS-eligible via HSM/KMS), never negotiated. `alg` is a signed covered
36
+ claim and the resolved key type MUST match it (`alg_key_mismatch`), so adding a
37
+ second curve introduces no algorithm-confusion surface. `es256SignerFromJwk`
38
+ ships alongside `ed25519SignerFromJwk`; the RFC 9421 sibling carries the
39
+ matching `ecdsa-p256-sha256` label. (CIMD DID-keyed JWKS extraction stays
40
+ Ed25519-only for now — a P-256 verifier supplies its own `resolveDidKeys`.)
41
+ - **VC-JWT verification (`./delegation`)** — `DelegationCredentialVerifier.verifyDelegationJwt()`
42
+ verifies the JWT serialization of a Verifiable Credential (compact JWS, where
43
+ the envelope signature over `header.payload` IS the proof — no embedded
44
+ `proof` block), so credentials minted by browser / passkey wallets verify
45
+ without a hand-rolled path. `algorithms` is pinned to `EdDSA`, and the
46
+ credential `issuer` must equal the signed `iss`. Additive; the Data Integrity
47
+ path is unchanged.
48
+ - **Multi-key did:web documents** — `buildDidWebDocument` now accepts
49
+ `Identity | Identity[]`, emitting one verification method per key under a
50
+ single controller DID. This is the basis for multi-device identity: a device
51
+ is added or removed by adding or removing a verification method, and a
52
+ verifier selects the signing key by `kid`. Backward-compatible — a lone
53
+ identity yields the same single-method document as before.
54
+
55
+ ### Changed — BREAKING for persisted status lists
56
+
57
+ - **Status-list bit order corrected to W3C MSB-first.** `BitstringManager`
58
+ (StatusList2021 / Bitstring Status List) now reads and writes bits
59
+ most-significant-first (`0x80 >> i`), matching the W3C spec and the Digital
60
+ Bazaar reference — and the Entity Card revocation reader — so both code paths
61
+ read an identical `encodedList` to the same verdict. The prior LSB-first order
62
+ was self-consistent but non-interoperable with any standard tool.
63
+ - **⚠️ MIGRATION — READ THIS.** A status list generated by a 1.x release is
64
+ encoded LSB-first. Read by this release it is **misread silently**: a
65
+ **revoked credential can read as LIVE** (the bit mirrors within its byte, so
66
+ e.g. revoked index 42 → clear, and phantom index 45 → revoked). The W3C
67
+ credential carries no bit-order/version field, so old lists **cannot be
68
+ auto-detected**. You MUST **regenerate every persisted status list** on
69
+ upgrade; do not read 1.x-encoded lists with this release. (Tracking a
70
+ KYA-OS-side encoding-version marker + a bit-reverse migration helper as a
71
+ follow-up so future changes are detectable.)
72
+ - **Fail-closed hardening.** `isIndexSet` / `BitstringManager.getBit` now throw
73
+ on an out-of-range or `NaN` index (were fail-open), `BitstringManager.decode`
74
+ caps the inflated bitstring at 16 MiB (decompression-bomb guard), and the card
75
+ `statusListIndex` must be a canonical decimal (a whitespace/hex value no longer
76
+ silently reads bit 0). IPv6 NAT64 / 6to4 / Teredo / site-local addresses are
77
+ now treated as non-public by the SSRF guard.
78
+
79
+ ## [1.7.0] - 2026-06-17
80
+
81
+ Durable consent persistence. Pluggable `GrantStore` / `PendingFlowStore` /
82
+ `SessionStore` seams so consent, grant, and PKCE state survive restarts and
83
+ resolve across load-balanced instances — the holder-of-key (`getByAgent`)
84
+ no-paste retry, with session-bearer (`getBySession`) as a fallback. The detached
85
+ proof is namespaced under `_meta["org.kya-os/proof"]` and still dual-emitted
86
+ under the legacy bare key (ON for all of 1.x, dropped at 2.0). Additive over
87
+ 1.6.x, with one documented behavioral change: a `strict` verifier now ignores
88
+ MCP-reserved foreign `_meta` keys instead of rejecting them.
89
+
90
+ ### Added
91
+
92
+ - **Durable consent persistence (optional, in-memory defaults — no breaking
93
+ change).** New pluggable seams so consent / grant / PKCE state survives
94
+ restarts and resolves across load-balanced instances: `grantStore` (the
95
+ no-paste retry — holder-of-key `getByAgent` first, then session-bearer
96
+ `getBySession`), `PendingFlowStore` (durable OAuth/OIDC PKCE state with an
97
+ atomic `consume()`), and an optional `SessionStore`. The detached proof is now
98
+ namespaced under `_meta["org.kya-os/proof"]`; the legacy bare `proof` key is
99
+ still accepted on verify and (by default) still emitted — toggle with
100
+ `emitLegacyProofKey`. The legacy mirror stays **ON by default for the entire
101
+ 1.x line** (a pre-1.1 reader of bare `_meta.proof` would otherwise silently get
102
+ no proof; the cost is ~1.5 KB of `_meta`, which is outside the response hash)
103
+ and will be **dropped at 2.0**.
104
+
105
+ ### Changed
106
+
107
+ - **BEHAVIORAL — `strict` `metaPolicy` now IGNORES foreign `_meta` keys instead
108
+ of rejecting them.** Previously a `strict` verifier rejected any `_meta` key
109
+ other than the proof. Under MCP 2026-07-28 (SEP-414) `_meta` legitimately
110
+ carries reserved `io.modelcontextprotocol/*` and W3C trace-context keys
111
+ (`traceparent`/`tracestate`/`baggage`), so `strict` now ignores every
112
+ non-KYA-OS key (never hashed, trusted, or rejected) and `allow-extensions`
113
+ additionally surfaces them. The zero-trust boundary is unchanged — only the
114
+ KYA-OS proof key is ever hashed or trusted. **Migration:** anyone relying on
115
+ `strict` to REJECT foreign `_meta` keys must now enforce that themselves; the
116
+ verifier no longer fails on them.
117
+
118
+ ### Fixed
119
+
120
+ - **Appendix A error codes corrected** to match `src/errors.ts`, the single
121
+ source of truth. The table listed prefixed codes (`KYA_OS_EHANDSHAKE`,
122
+ `KYA_OS_EPROOF`, ...) that no part of the codebase emits; the runtime,
123
+ middleware, and session manager all return bare snake_case codes
124
+ (`handshake_failed`, `invalid_proof`, ...). Documentation only — no behaviour
125
+ change.
126
+
10
127
  ## [1.6.1] - 2026-06-10
11
128
 
12
129
  Releases the schema-host migration already merged on `main` (it was unshipped:
package/README.md CHANGED
@@ -108,6 +108,44 @@ When an agent calls `checkout` without a delegation credential, it gets back a `
108
108
 
109
109
  ---
110
110
 
111
+ ## Typed, DID-anchored identity: the Entity Card
112
+
113
+ Proofs answer *what an agent did*. The **Entity Card** answers *who is calling* — a typed, DID-anchored identity (`agent`, `mcp`, `client`, `verifier`, `human`) an entity publishes once and every discovery rail can index. It is claim-minimal: it asserts only identity, type, declared capabilities, and accountability locators. The trust **level** (L1/L2/L3) is never self-claimed — a verifier RECOMPUTES it from evidence. Three ergonomic calls, imported from the published `@kya-os/mcp/card` subpath:
114
+
115
+ ```typescript
116
+ import { card, withKyaOsCard, requireProof, InMemoryNonceCache } from '@kya-os/mcp/card';
117
+
118
+ // 1. BUILD — describe the agent, fluently. No conformanceLevel: a verifier derives it.
119
+ const myCard = card({ did: 'did:web:acme.example:agents:pay', entityType: 'agent', name: 'Acme Pay' })
120
+ .capability('search') // L1: bare-string, self-declared
121
+ .attestedCapability('payments.transfer', capabilityVc) // L2: VC-backed
122
+ .accountableTo('did:web:acme.example:org', { via: 'vc_root>del_123' })
123
+ .usesProof()
124
+ .build();
125
+
126
+ // 2. EMIT — mount the three discovery artifacts (card.json, DID service entry, server.json _meta).
127
+ const mount = withKyaOsCard(myCard);
128
+ const serverJson = mount.mountServerJson({ name: 'acme-mcp', version: '1.0.0' });
129
+
130
+ // 3. GUARD — verify a per-request holder-of-key proof, fail-closed.
131
+ const nonces = new InMemoryNonceCache(); // ATOMIC replay defense — never hand-roll this seam
132
+ const guard = requireProof({
133
+ resolveKey, // resolve the signing key from its kid (DID document)
134
+ expectedAudience: 'did:web:acme.example:mcp:server',
135
+ consumeNonceIfFresh: nonces.consume, // test-AND-set; a replayed nonce is rejected
136
+ });
137
+
138
+ // Pass the EXACT body the client signed (without _meta) plus the _meta that carried the proof.
139
+ const { _meta, ...signedBody } = incomingRequest;
140
+ const verdict = await guard(signedBody, _meta); // { ok: true, did, level } or a 401-shaped reject
141
+ ```
142
+
143
+ Miss the proof, replay a nonce, or tamper the body and `requireProof` fails closed. To go the other direction — DISCOVER and verify another entity's card — use `resolveCard` + `verifyCard` (the verifier recomputes the conformance floor rather than trusting the card).
144
+
145
+ > Run the full 10-minute path end-to-end: [examples/entity-card](./examples/entity-card/) — `npm run example:entity-card:server` (build → emit → guard, with a valid proof accepted and a replay + tamper rejected) and `npm run example:entity-card` (the discover → resolve → verify walkthrough). See [SPEC-ENTITY-CARD.md](./SPEC-ENTITY-CARD.md) for normative detail.
146
+
147
+ ---
148
+
111
149
  ## See it in action
112
150
 
113
151
  ```bash
@@ -125,7 +163,7 @@ This starts all example servers and opens [MCP Inspector](https://github.com/mod
125
163
  | 3003 | [consent-full](./examples/consent-full/) | Production consent UI ([@kya-os/consent](https://www.npmjs.com/package/@kya-os/consent)) |
126
164
  | 3004 | [context7-with-kya-os](./examples/context7-with-kya-os/) | 2-line migration of a real MCP server |
127
165
 
128
- Also available: [outbound-delegation](./examples/outbound-delegation/) (gateway pattern), [verify-proof](./examples/verify-proof/) (standalone verification), [statuslist](./examples/statuslist/) (revocation lifecycle).
166
+ Also available: [outbound-delegation](./examples/outbound-delegation/) (gateway pattern), [verify-proof](./examples/verify-proof/) (standalone verification), [statuslist](./examples/statuslist/) (revocation lifecycle), [cheqd-dlr](./examples/cheqd-dlr/) (operator DID linkage + DLR publishing).
129
167
 
130
168
  ---
131
169
 
@@ -133,18 +171,205 @@ Also available: [outbound-delegation](./examples/outbound-delegation/) (gateway
133
171
 
134
172
  | Capability | How it works |
135
173
  |-----------|-------------|
136
- | **Cryptographic identity** | Ed25519 key pairs, `did:key` and `did:web` resolution |
174
+ | **Cryptographic identity** | Ed25519 (EdDSA) and P-256 (ES256, FIPS-eligible) key pairs, `did:key` / `did:web` resolution, optional `did:cheqd` resolver support |
175
+ | **Entity Card** | Typed, DID-anchored identity: fluent `card()` builder, `withKyaOsCard` discovery projections, `requireProof` per-request holder-of-key guard |
137
176
  | **Signed proofs** | Detached JWS over JCS-canonicalized request/response hashes |
138
177
  | **Delegation credentials** | W3C Verifiable Credentials with scope constraints, rooted at a Responsible Party |
139
178
  | **Revocation** | StatusList2021 bitstring with cascading revocation |
140
179
  | **Replay prevention** | Nonce-based handshake with timestamp skew validation |
141
180
  | **Extensible** | Bring your own KMS, HSM, nonce cache (Redis, DynamoDB, KV), or DID method |
142
181
 
182
+ ### Multi-instance deployments
183
+
184
+ The in-memory defaults are **single-process only**. For a load-balanced /
185
+ multi-instance deployment, inject a durable Redis / Durable Object / DB-backed
186
+ implementation for **every** runtime-state seam — the nonce cache
187
+ (`NonceCacheProvider`) together with the consent stores (`GrantStore`,
188
+ `PendingFlowStore`, `SessionStore`) — so replay protection, grants, pending OAuth
189
+ flows, and sessions are shared across instances and survive restarts.
190
+
143
191
  ---
144
192
 
193
+ ## Optional did:cheqd and DID-Linked Resources
194
+
195
+ `did:cheqd` support is additive and opt-in. Existing `did:key` and `did:web`
196
+ flows remain unchanged, and operators can keep `did:web` as their canonical
197
+ identifier while linking to a cheqd DID over time.
198
+
199
+ ### Resolver configuration
200
+
201
+ ```typescript
202
+ import { RuntimeFetchProvider, withKyaOs, NodeCryptoProvider } from '@kya-os/mcp';
203
+ import { cheqdResolver } from '@kya-os/mcp/cheqd';
204
+
205
+ const crypto = new NodeCryptoProvider();
206
+ const fetchProvider = new RuntimeFetchProvider();
207
+ const didResolvers = {
208
+ cheqd: cheqdResolver({ resolverUrl: 'https://resolver.cheqd.net' }),
209
+ };
210
+
211
+ await withKyaOs(server, {
212
+ crypto,
213
+ delegation: {
214
+ fetchProvider,
215
+ didResolvers,
216
+ },
217
+ });
218
+ ```
219
+
220
+ `did:cheqd` is resolved only when a resolver for the `cheqd` DID method is
221
+ explicitly supplied. The core middleware and fetch provider use the generic
222
+ `didResolvers` registry; cheqd-specific URL/cache/header options live in the
223
+ `cheqdResolver()` factory from `@kya-os/mcp/cheqd`.
224
+ `RuntimeFetchProvider` accepts the same registry when it is used directly by a
225
+ standalone verifier or operator script.
226
+ Unsupported methods, malformed DIDs, fetch failures, invalid JSON, malformed DID
227
+ Documents, and DID id mismatches fail closed by returning `null`. The resolver
228
+ accepts both raw DID Documents and Universal Resolver-style DID Resolution
229
+ Results (`{ didDocument: ... }`).
230
+
231
+ ### Registrar writes
232
+
233
+ Registrar writes are explicit operator/admin actions. The package exposes
234
+ `CheqdDidRegistrarClient` for cheqd DID Registrar `/create`, `/update`, and
235
+ `/{did}/create-resource` flows, using cheqd's client-managed-secret pattern:
236
+ the registrar returns a serialized payload, your signer signs it, and the
237
+ signature is submitted back. Private keys are not sent to the registrar.
238
+
239
+ ```typescript
240
+ import {
241
+ CheqdDidRegistrarClient,
242
+ createLocalEd25519CheqdRegistrarSigner,
243
+ } from '@kya-os/mcp/cheqd';
244
+ import {
245
+ NodeCryptoProvider,
246
+ } from '@kya-os/mcp';
247
+
248
+ const crypto = new NodeCryptoProvider();
249
+ const registrar = new CheqdDidRegistrarClient({
250
+ registrarUrl: 'https://did-registrar-staging.cheqd.net/1.0',
251
+ fetchProvider,
252
+ // Optional static or async auth headers for private registrar deployments.
253
+ // headers: async () => ({ Authorization: `Bearer ${token}` }),
254
+ });
255
+
256
+ const signer = createLocalEd25519CheqdRegistrarSigner({
257
+ cryptoProvider: crypto,
258
+ privateKey: process.env.CHEQD_DID_PRIVATE_KEY_BASE64!,
259
+ verificationMethodId: 'did:cheqd:testnet:...#key-1',
260
+ signatureEncoding: 'base64url',
261
+ });
262
+ ```
263
+
264
+ For mainnet, run or contract against your own fee-payer registrar deployment and
265
+ provide the signer hook from your KMS/HSM boundary. The local Ed25519 helper is
266
+ for simple controlled deployments and tests; it still signs locally and sends
267
+ only signatures to the registrar.
268
+
269
+ Runtime proof generation does not perform registrar writes. Create/update/DLR
270
+ publishing should be triggered by an explicit operator workflow, deployment
271
+ step, or admin tool.
272
+
273
+ ### DID linkage
274
+
275
+ For `did:web` <-> `did:cheqd` binding, publish reciprocal `alsoKnownAs` values
276
+ and verify both DID Documents with `verifyDidLinkage()`. `buildDidWebDocument`
277
+ can include the `did:cheqd` reference on the `did:web` side, while
278
+ `updateCheqdAlsoKnownAs()` updates the cheqd side through the registrar.
279
+
280
+ ```typescript
281
+ import { verifyDidLinkage } from '@kya-os/mcp';
282
+ import { updateCheqdAlsoKnownAs } from '@kya-os/mcp/cheqd';
283
+
284
+ await updateCheqdAlsoKnownAs({
285
+ didWeb: 'did:web:agent.example.com',
286
+ didCheqd: 'did:cheqd:testnet:...',
287
+ resolver: cheqdResolver,
288
+ registrar,
289
+ signer,
290
+ verificationMethodId: 'did:cheqd:testnet:...#key-1',
291
+ });
292
+
293
+ const linkage = verifyDidLinkage({
294
+ primaryDid: 'did:web:agent.example.com',
295
+ secondaryDid: 'did:cheqd:testnet:...',
296
+ primaryDidDocument: didWebDocument,
297
+ secondaryDidDocument: didCheqdDocument,
298
+ });
299
+ ```
300
+
301
+ ### DID-Linked Resource helpers
302
+
303
+ DID-Linked Resource helpers are intended for durable manifests only. Supported
304
+ artifact types are:
305
+
306
+ - `CapabilityManifest`
307
+ - `ConformanceManifest`
308
+ - `AccessHashManifest`
309
+ - `TrustConfigManifest`
310
+
311
+ `prepareCheqdDlrResource()` validates the artifact, canonicalizes its `content`
312
+ with JSON Canonicalization Scheme, computes or validates a `sha256:<64 hex>`
313
+ content hash, and returns a registrar resource body. Updates are modeled as new
314
+ resource versions under the same resource `name` and `type`; prior resources are
315
+ not overwritten. Do not write high-volume tool calls, raw operational logs, or
316
+ normal runtime proof events to cheqd; keep those in your normal audit/hash
317
+ stores.
318
+
319
+ ```typescript
320
+ import { prepareCheqdDlrResource } from '@kya-os/mcp/cheqd';
321
+
322
+ const prepared = await prepareCheqdDlrResource({
323
+ type: 'TrustConfigManifest',
324
+ subjectDid: 'did:cheqd:testnet:...',
325
+ name: 'agent-trust-config',
326
+ resourceType: 'TrustConfigManifest',
327
+ version: '2026-06-01',
328
+ content: {
329
+ acceptedDidMethods: ['did:web', 'did:key', 'did:cheqd'],
330
+ requiredLinkage: { type: 'alsoKnownAs', bidirectional: true },
331
+ },
332
+ }, crypto);
333
+
334
+ await registrar.createResource({
335
+ did: 'did:cheqd:testnet:...',
336
+ resource: prepared.resource,
337
+ signer,
338
+ verificationMethodId: 'did:cheqd:testnet:...#key-1',
339
+ });
340
+ ```
341
+
342
+ See [examples/cheqd-dlr](./examples/cheqd-dlr/) for a complete operator flow.
343
+
344
+ ### Live cheqd registrar E2E tests
345
+
346
+ Live registrar coverage is opt-in because it performs real writes to cheqd
347
+ testnet. The default endpoint is the cheqd-published testnet staging registrar;
348
+ override it only with another testnet registrar. The live test creates a testnet
349
+ DID, adds a realistic `did:web` alias via `alsoKnownAs`, then publishes one
350
+ resource for each supported KYA DLR artifact type.
351
+
352
+ ```powershell
353
+ $env:KYA_OS_CHEQD_E2E = '1'
354
+ npm run test:e2e:cheqd:testnet
355
+ Remove-Item Env:\KYA_OS_CHEQD_E2E
356
+ ```
357
+
358
+ Optional environment variables:
359
+
360
+ | Variable | Default |
361
+ | --- | --- |
362
+ | `KYA_OS_CHEQD_TESTNET_REGISTRAR_URL` | `https://did-registrar-staging.cheqd.net/1.0` |
363
+ | `KYA_OS_CHEQD_TESTNET_RESOLVER_URL` | `https://resolver.cheqd.net` |
364
+ | `KYA_OS_CHEQD_E2E_TIMEOUT_MS` | `180000` |
365
+
366
+ Out of scope for this package: replacing `did:web` as the canonical identity,
367
+ writing runtime proof events on-chain, KYC/KYB issuance, reputation VC snapshot
368
+ publication, status-list backend hosting, and external registry changes.
369
+
145
370
  ## Links
146
371
 
147
- - [Spec](./SPEC.md) | [Changelog](./CHANGELOG.md) | [DIF TAAWG](https://identity.foundation/working-groups/agent-and-authorization.html) | [npm](https://www.npmjs.com/package/@kya-os/mcp)
372
+ - [Spec](./SPEC.md) | [Card Profile](./SPEC-ENTITY-CARD.md) | [Changelog](./CHANGELOG.md) | [DIF TAAWG](https://identity.foundation/working-groups/agent-and-authorization.html) | [npm](https://www.npmjs.com/package/@kya-os/mcp)
148
373
  - [CONTRIBUTING.md](./CONTRIBUTING.md) | [CONFORMANCE.md](./CONFORMANCE.md) | [SECURITY.md](./SECURITY.md) | [GOVERNANCE.md](./GOVERNANCE.md)
149
374
 
150
375
  ## License
@@ -14,6 +14,7 @@ export { buildAuthorizeUrl, type AuthorizeUrlParams } from './oidc/authorize.js'
14
14
  export { buildAuthorizationServerMetadata, buildProtectedResourceMetadata, type AuthorizationServerMetadata, type AuthorizationServerMetadataInput, type ProtectedResourceMetadata, type ProtectedResourceMetadataInput, } from './oidc/metadata.js';
15
15
  export { isS256ChallengeMethod, computeS256Challenge, verifyS256Challenge, type S256, } from './oidc/pkce.js';
16
16
  export { GenericOidcAdapter, type GenericOidcAdapterConfig, type FetchImpl, } from './oidc/oidc-adapter.js';
17
+ export { PendingFlowStore, MemoryPendingFlowStore, type PendingFlow, type MemoryPendingFlowStoreOptions, } from './oidc/pending-flow-store.js';
17
18
  export { AuthorizationServerRegistry } from './registry.js';
18
19
  export { projectAccountability, accountabilityToPolicyPrincipal, type AccountabilityContext, } from './accountability.js';
19
20
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/authz/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EACL,8BAA8B,EAC9B,oBAAoB,EACpB,KAAK,wBAAwB,EAC7B,KAAK,cAAc,GACpB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EACL,yBAAyB,EACzB,KAAK,0BAA0B,EAC/B,KAAK,UAAU,GAChB,MAAM,cAAc,CAAC;AAEtB,OAAO,EAAE,iBAAiB,EAAE,KAAK,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAEjF,OAAO,EACL,gCAAgC,EAChC,8BAA8B,EAC9B,KAAK,2BAA2B,EAChC,KAAK,gCAAgC,EACrC,KAAK,yBAAyB,EAC9B,KAAK,8BAA8B,GACpC,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EACL,qBAAqB,EACrB,oBAAoB,EACpB,mBAAmB,EACnB,KAAK,IAAI,GACV,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACL,kBAAkB,EAClB,KAAK,wBAAwB,EAC7B,KAAK,SAAS,GACf,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EAAE,2BAA2B,EAAE,MAAM,eAAe,CAAC;AAE5D,OAAO,EACL,qBAAqB,EACrB,+BAA+B,EAC/B,KAAK,qBAAqB,GAC3B,MAAM,qBAAqB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/authz/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EACL,8BAA8B,EAC9B,oBAAoB,EACpB,KAAK,wBAAwB,EAC7B,KAAK,cAAc,GACpB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EACL,yBAAyB,EACzB,KAAK,0BAA0B,EAC/B,KAAK,UAAU,GAChB,MAAM,cAAc,CAAC;AAEtB,OAAO,EAAE,iBAAiB,EAAE,KAAK,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAEjF,OAAO,EACL,gCAAgC,EAChC,8BAA8B,EAC9B,KAAK,2BAA2B,EAChC,KAAK,gCAAgC,EACrC,KAAK,yBAAyB,EAC9B,KAAK,8BAA8B,GACpC,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EACL,qBAAqB,EACrB,oBAAoB,EACpB,mBAAmB,EACnB,KAAK,IAAI,GACV,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACL,kBAAkB,EAClB,KAAK,wBAAwB,EAC7B,KAAK,SAAS,GACf,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EACL,gBAAgB,EAChB,sBAAsB,EACtB,KAAK,WAAW,EAChB,KAAK,6BAA6B,GACnC,MAAM,8BAA8B,CAAC;AAEtC,OAAO,EAAE,2BAA2B,EAAE,MAAM,eAAe,CAAC;AAE5D,OAAO,EACL,qBAAqB,EACrB,+BAA+B,EAC/B,KAAK,qBAAqB,GAC3B,MAAM,qBAAqB,CAAC"}
@@ -14,6 +14,7 @@ export { buildAuthorizeUrl } from './oidc/authorize.js';
14
14
  export { buildAuthorizationServerMetadata, buildProtectedResourceMetadata, } from './oidc/metadata.js';
15
15
  export { isS256ChallengeMethod, computeS256Challenge, verifyS256Challenge, } from './oidc/pkce.js';
16
16
  export { GenericOidcAdapter, } from './oidc/oidc-adapter.js';
17
+ export { PendingFlowStore, MemoryPendingFlowStore, } from './oidc/pending-flow-store.js';
17
18
  export { AuthorizationServerRegistry } from './registry.js';
18
19
  export { projectAccountability, accountabilityToPolicyPrincipal, } from './accountability.js';
19
20
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/authz/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EACL,8BAA8B,EAC9B,oBAAoB,GAGrB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EACL,yBAAyB,GAG1B,MAAM,cAAc,CAAC;AAEtB,OAAO,EAAE,iBAAiB,EAA2B,MAAM,qBAAqB,CAAC;AAEjF,OAAO,EACL,gCAAgC,EAChC,8BAA8B,GAK/B,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EACL,qBAAqB,EACrB,oBAAoB,EACpB,mBAAmB,GAEpB,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACL,kBAAkB,GAGnB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EAAE,2BAA2B,EAAE,MAAM,eAAe,CAAC;AAE5D,OAAO,EACL,qBAAqB,EACrB,+BAA+B,GAEhC,MAAM,qBAAqB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/authz/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EACL,8BAA8B,EAC9B,oBAAoB,GAGrB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EACL,yBAAyB,GAG1B,MAAM,cAAc,CAAC;AAEtB,OAAO,EAAE,iBAAiB,EAA2B,MAAM,qBAAqB,CAAC;AAEjF,OAAO,EACL,gCAAgC,EAChC,8BAA8B,GAK/B,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EACL,qBAAqB,EACrB,oBAAoB,EACpB,mBAAmB,GAEpB,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACL,kBAAkB,GAGnB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EACL,gBAAgB,EAChB,sBAAsB,GAGvB,MAAM,8BAA8B,CAAC;AAEtC,OAAO,EAAE,2BAA2B,EAAE,MAAM,eAAe,CAAC;AAE5D,OAAO,EACL,qBAAqB,EACrB,+BAA+B,GAEhC,MAAM,qBAAqB,CAAC"}
@@ -2,6 +2,7 @@ import { type NeedsAuthorizationError } from '../../types/protocol.js';
2
2
  import type { VerifyDelegationResult } from '../../auth/types.js';
3
3
  import type { AuthorizationServerAdapter, FlowParams } from '../adapter.js';
4
4
  import type { ToolProtection } from '../requirement.js';
5
+ import { type PendingFlowStore } from './pending-flow-store.js';
5
6
  /** A minimal fetch signature — the injectable seam for IdP HTTP calls. */
6
7
  export type FetchImpl = (url: string, init?: {
7
8
  method?: string;
@@ -22,6 +23,13 @@ export interface GenericOidcAdapterConfig {
22
23
  resumeTokenTtlMs?: number;
23
24
  /** Injected fetch seam; defaults to the runtime global fetch. */
24
25
  fetchImpl?: FetchImpl;
26
+ /**
27
+ * Pluggable store for in-flight PKCE state. Defaults to an in-memory store
28
+ * (single-process only). Inject a durable {@link PendingFlowStore} (Redis /
29
+ * Durable Object / DB) so an authorization callback that lands on another
30
+ * instance — or after a restart — can still complete the token exchange.
31
+ */
32
+ pendingFlowStore?: PendingFlowStore;
25
33
  }
26
34
  /**
27
35
  * Reference generic-OIDC authorization-server adapter.
@@ -40,13 +48,13 @@ export interface GenericOidcAdapterConfig {
40
48
  export declare class GenericOidcAdapter implements AuthorizationServerAdapter {
41
49
  private readonly config;
42
50
  readonly type: "oauth";
43
- private readonly pending;
51
+ private readonly pendingFlowStore;
44
52
  private readonly fetchImpl;
45
53
  constructor(config: GenericOidcAdapterConfig);
46
54
  isRequired(protection: ToolProtection): boolean;
47
55
  initiateFlow(params: FlowParams): Promise<NeedsAuthorizationError>;
48
56
  verifyAuthorization(flowState: string, result: unknown): Promise<VerifyDelegationResult>;
49
57
  /** Test/inspection seam: the pending code verifier for a resume token, if any. */
50
- pendingVerifierFor(resumeToken: string): string | undefined;
58
+ pendingVerifierFor(resumeToken: string): Promise<string | undefined>;
51
59
  }
52
60
  //# sourceMappingURL=oidc-adapter.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"oidc-adapter.d.ts","sourceRoot":"","sources":["../../../src/authz/oidc/oidc-adapter.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,KAAK,uBAAuB,EAC7B,MAAM,yBAAyB,CAAC;AACjC,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAClE,OAAO,KAAK,EAAE,0BAA0B,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAI5E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAExD,0EAA0E;AAC1E,MAAM,MAAM,SAAS,GAAG,CACtB,GAAG,EAAE,MAAM,EACX,IAAI,CAAC,EAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,KACxE,OAAO,CAAC,QAAQ,CAAC,CAAC;AAEvB,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,qBAAqB,EAAE,MAAM,CAAC;IAC9B,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,qFAAqF;IACrF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,wDAAwD;IACxD,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,iEAAiE;IACjE,SAAS,CAAC,EAAE,SAAS,CAAC;CACvB;AAUD;;;;;;;;;;;;;GAaG;AACH,qBAAa,kBAAmB,YAAW,0BAA0B;IAKvD,OAAO,CAAC,QAAQ,CAAC,MAAM;IAJnC,QAAQ,CAAC,IAAI,EAAG,OAAO,CAAU;IACjC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAkC;IAC1D,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAY;gBAET,MAAM,EAAE,wBAAwB;IAI7D,UAAU,CAAC,UAAU,EAAE,cAAc,GAAG,OAAO;IAIzC,YAAY,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,uBAAuB,CAAC;IAsClE,mBAAmB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,OAAO,CAAC,sBAAsB,CAAC;IAqD9F,kFAAkF;IAClF,kBAAkB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;CAG5D"}
1
+ {"version":3,"file":"oidc-adapter.d.ts","sourceRoot":"","sources":["../../../src/authz/oidc/oidc-adapter.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,KAAK,uBAAuB,EAC7B,MAAM,yBAAyB,CAAC;AACjC,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAClE,OAAO,KAAK,EAAE,0BAA0B,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAI5E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAEL,KAAK,gBAAgB,EACtB,MAAM,yBAAyB,CAAC;AAEjC,0EAA0E;AAC1E,MAAM,MAAM,SAAS,GAAG,CACtB,GAAG,EAAE,MAAM,EACX,IAAI,CAAC,EAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,KACxE,OAAO,CAAC,QAAQ,CAAC,CAAC;AAEvB,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,qBAAqB,EAAE,MAAM,CAAC;IAC9B,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,qFAAqF;IACrF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,wDAAwD;IACxD,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,iEAAiE;IACjE,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;CACrC;AAKD;;;;;;;;;;;;;GAaG;AACH,qBAAa,kBAAmB,YAAW,0BAA0B;IAKvD,OAAO,CAAC,QAAQ,CAAC,MAAM;IAJnC,QAAQ,CAAC,IAAI,EAAG,OAAO,CAAU;IACjC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAmB;IACpD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAY;gBAET,MAAM,EAAE,wBAAwB;IAK7D,UAAU,CAAC,UAAU,EAAE,cAAc,GAAG,OAAO;IAIzC,YAAY,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,uBAAuB,CAAC;IA2ClE,mBAAmB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,OAAO,CAAC,sBAAsB,CAAC;IAwD9F,kFAAkF;IAC5E,kBAAkB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;CAG3E"}
@@ -3,6 +3,9 @@ import { createNeedsAuthorizationError, } from '../../types/protocol.js';
3
3
  import { requirementMatchesAdapter } from '../adapter.js';
4
4
  import { buildAuthorizeUrl } from './authorize.js';
5
5
  import { computeS256Challenge } from './pkce.js';
6
+ import { MemoryPendingFlowStore, } from './pending-flow-store.js';
7
+ /** Default resume-token / pending-flow lifetime (10 minutes). */
8
+ const DEFAULT_RESUME_TOKEN_TTL_MS = 600_000;
6
9
  /**
7
10
  * Reference generic-OIDC authorization-server adapter.
8
11
  *
@@ -20,11 +23,12 @@ import { computeS256Challenge } from './pkce.js';
20
23
  export class GenericOidcAdapter {
21
24
  config;
22
25
  type = 'oauth';
23
- pending = new Map();
26
+ pendingFlowStore;
24
27
  fetchImpl;
25
28
  constructor(config) {
26
29
  this.config = config;
27
30
  this.fetchImpl = config.fetchImpl ?? ((url, init) => fetch(url, init));
31
+ this.pendingFlowStore = config.pendingFlowStore ?? new MemoryPendingFlowStore();
28
32
  }
29
33
  isRequired(protection) {
30
34
  return requirementMatchesAdapter(this.type, protection);
@@ -37,13 +41,14 @@ export class GenericOidcAdapter {
37
41
  const codeVerifier = randomToken(32);
38
42
  const codeChallenge = await computeS256Challenge(codeVerifier);
39
43
  const resumeToken = randomToken(24);
40
- this.pending.set(resumeToken, {
44
+ const ttlMs = this.config.resumeTokenTtlMs ?? DEFAULT_RESUME_TOKEN_TTL_MS;
45
+ await this.pendingFlowStore.put(resumeToken, {
41
46
  agentDid: params.agentDid,
42
47
  scopes,
43
48
  state: params.state,
44
49
  codeVerifier,
45
50
  redirectUri: params.redirectUri,
46
- });
51
+ }, ttlMs);
47
52
  const authorizationUrl = buildAuthorizeUrl({
48
53
  authorizationEndpoint: this.config.authorizationEndpoint,
49
54
  clientId: this.config.clientId,
@@ -57,12 +62,17 @@ export class GenericOidcAdapter {
57
62
  message: `Authorization required for "${params.protection.toolName}".`,
58
63
  authorizationUrl,
59
64
  resumeToken,
60
- expiresAt: nowMs() + (this.config.resumeTokenTtlMs ?? 600_000),
65
+ expiresAt: nowMs() + ttlMs,
61
66
  scopes,
62
67
  });
63
68
  }
64
69
  async verifyAuthorization(flowState, result) {
65
- const pending = this.pending.get(flowState);
70
+ // Atomically consume the pending flow up front: one-time use, so two
71
+ // concurrent callbacks for the same resume token can't both reach the token
72
+ // exchange (closes the replay window). The trade-off is that a transient IdP
73
+ // failure burns the token and the user re-initiates — acceptable, and the
74
+ // authorization code is itself one-time-use at the IdP.
75
+ const pending = await this.pendingFlowStore.consume(flowState);
66
76
  if (!pending) {
67
77
  return { valid: false, reason: 'unknown or expired resume token' };
68
78
  }
@@ -99,8 +109,7 @@ export class GenericOidcAdapter {
99
109
  catch (error) {
100
110
  return { valid: false, reason: `token exchange failed: ${error.message}` };
101
111
  }
102
- // One-time use: a resume token is consumed on verification.
103
- this.pending.delete(flowState);
112
+ // The flow was already atomically consumed above (one-time use).
104
113
  const grantedScopes = token.scope ? token.scope.split(' ') : pending.scopes;
105
114
  return {
106
115
  valid: true,
@@ -113,8 +122,8 @@ export class GenericOidcAdapter {
113
122
  };
114
123
  }
115
124
  /** Test/inspection seam: the pending code verifier for a resume token, if any. */
116
- pendingVerifierFor(resumeToken) {
117
- return this.pending.get(resumeToken)?.codeVerifier;
125
+ async pendingVerifierFor(resumeToken) {
126
+ return (await this.pendingFlowStore.get(resumeToken))?.codeVerifier;
118
127
  }
119
128
  }
120
129
  function randomToken(byteLength) {
@@ -1 +1 @@
1
- {"version":3,"file":"oidc-adapter.js","sourceRoot":"","sources":["../../../src/authz/oidc/oidc-adapter.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"oidc-adapter.js","sourceRoot":"","sources":["../../../src/authz/oidc/oidc-adapter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,80 @@
1
+ /**
2
+ * PendingFlowStore — the provider seam for in-flight OAuth/OIDC PKCE state.
3
+ *
4
+ * Between {@link GenericOidcAdapter.initiateFlow} (which mints a resume token and
5
+ * the PKCE `codeVerifier`) and the authorization callback (which exchanges the
6
+ * code), the verifier must be held server-side keyed by the resume token — it is
7
+ * never placed on the wire. Holding it in a per-process `Map` breaks the moment a
8
+ * second instance or a restart enters the picture: if the callback lands on
9
+ * another instance the verifier is gone, the token exchange fails closed, and no
10
+ * grant is ever minted.
11
+ *
12
+ * This seam mirrors {@link GrantStore} / `NonceCacheProvider`: the in-memory
13
+ * implementation here is the dev/reference impl; production injects a Redis /
14
+ * Durable Object / database-backed store behind the same interface so
15
+ * `initiateFlow` on instance A and the callback on instance B share one verifier.
16
+ *
17
+ * `get` (non-consuming read) and `delete` (consume) are kept separate so the
18
+ * adapter can preserve its one-time-use ordering: it reads the pending flow,
19
+ * validates `state`, performs the token exchange, and deletes ONLY after the
20
+ * exchange succeeds — so a transient IdP error does not burn the resume token.
21
+ *
22
+ * Production note: a durable backing SHOULD make `delete`-after-exchange atomic
23
+ * (e.g. Redis `GETDEL`, or a compare-and-set) to close the one-time-use replay
24
+ * window across instances.
25
+ */
26
+ /** In-flight authorization state held between initiateFlow and the callback. */
27
+ export interface PendingFlow {
28
+ agentDid: string;
29
+ scopes: string[];
30
+ state: string;
31
+ codeVerifier: string;
32
+ redirectUri: string;
33
+ }
34
+ /**
35
+ * Store for pending (awaiting-callback) OAuth/OIDC PKCE flows. Implementations
36
+ * persist a flow under a resume token with a TTL, read it back (non-consuming),
37
+ * consume it after a successful exchange, and sweep expired entries.
38
+ */
39
+ export declare abstract class PendingFlowStore {
40
+ /** Persist (or replace) a pending flow under `token`, expiring after `ttlMs`. */
41
+ abstract put(token: string, flow: PendingFlow, ttlMs: number): Promise<void>;
42
+ /** Read the pending flow without consuming it (e.g. inspection). */
43
+ abstract get(token: string): Promise<PendingFlow | undefined>;
44
+ /**
45
+ * Atomically read AND remove the pending flow — the one-time-use gate for the
46
+ * token exchange. Returns the flow if it existed and was not expired, else
47
+ * undefined; either way the token is gone afterward, so two concurrent
48
+ * callbacks for the same token can never both proceed (closes the replay
49
+ * window). Durable backings (Redis / Durable Object / DB) MUST implement this
50
+ * atomically (e.g. Redis `GETDEL`, or a compare-and-set) — a non-atomic
51
+ * read-then-delete reopens the window across instances.
52
+ */
53
+ abstract consume(token: string): Promise<PendingFlow | undefined>;
54
+ /** Remove a pending flow without reading it. */
55
+ abstract delete(token: string): Promise<void>;
56
+ /** Drop expired entries. */
57
+ abstract cleanup(): Promise<void>;
58
+ }
59
+ export interface MemoryPendingFlowStoreOptions {
60
+ /** Clock injection for tests; defaults to Date.now. */
61
+ now?: () => number;
62
+ }
63
+ /**
64
+ * In-memory {@link PendingFlowStore} — the dev/reference implementation.
65
+ *
66
+ * NOT for production: pending flows are lost on restart and are invisible to a
67
+ * sibling instance, so a callback that lands elsewhere cannot complete. Inject a
68
+ * Redis / Durable Object / database-backed store for multi-instance deployments.
69
+ */
70
+ export declare class MemoryPendingFlowStore extends PendingFlowStore {
71
+ private readonly pending;
72
+ private readonly now;
73
+ constructor(options?: MemoryPendingFlowStoreOptions);
74
+ put(token: string, flow: PendingFlow, ttlMs: number): Promise<void>;
75
+ get(token: string): Promise<PendingFlow | undefined>;
76
+ consume(token: string): Promise<PendingFlow | undefined>;
77
+ delete(token: string): Promise<void>;
78
+ cleanup(): Promise<void>;
79
+ }
80
+ //# sourceMappingURL=pending-flow-store.d.ts.map