@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.
- package/CHANGELOG.md +117 -0
- package/README.md +228 -3
- package/dist/authz/index.d.ts +1 -0
- package/dist/authz/index.d.ts.map +1 -1
- package/dist/authz/index.js +1 -0
- package/dist/authz/index.js.map +1 -1
- package/dist/authz/oidc/oidc-adapter.d.ts +10 -2
- package/dist/authz/oidc/oidc-adapter.d.ts.map +1 -1
- package/dist/authz/oidc/oidc-adapter.js +18 -9
- package/dist/authz/oidc/oidc-adapter.js.map +1 -1
- package/dist/authz/oidc/pending-flow-store.d.ts +80 -0
- package/dist/authz/oidc/pending-flow-store.d.ts.map +1 -0
- package/dist/authz/oidc/pending-flow-store.js +82 -0
- package/dist/authz/oidc/pending-flow-store.js.map +1 -0
- package/dist/card/build.d.ts +41 -0
- package/dist/card/build.d.ts.map +1 -0
- package/dist/card/build.js +47 -0
- package/dist/card/build.js.map +1 -0
- package/dist/card/builder.d.ts +99 -0
- package/dist/card/builder.d.ts.map +1 -0
- package/dist/card/builder.js +147 -0
- package/dist/card/builder.js.map +1 -0
- package/dist/card/cimd.d.ts +92 -0
- package/dist/card/cimd.d.ts.map +1 -0
- package/dist/card/cimd.js +225 -0
- package/dist/card/cimd.js.map +1 -0
- package/dist/card/delegation.d.ts +145 -0
- package/dist/card/delegation.d.ts.map +1 -0
- package/dist/card/delegation.js +293 -0
- package/dist/card/delegation.js.map +1 -0
- package/dist/card/emit.d.ts +133 -0
- package/dist/card/emit.d.ts.map +1 -0
- package/dist/card/emit.js +127 -0
- package/dist/card/emit.js.map +1 -0
- package/dist/card/index.d.ts +43 -0
- package/dist/card/index.d.ts.map +1 -0
- package/dist/card/index.js +46 -0
- package/dist/card/index.js.map +1 -0
- package/dist/card/middleware.d.ts +112 -0
- package/dist/card/middleware.d.ts.map +1 -0
- package/dist/card/middleware.js +121 -0
- package/dist/card/middleware.js.map +1 -0
- package/dist/card/proof/build.d.ts +22 -0
- package/dist/card/proof/build.d.ts.map +1 -0
- package/dist/card/proof/build.js +55 -0
- package/dist/card/proof/build.js.map +1 -0
- package/dist/card/proof/canonical.d.ts +66 -0
- package/dist/card/proof/canonical.d.ts.map +1 -0
- package/dist/card/proof/canonical.js +131 -0
- package/dist/card/proof/canonical.js.map +1 -0
- package/dist/card/proof/http-sig.d.ts +69 -0
- package/dist/card/proof/http-sig.d.ts.map +1 -0
- package/dist/card/proof/http-sig.js +101 -0
- package/dist/card/proof/http-sig.js.map +1 -0
- package/dist/card/proof/index.d.ts +25 -0
- package/dist/card/proof/index.d.ts.map +1 -0
- package/dist/card/proof/index.js +25 -0
- package/dist/card/proof/index.js.map +1 -0
- package/dist/card/proof/nonce-cache.d.ts +67 -0
- package/dist/card/proof/nonce-cache.d.ts.map +1 -0
- package/dist/card/proof/nonce-cache.js +88 -0
- package/dist/card/proof/nonce-cache.js.map +1 -0
- package/dist/card/proof/signer.d.ts +32 -0
- package/dist/card/proof/signer.d.ts.map +1 -0
- package/dist/card/proof/signer.js +59 -0
- package/dist/card/proof/signer.js.map +1 -0
- package/dist/card/proof/types.d.ts +219 -0
- package/dist/card/proof/types.d.ts.map +1 -0
- package/dist/card/proof/types.js +87 -0
- package/dist/card/proof/types.js.map +1 -0
- package/dist/card/proof/verify.d.ts +27 -0
- package/dist/card/proof/verify.d.ts.map +1 -0
- package/dist/card/proof/verify.js +236 -0
- package/dist/card/proof/verify.js.map +1 -0
- package/dist/card/resolve.d.ts +97 -0
- package/dist/card/resolve.d.ts.map +1 -0
- package/dist/card/resolve.js +223 -0
- package/dist/card/resolve.js.map +1 -0
- package/dist/card/revocation.d.ts +96 -0
- package/dist/card/revocation.d.ts.map +1 -0
- package/dist/card/revocation.js +190 -0
- package/dist/card/revocation.js.map +1 -0
- package/dist/card/schema.d.ts +177 -0
- package/dist/card/schema.d.ts.map +1 -0
- package/dist/card/schema.js +119 -0
- package/dist/card/schema.js.map +1 -0
- package/dist/card/verify.d.ts +144 -0
- package/dist/card/verify.d.ts.map +1 -0
- package/dist/card/verify.js +132 -0
- package/dist/card/verify.js.map +1 -0
- package/dist/delegation/bitstring.d.ts +9 -7
- package/dist/delegation/bitstring.d.ts.map +1 -1
- package/dist/delegation/bitstring.js +70 -37
- package/dist/delegation/bitstring.js.map +1 -1
- package/dist/delegation/did-linkage.d.ts +23 -0
- package/dist/delegation/did-linkage.d.ts.map +1 -0
- package/dist/delegation/did-linkage.js +57 -0
- package/dist/delegation/did-linkage.js.map +1 -0
- package/dist/delegation/did-resolver-registry.d.ts +7 -0
- package/dist/delegation/did-resolver-registry.d.ts.map +1 -0
- package/dist/delegation/did-resolver-registry.js +20 -0
- package/dist/delegation/did-resolver-registry.js.map +1 -0
- package/dist/delegation/did-web-resolver.d.ts +29 -18
- package/dist/delegation/did-web-resolver.d.ts.map +1 -1
- package/dist/delegation/did-web-resolver.js +65 -35
- package/dist/delegation/did-web-resolver.js.map +1 -1
- package/dist/delegation/index.d.ts +3 -0
- package/dist/delegation/index.d.ts.map +1 -1
- package/dist/delegation/index.js +3 -0
- package/dist/delegation/index.js.map +1 -1
- package/dist/delegation/statuslist-manager.d.ts.map +1 -1
- package/dist/delegation/statuslist-manager.js +16 -1
- package/dist/delegation/statuslist-manager.js.map +1 -1
- package/dist/delegation/vc-jwt-verify.d.ts +61 -0
- package/dist/delegation/vc-jwt-verify.d.ts.map +1 -0
- package/dist/delegation/vc-jwt-verify.js +131 -0
- package/dist/delegation/vc-jwt-verify.js.map +1 -0
- package/dist/delegation/vc-verification-checks.d.ts +50 -0
- package/dist/delegation/vc-verification-checks.d.ts.map +1 -0
- package/dist/delegation/vc-verification-checks.js +212 -0
- package/dist/delegation/vc-verification-checks.js.map +1 -0
- package/dist/delegation/vc-verifier.d.ts +24 -61
- package/dist/delegation/vc-verifier.d.ts.map +1 -1
- package/dist/delegation/vc-verifier.js +57 -180
- package/dist/delegation/vc-verifier.js.map +1 -1
- package/dist/delegation/vc-verifier.types.d.ts +88 -0
- package/dist/delegation/vc-verifier.types.d.ts.map +1 -0
- package/dist/delegation/vc-verifier.types.js +9 -0
- package/dist/delegation/vc-verifier.types.js.map +1 -0
- package/dist/index.d.ts +8 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -3
- package/dist/index.js.map +1 -1
- package/dist/integrations/cheqd/dlr.d.ts +44 -0
- package/dist/integrations/cheqd/dlr.d.ts.map +1 -0
- package/dist/integrations/cheqd/dlr.js +86 -0
- package/dist/integrations/cheqd/dlr.js.map +1 -0
- package/dist/integrations/cheqd/index.d.ts +5 -0
- package/dist/integrations/cheqd/index.d.ts.map +1 -0
- package/dist/integrations/cheqd/index.js +5 -0
- package/dist/integrations/cheqd/index.js.map +1 -0
- package/dist/integrations/cheqd/linkage.d.ts +20 -0
- package/dist/integrations/cheqd/linkage.d.ts.map +1 -0
- package/dist/integrations/cheqd/linkage.js +32 -0
- package/dist/integrations/cheqd/linkage.js.map +1 -0
- package/dist/integrations/cheqd/registrar.d.ts +85 -0
- package/dist/integrations/cheqd/registrar.d.ts.map +1 -0
- package/dist/integrations/cheqd/registrar.js +304 -0
- package/dist/integrations/cheqd/registrar.js.map +1 -0
- package/dist/integrations/cheqd/resolver.d.ts +38 -0
- package/dist/integrations/cheqd/resolver.d.ts.map +1 -0
- package/dist/integrations/cheqd/resolver.js +156 -0
- package/dist/integrations/cheqd/resolver.js.map +1 -0
- package/dist/middleware/index.d.ts +2 -0
- package/dist/middleware/index.d.ts.map +1 -1
- package/dist/middleware/index.js +5 -0
- package/dist/middleware/index.js.map +1 -1
- package/dist/middleware/kya-os-transport.d.ts +2 -1
- package/dist/middleware/kya-os-transport.d.ts.map +1 -1
- package/dist/middleware/kya-os-transport.js +2 -1
- package/dist/middleware/kya-os-transport.js.map +1 -1
- package/dist/middleware/with-kya-os-server.d.ts +21 -4
- package/dist/middleware/with-kya-os-server.d.ts.map +1 -1
- package/dist/middleware/with-kya-os-server.js +4 -0
- package/dist/middleware/with-kya-os-server.js.map +1 -1
- package/dist/middleware/with-kya-os.config-types.d.ts +139 -0
- package/dist/middleware/with-kya-os.config-types.d.ts.map +1 -0
- package/dist/middleware/with-kya-os.config-types.js +9 -0
- package/dist/middleware/with-kya-os.config-types.js.map +1 -0
- package/dist/middleware/with-kya-os.d.ts +10 -238
- package/dist/middleware/with-kya-os.d.ts.map +1 -1
- package/dist/middleware/with-kya-os.delegation-gate.d.ts +19 -0
- package/dist/middleware/with-kya-os.delegation-gate.d.ts.map +1 -0
- package/dist/middleware/with-kya-os.delegation-gate.js +175 -0
- package/dist/middleware/with-kya-os.delegation-gate.js.map +1 -0
- package/dist/middleware/with-kya-os.delegation-verify.d.ts +51 -0
- package/dist/middleware/with-kya-os.delegation-verify.d.ts.map +1 -0
- package/dist/middleware/with-kya-os.delegation-verify.js +165 -0
- package/dist/middleware/with-kya-os.delegation-verify.js.map +1 -0
- package/dist/middleware/with-kya-os.deps.d.ts +40 -0
- package/dist/middleware/with-kya-os.deps.d.ts.map +1 -0
- package/dist/middleware/with-kya-os.deps.js +9 -0
- package/dist/middleware/with-kya-os.deps.js.map +1 -0
- package/dist/middleware/with-kya-os.grants.d.ts +30 -0
- package/dist/middleware/with-kya-os.grants.d.ts.map +1 -0
- package/dist/middleware/with-kya-os.grants.js +145 -0
- package/dist/middleware/with-kya-os.grants.js.map +1 -0
- package/dist/middleware/with-kya-os.helpers.d.ts +24 -0
- package/dist/middleware/with-kya-os.helpers.d.ts.map +1 -0
- package/dist/middleware/with-kya-os.helpers.js +57 -0
- package/dist/middleware/with-kya-os.helpers.js.map +1 -0
- package/dist/middleware/with-kya-os.js +65 -703
- package/dist/middleware/with-kya-os.js.map +1 -1
- package/dist/middleware/with-kya-os.policy-gate.d.ts +16 -0
- package/dist/middleware/with-kya-os.policy-gate.d.ts.map +1 -0
- package/dist/middleware/with-kya-os.policy-gate.js +98 -0
- package/dist/middleware/with-kya-os.policy-gate.js.map +1 -0
- package/dist/middleware/with-kya-os.protocol.d.ts +29 -0
- package/dist/middleware/with-kya-os.protocol.d.ts.map +1 -0
- package/dist/middleware/with-kya-os.protocol.js +121 -0
- package/dist/middleware/with-kya-os.protocol.js.map +1 -0
- package/dist/middleware/with-kya-os.session.d.ts +32 -0
- package/dist/middleware/with-kya-os.session.d.ts.map +1 -0
- package/dist/middleware/with-kya-os.session.js +201 -0
- package/dist/middleware/with-kya-os.session.js.map +1 -0
- package/dist/middleware/with-kya-os.types.d.ts +178 -0
- package/dist/middleware/with-kya-os.types.d.ts.map +1 -0
- package/dist/middleware/with-kya-os.types.js +13 -0
- package/dist/middleware/with-kya-os.types.js.map +1 -0
- package/dist/proof/generator.d.ts +21 -0
- package/dist/proof/generator.d.ts.map +1 -1
- package/dist/proof/generator.js +21 -0
- package/dist/proof/generator.js.map +1 -1
- package/dist/proof/index.d.ts +1 -1
- package/dist/proof/index.d.ts.map +1 -1
- package/dist/proof/index.js +1 -1
- package/dist/proof/index.js.map +1 -1
- package/dist/proof/verifier.d.ts +26 -3
- package/dist/proof/verifier.d.ts.map +1 -1
- package/dist/proof/verifier.js +54 -24
- package/dist/proof/verifier.js.map +1 -1
- package/dist/providers/grant-store.d.ts +10 -1
- package/dist/providers/grant-store.d.ts.map +1 -1
- package/dist/providers/grant-store.js.map +1 -1
- package/dist/providers/runtime-fetch.d.ts +8 -0
- package/dist/providers/runtime-fetch.d.ts.map +1 -1
- package/dist/providers/runtime-fetch.js +17 -0
- package/dist/providers/runtime-fetch.js.map +1 -1
- package/dist/providers/web-crypto.d.ts.map +1 -1
- package/dist/providers/web-crypto.js +15 -7
- package/dist/providers/web-crypto.js.map +1 -1
- package/dist/session/index.d.ts +1 -0
- package/dist/session/index.d.ts.map +1 -1
- package/dist/session/index.js +1 -0
- package/dist/session/index.js.map +1 -1
- package/dist/session/manager.d.ts +17 -6
- package/dist/session/manager.d.ts.map +1 -1
- package/dist/session/manager.js +16 -26
- package/dist/session/manager.js.map +1 -1
- package/dist/session/session-store.d.ts +78 -0
- package/dist/session/session-store.d.ts.map +1 -0
- package/dist/session/session-store.js +79 -0
- package/dist/session/session-store.js.map +1 -0
- package/dist/types/protocol.d.ts +9 -3
- package/dist/types/protocol.d.ts.map +1 -1
- package/dist/types/protocol.js.map +1 -1
- package/dist/utils/guards.d.ts +2 -0
- package/dist/utils/guards.d.ts.map +1 -0
- package/dist/utils/guards.js +4 -0
- package/dist/utils/guards.js.map +1 -0
- package/dist/utils/index.d.ts +3 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +3 -0
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/ip-classifier.d.ts +12 -0
- package/dist/utils/ip-classifier.d.ts.map +1 -0
- package/dist/utils/ip-classifier.js +153 -0
- package/dist/utils/ip-classifier.js.map +1 -0
- package/dist/utils/safe-fetch-transports.d.ts +40 -0
- package/dist/utils/safe-fetch-transports.d.ts.map +1 -0
- package/dist/utils/safe-fetch-transports.js +121 -0
- package/dist/utils/safe-fetch-transports.js.map +1 -0
- package/dist/utils/safe-fetch-types.d.ts +66 -0
- package/dist/utils/safe-fetch-types.d.ts.map +1 -0
- package/dist/utils/safe-fetch-types.js +10 -0
- package/dist/utils/safe-fetch-types.js.map +1 -0
- package/dist/utils/safe-fetch.d.ts +40 -0
- package/dist/utils/safe-fetch.d.ts.map +1 -0
- package/dist/utils/safe-fetch.js +188 -0
- package/dist/utils/safe-fetch.js.map +1 -0
- package/dist/utils/statuslist-purpose.d.ts +12 -0
- package/dist/utils/statuslist-purpose.d.ts.map +1 -0
- package/dist/utils/statuslist-purpose.js +19 -0
- package/dist/utils/statuslist-purpose.js.map +1 -0
- package/dist/utils/url.d.ts +2 -0
- package/dist/utils/url.d.ts.map +1 -0
- package/dist/utils/url.js +8 -0
- package/dist/utils/url.js.map +1 -0
- package/package.json +25 -5
- package/schemas/README.md +2 -1
- package/schemas/card-delegation-credential.json +239 -0
- 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`
|
|
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
|
package/dist/authz/index.d.ts
CHANGED
|
@@ -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"}
|
package/dist/authz/index.js
CHANGED
|
@@ -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
|
package/dist/authz/index.js.map
CHANGED
|
@@ -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
|
|
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;
|
|
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
|
-
|
|
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.
|
|
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() +
|
|
65
|
+
expiresAt: nowMs() + ttlMs,
|
|
61
66
|
scopes,
|
|
62
67
|
});
|
|
63
68
|
}
|
|
64
69
|
async verifyAuthorization(flowState, result) {
|
|
65
|
-
|
|
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
|
-
//
|
|
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.
|
|
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":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,MAAM,CAAC;AACjC,OAAO,EACL,6BAA6B,GAE9B,MAAM,yBAAyB,CAAC;AAGjC,OAAO,EAAE,yBAAyB,EAAE,MAAM,eAAe,CAAC;AAC1D,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC;
|
|
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
|