@kya-os/mcp-i-core 1.2.3-canary.7 → 1.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/settings.local.json +9 -0
- package/.turbo/turbo-build.log +4 -0
- package/.turbo/turbo-test.log +2979 -0
- package/COMPLIANCE_IMPROVEMENT_REPORT.md +483 -0
- package/Composer 3.md +615 -0
- package/GPT-5.md +1169 -0
- package/OPUS-plan.md +352 -0
- package/PHASE_3_AND_4.1_SUMMARY.md +585 -0
- package/PHASE_3_SUMMARY.md +317 -0
- package/PHASE_4.1.3_SUMMARY.md +428 -0
- package/PHASE_4.1_COMPLETE.md +525 -0
- package/PHASE_4_USER_DID_IDENTITY_LINKING_PLAN.md +1240 -0
- package/SCHEMA_COMPLIANCE_REPORT.md +275 -0
- package/TEST_PLAN.md +571 -0
- package/coverage/coverage-final.json +57 -0
- package/dist/__tests__/utils/mock-providers.d.ts +1 -2
- package/dist/__tests__/utils/mock-providers.d.ts.map +1 -1
- package/dist/__tests__/utils/mock-providers.js.map +1 -1
- package/dist/cache/oauth-config-cache.d.ts +69 -0
- package/dist/cache/oauth-config-cache.d.ts.map +1 -0
- package/dist/cache/oauth-config-cache.js +76 -0
- package/dist/cache/oauth-config-cache.js.map +1 -0
- package/dist/identity/idp-token-resolver.d.ts +53 -0
- package/dist/identity/idp-token-resolver.d.ts.map +1 -0
- package/dist/identity/idp-token-resolver.js +108 -0
- package/dist/identity/idp-token-resolver.js.map +1 -0
- package/dist/identity/idp-token-storage.interface.d.ts +42 -0
- package/dist/identity/idp-token-storage.interface.d.ts.map +1 -0
- package/dist/identity/idp-token-storage.interface.js +12 -0
- package/dist/identity/idp-token-storage.interface.js.map +1 -0
- package/dist/identity/user-did-manager.d.ts +39 -1
- package/dist/identity/user-did-manager.d.ts.map +1 -1
- package/dist/identity/user-did-manager.js +69 -3
- package/dist/identity/user-did-manager.js.map +1 -1
- package/dist/index.d.ts +22 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +39 -1
- package/dist/index.js.map +1 -1
- package/dist/runtime/audit-logger.d.ts +37 -0
- package/dist/runtime/audit-logger.d.ts.map +1 -0
- package/dist/runtime/audit-logger.js +9 -0
- package/dist/runtime/audit-logger.js.map +1 -0
- package/dist/runtime/base.d.ts +58 -2
- package/dist/runtime/base.d.ts.map +1 -1
- package/dist/runtime/base.js +266 -11
- package/dist/runtime/base.js.map +1 -1
- package/dist/services/access-control.service.d.ts.map +1 -1
- package/dist/services/access-control.service.js +200 -35
- package/dist/services/access-control.service.js.map +1 -1
- package/dist/services/authorization/authorization-registry.d.ts +29 -0
- package/dist/services/authorization/authorization-registry.d.ts.map +1 -0
- package/dist/services/authorization/authorization-registry.js +57 -0
- package/dist/services/authorization/authorization-registry.js.map +1 -0
- package/dist/services/authorization/types.d.ts +53 -0
- package/dist/services/authorization/types.d.ts.map +1 -0
- package/dist/services/authorization/types.js +10 -0
- package/dist/services/authorization/types.js.map +1 -0
- package/dist/services/batch-delegation.service.d.ts +53 -0
- package/dist/services/batch-delegation.service.d.ts.map +1 -0
- package/dist/services/batch-delegation.service.js +95 -0
- package/dist/services/batch-delegation.service.js.map +1 -0
- package/dist/services/oauth-config.service.d.ts +53 -0
- package/dist/services/oauth-config.service.d.ts.map +1 -0
- package/dist/services/oauth-config.service.js +119 -0
- package/dist/services/oauth-config.service.js.map +1 -0
- package/dist/services/oauth-provider-registry.d.ts +88 -0
- package/dist/services/oauth-provider-registry.d.ts.map +1 -0
- package/dist/services/oauth-provider-registry.js +128 -0
- package/dist/services/oauth-provider-registry.js.map +1 -0
- package/dist/services/oauth-service.d.ts +77 -0
- package/dist/services/oauth-service.d.ts.map +1 -0
- package/dist/services/oauth-service.js +348 -0
- package/dist/services/oauth-service.js.map +1 -0
- package/dist/services/oauth-token-retrieval.service.d.ts +49 -0
- package/dist/services/oauth-token-retrieval.service.d.ts.map +1 -0
- package/dist/services/oauth-token-retrieval.service.js +150 -0
- package/dist/services/oauth-token-retrieval.service.js.map +1 -0
- package/dist/services/provider-resolver.d.ts +48 -0
- package/dist/services/provider-resolver.d.ts.map +1 -0
- package/dist/services/provider-resolver.js +121 -0
- package/dist/services/provider-resolver.js.map +1 -0
- package/dist/services/provider-validator.d.ts +55 -0
- package/dist/services/provider-validator.d.ts.map +1 -0
- package/dist/services/provider-validator.js +135 -0
- package/dist/services/provider-validator.js.map +1 -0
- package/dist/services/tool-context-builder.d.ts +57 -0
- package/dist/services/tool-context-builder.d.ts.map +1 -0
- package/dist/services/tool-context-builder.js +125 -0
- package/dist/services/tool-context-builder.js.map +1 -0
- package/dist/services/tool-protection.service.d.ts +87 -10
- package/dist/services/tool-protection.service.d.ts.map +1 -1
- package/dist/services/tool-protection.service.js +282 -112
- package/dist/services/tool-protection.service.js.map +1 -1
- package/dist/types/oauth-required-error.d.ts +40 -0
- package/dist/types/oauth-required-error.d.ts.map +1 -0
- package/dist/types/oauth-required-error.js +40 -0
- package/dist/types/oauth-required-error.js.map +1 -0
- package/dist/utils/did-helpers.d.ts +33 -0
- package/dist/utils/did-helpers.d.ts.map +1 -1
- package/dist/utils/did-helpers.js +40 -0
- package/dist/utils/did-helpers.js.map +1 -1
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +1 -0
- package/dist/utils/index.js.map +1 -1
- package/docs/API_REFERENCE.md +1362 -0
- package/docs/COMPLIANCE_MATRIX.md +691 -0
- package/docs/STATUSLIST2021_GUIDE.md +696 -0
- package/docs/W3C_VC_DELEGATION_GUIDE.md +710 -0
- package/package.json +24 -50
- package/scripts/audit-compliance.ts +724 -0
- package/src/__tests__/cache/tool-protection-cache.test.ts +640 -0
- package/src/__tests__/config/provider-runtime-config.test.ts +309 -0
- package/src/__tests__/delegation-e2e.test.ts +690 -0
- package/src/__tests__/identity/user-did-manager.test.ts +213 -0
- package/src/__tests__/index.test.ts +56 -0
- package/src/__tests__/integration/full-flow.test.ts +776 -0
- package/src/__tests__/integration.test.ts +281 -0
- package/src/__tests__/providers/base.test.ts +173 -0
- package/src/__tests__/providers/memory.test.ts +319 -0
- package/src/__tests__/regression/phase2-regression.test.ts +429 -0
- package/src/__tests__/runtime/audit-logger.test.ts +154 -0
- package/src/__tests__/runtime/base-extensions.test.ts +593 -0
- package/src/__tests__/runtime/base.test.ts +869 -0
- package/src/__tests__/runtime/delegation-flow.test.ts +164 -0
- package/src/__tests__/runtime/proof-client-did.test.ts +375 -0
- package/src/__tests__/runtime/route-interception.test.ts +686 -0
- package/src/__tests__/runtime/tool-protection-enforcement.test.ts +908 -0
- package/src/__tests__/services/agentshield-integration.test.ts +784 -0
- package/src/__tests__/services/provider-resolver-edge-cases.test.ts +591 -0
- package/src/__tests__/services/tool-protection-oauth-provider.test.ts +480 -0
- package/src/__tests__/services/tool-protection.service.test.ts +1366 -0
- package/src/__tests__/utils/mock-providers.ts +340 -0
- package/src/cache/oauth-config-cache.d.ts +69 -0
- package/src/cache/oauth-config-cache.d.ts.map +1 -0
- package/src/cache/oauth-config-cache.js.map +1 -0
- package/src/cache/oauth-config-cache.ts +123 -0
- package/src/cache/tool-protection-cache.ts +171 -0
- package/src/compliance/EXAMPLE.md +412 -0
- package/src/compliance/__tests__/schema-verifier.test.ts +797 -0
- package/src/compliance/index.ts +8 -0
- package/src/compliance/schema-registry.ts +460 -0
- package/src/compliance/schema-verifier.ts +708 -0
- package/src/config/__tests__/remote-config.spec.ts +268 -0
- package/src/config/remote-config.ts +174 -0
- package/src/config.ts +309 -0
- package/src/delegation/__tests__/audience-validator.test.ts +112 -0
- package/src/delegation/__tests__/bitstring.test.ts +346 -0
- package/src/delegation/__tests__/cascading-revocation.test.ts +628 -0
- package/src/delegation/__tests__/delegation-graph.test.ts +584 -0
- package/src/delegation/__tests__/utils.test.ts +152 -0
- package/src/delegation/__tests__/vc-issuer.test.ts +442 -0
- package/src/delegation/__tests__/vc-verifier.test.ts +922 -0
- package/src/delegation/audience-validator.ts +52 -0
- package/src/delegation/bitstring.ts +278 -0
- package/src/delegation/cascading-revocation.ts +370 -0
- package/src/delegation/delegation-graph.ts +299 -0
- package/src/delegation/index.ts +14 -0
- package/src/delegation/statuslist-manager.ts +353 -0
- package/src/delegation/storage/__tests__/memory-graph-storage.test.ts +366 -0
- package/src/delegation/storage/__tests__/memory-statuslist-storage.test.ts +228 -0
- package/src/delegation/storage/index.ts +9 -0
- package/src/delegation/storage/memory-graph-storage.ts +178 -0
- package/src/delegation/storage/memory-statuslist-storage.ts +77 -0
- package/src/delegation/utils.ts +42 -0
- package/src/delegation/vc-issuer.ts +232 -0
- package/src/delegation/vc-verifier.ts +568 -0
- package/src/identity/idp-token-resolver.ts +147 -0
- package/src/identity/idp-token-storage.interface.ts +59 -0
- package/src/identity/user-did-manager.ts +370 -0
- package/src/index.ts +260 -0
- package/src/providers/base.d.ts +91 -0
- package/src/providers/base.d.ts.map +1 -0
- package/src/providers/base.js.map +1 -0
- package/src/providers/base.ts +96 -0
- package/src/providers/memory.ts +142 -0
- package/src/runtime/audit-logger.ts +39 -0
- package/src/runtime/base.ts +1329 -0
- package/src/services/__tests__/access-control.integration.test.ts +443 -0
- package/src/services/__tests__/access-control.proof-response-validation.test.ts +578 -0
- package/src/services/__tests__/access-control.service.test.ts +970 -0
- package/src/services/__tests__/batch-delegation.service.test.ts +351 -0
- package/src/services/__tests__/crypto.service.test.ts +531 -0
- package/src/services/__tests__/oauth-provider-registry.test.ts +142 -0
- package/src/services/__tests__/proof-verifier.integration.test.ts +485 -0
- package/src/services/__tests__/proof-verifier.test.ts +489 -0
- package/src/services/__tests__/provider-resolution.integration.test.ts +202 -0
- package/src/services/__tests__/provider-resolver.test.ts +213 -0
- package/src/services/__tests__/storage.service.test.ts +358 -0
- package/src/services/access-control.service.ts +990 -0
- package/src/services/authorization/authorization-registry.ts +66 -0
- package/src/services/authorization/types.ts +71 -0
- package/src/services/batch-delegation.service.ts +137 -0
- package/src/services/crypto.service.ts +302 -0
- package/src/services/errors.ts +76 -0
- package/src/services/index.ts +9 -0
- package/src/services/oauth-config.service.d.ts +53 -0
- package/src/services/oauth-config.service.d.ts.map +1 -0
- package/src/services/oauth-config.service.js.map +1 -0
- package/src/services/oauth-config.service.ts +169 -0
- package/src/services/oauth-provider-registry.d.ts +57 -0
- package/src/services/oauth-provider-registry.d.ts.map +1 -0
- package/src/services/oauth-provider-registry.js.map +1 -0
- package/src/services/oauth-provider-registry.ts +141 -0
- package/src/services/oauth-service.ts +510 -0
- package/src/services/oauth-token-retrieval.service.ts +245 -0
- package/src/services/proof-verifier.ts +478 -0
- package/src/services/provider-resolver.d.ts +48 -0
- package/src/services/provider-resolver.d.ts.map +1 -0
- package/src/services/provider-resolver.js.map +1 -0
- package/src/services/provider-resolver.ts +146 -0
- package/src/services/provider-validator.ts +170 -0
- package/src/services/storage.service.ts +566 -0
- package/src/services/tool-context-builder.ts +172 -0
- package/src/services/tool-protection.service.ts +958 -0
- package/src/types/oauth-required-error.ts +63 -0
- package/src/types/tool-protection.ts +155 -0
- package/src/utils/__tests__/did-helpers.test.ts +101 -0
- package/src/utils/base64.ts +148 -0
- package/src/utils/cors.ts +83 -0
- package/src/utils/did-helpers.ts +150 -0
- package/src/utils/index.ts +8 -0
- package/src/utils/storage-keys.ts +278 -0
- package/tsconfig.json +21 -0
- package/vitest.config.ts +56 -0
package/GPT-5.md
ADDED
|
@@ -0,0 +1,1169 @@
|
|
|
1
|
+
## Phase 4 — User DID & Identity Linking (Polished Plan, MCP‑I §3.1 Compliant)
|
|
2
|
+
|
|
3
|
+
Status: Ready for implementation
|
|
4
|
+
Scope: MCP‑I Identity, Consent, Delegation, OAuth Linking, Cross‑Agent Validation
|
|
5
|
+
Primary repos: `xmcp-i` (this), AgentShield/bouncer dashboard (API), Know‑That‑AI (reputation – advisory)
|
|
6
|
+
|
|
7
|
+
### Executive Summary
|
|
8
|
+
Phase 4 delivers persistent User identity by linking OAuth identities to User DIDs and using the User DID as `issuerDid` for delegations. It fixes consent→delegation gaps, resolves multi‑tenant conflicts, and aligns on strict API contracts and error formats. The outcome is spec‑compliant delegation across sessions and agents, with robust observability and privacy controls.
|
|
9
|
+
|
|
10
|
+
— Core moves
|
|
11
|
+
- Use OAuth identity → User DID linking for persistence.
|
|
12
|
+
- Delegation issuance: `issuerDid` = User DID, `subjectDid` = Agent DID.
|
|
13
|
+
- Store delegation tokens per user+agent; session cache is a fast path.
|
|
14
|
+
- Validate with decentralized VCs first; fall back to OAuth verification if needed.
|
|
15
|
+
- Strict API parity with AgentShield wrapper `{ success, data, metadata }` and error `{ code, message, details }`.
|
|
16
|
+
|
|
17
|
+
— Why this is game‑changing
|
|
18
|
+
- True cross‑agent portability via DID/VCs, not just OAuth sessions.
|
|
19
|
+
- Seamless UX: first consent creates delegation; later sessions just work.
|
|
20
|
+
- Enterprise‑ready controls: audit, privacy APIs, and chain validation.
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
### Architecture Overview
|
|
24
|
+
|
|
25
|
+
1) Identity model (three DIDs)
|
|
26
|
+
- Server DID: Receiver of MCP calls (bouncer or app server)
|
|
27
|
+
- Agent DID: Requesting software (Claude Desktop, SaaS agents, other MCP servers)
|
|
28
|
+
- User DID: Human user granting permission; becomes `issuerDid` in delegations
|
|
29
|
+
|
|
30
|
+
2) Persistence & linking
|
|
31
|
+
- OAuth callback links `oauth:{provider}:{subject}` → `userDid` (KV)
|
|
32
|
+
- `UserDidManager` retrieves/creates User DID based on session or OAuth identity
|
|
33
|
+
|
|
34
|
+
3) Delegation issuance (Consent → AgentShield)
|
|
35
|
+
- Consent approval constructs a spec‑aligned request embedding `issuerDid` and `subjectDid`
|
|
36
|
+
- Transitional compatibility: if AgentShield endpoint hasn’t adopted `issuer_did`/`subject_did`, include `issuerDid` in `metadata` and continue using `agent_did` until API parity lands; add deprecation header to surface the gap
|
|
37
|
+
|
|
38
|
+
4) Token storage (multi‑tenant safe)
|
|
39
|
+
- Primary key: `delegation:user:{userDid}:agent:{agentDid}` (KV)
|
|
40
|
+
- Session key: `delegation:session:{sessionId}` (short TTL for speed)
|
|
41
|
+
|
|
42
|
+
5) Verification order (Edge verification policy)
|
|
43
|
+
- First try decentralized VC verification (DID + VC chain, CRISP constraints, revocation)
|
|
44
|
+
- If absent or invalid, fall back to AgentShield OAuth verification
|
|
45
|
+
- Always produce audit logs and parity‑safe error wrappers
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
### End‑to‑End Flows
|
|
49
|
+
|
|
50
|
+
1) First‑time consent
|
|
51
|
+
2. Handshake initializes session; `agentDid` captured; ephemeral `userDid` is generated
|
|
52
|
+
3. Tool call requires scopes → raise `DelegationRequiredError` with consent URL
|
|
53
|
+
4. User approves on consent page; page posts approval to `/consent/approve`
|
|
54
|
+
5. Service constructs delegation creation payload with `issuerDid` and `subjectDid`
|
|
55
|
+
6. AgentShield returns a delegation token (and/or VC); store per user+agent and session
|
|
56
|
+
7. Success page auto‑closes and returns control to client
|
|
57
|
+
|
|
58
|
+
8) Return session
|
|
59
|
+
9. Handshake finds OAuth cookie or identity → retrieve `userDid` via link
|
|
60
|
+
10. Tool call: delegation token found via session key or user+agent cache
|
|
61
|
+
11. No consent required; call proceeds
|
|
62
|
+
|
|
63
|
+
12) Cross‑agent validation
|
|
64
|
+
13. External agent calls bouncer; provides agent DID
|
|
65
|
+
14. Verify VC chain; if unavailable, call AgentShield `delegations/verify` for that `agent_did` + scopes
|
|
66
|
+
15. Decision response uses standard success/error wrapper
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
### API Contracts and Parity
|
|
70
|
+
|
|
71
|
+
All endpoints must follow the wrapper:
|
|
72
|
+
```json
|
|
73
|
+
{ "success": true, "data": { ... }, "metadata": { ... } }
|
|
74
|
+
```
|
|
75
|
+
Errors:
|
|
76
|
+
```json
|
|
77
|
+
{ "code": "string", "message": "string", "details": { ... } }
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
AgentShield endpoints (must remain parity‑consistent)
|
|
81
|
+
- POST `/api/v1/bouncer/delegations/verify`
|
|
82
|
+
- Request: `{ agent_did: string, scopes: string[], credential_jwt?: string, timestamp?: number, client_info?: any }`
|
|
83
|
+
- Response: `{ success, data: { valid: boolean, reason?: string, expiresAt?: number } }`
|
|
84
|
+
- GET `/api/v1/bouncer/config/{projectId}`
|
|
85
|
+
- Response: `{ success, data: { tools: Record<string, { scopes: string[], requiresDelegation: boolean }> } }`
|
|
86
|
+
- POST `/api/v1/bouncer/proofs`
|
|
87
|
+
- Request: `{ proof: string, session: { id: string, audience: string, agentDid: string } }`
|
|
88
|
+
- Response: `{ success, data: { verified: boolean, ... } }`
|
|
89
|
+
|
|
90
|
+
Delegation creation (transitional until AgentShield upgrades)
|
|
91
|
+
- If AgentShield supports spec names now:
|
|
92
|
+
- Request: `{ issuer_did: string, subject_did: string, scopes: string[], expires_in_days?: number, constraints?: {...}, metadata?: {...} }`
|
|
93
|
+
- If not yet:
|
|
94
|
+
- Request: `{ agent_did: string, scopes: string[], expires_in_days?: number, metadata?: { issuer_did: string, subject_did: string, ... } }`
|
|
95
|
+
- Include a `Deprecation: use-issuer_did/subject_did` header where possible
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
### Contracts and Validation (in `@kya-os/contracts`)
|
|
99
|
+
|
|
100
|
+
Consent Approval (back‑compat + new fields optional)
|
|
101
|
+
```ts
|
|
102
|
+
export const consentApprovalRequestSchema = z.object({
|
|
103
|
+
tool: z.string().min(1),
|
|
104
|
+
scopes: z.array(z.string()),
|
|
105
|
+
agent_did: z.string(),
|
|
106
|
+
session_id: z.string(),
|
|
107
|
+
project_id: z.string(),
|
|
108
|
+
termsAccepted: z.boolean(),
|
|
109
|
+
termsVersion: z.string().max(50).optional(),
|
|
110
|
+
customFields: z.record(z.union([z.string(), z.boolean()])).optional(),
|
|
111
|
+
|
|
112
|
+
// NEW (optional; back‑compatible)
|
|
113
|
+
oauth_identity: z.object({
|
|
114
|
+
provider: z.enum(['google','github','microsoft','custom']),
|
|
115
|
+
subject: z.string(),
|
|
116
|
+
email: z.string().email().optional(),
|
|
117
|
+
name: z.string().optional(),
|
|
118
|
+
}).optional(),
|
|
119
|
+
user_did: z.string().optional(),
|
|
120
|
+
});
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Handshake (optional client info)
|
|
124
|
+
```ts
|
|
125
|
+
export const HandshakeRequestSchema = z.object({
|
|
126
|
+
nonce: z.string().min(1),
|
|
127
|
+
audience: z.string().min(1),
|
|
128
|
+
timestamp: z.number().int().positive(),
|
|
129
|
+
agentDid: z.string().startsWith('did:').optional(),
|
|
130
|
+
clientInfo: z.object({
|
|
131
|
+
name: z.string(),
|
|
132
|
+
version: z.string(),
|
|
133
|
+
platform: z.string(),
|
|
134
|
+
}).optional(),
|
|
135
|
+
});
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Error Types (shared)
|
|
139
|
+
```ts
|
|
140
|
+
export const AgentErrorSchema = z.object({
|
|
141
|
+
code: z.string(),
|
|
142
|
+
message: z.string(),
|
|
143
|
+
details: z.unknown().optional(),
|
|
144
|
+
});
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
### Implementation Changes (xmcp‑i)
|
|
149
|
+
|
|
150
|
+
1) Consent → Delegation creation (fix critical gap)
|
|
151
|
+
- File: `packages/mcp-i-cloudflare/src/services/consent.service.ts`
|
|
152
|
+
- Build delegation request with `issuerDid` and `subjectDid`:
|
|
153
|
+
```ts
|
|
154
|
+
const userDid = await this.getUserDidForSession(request.session_id);
|
|
155
|
+
const delegationRequest = {
|
|
156
|
+
issuer_did: userDid,
|
|
157
|
+
subject_did: request.agent_did,
|
|
158
|
+
scopes: request.scopes,
|
|
159
|
+
expires_in_days: expiresInDays,
|
|
160
|
+
...(request.customFields && Object.keys(request.customFields).length > 0
|
|
161
|
+
? { metadata: request.customFields }
|
|
162
|
+
: {}),
|
|
163
|
+
};
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
2) User DID retrieval
|
|
167
|
+
- Add private method in `ConsentService`:
|
|
168
|
+
```ts
|
|
169
|
+
private async getUserDidForSession(sessionId: string): Promise<string> {
|
|
170
|
+
const session = await this.sessionStorage.get(sessionId);
|
|
171
|
+
if (session?.userDid) return session.userDid;
|
|
172
|
+
const userDidManager = new UserDidManager({ crypto: this.cryptoProvider, storage: this.userDidStorage });
|
|
173
|
+
const userDid = await userDidManager.getOrCreateUserDid(sessionId);
|
|
174
|
+
await this.sessionStorage.set(sessionId, { ...session, userDid });
|
|
175
|
+
return userDid;
|
|
176
|
+
}
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
3) OAuth callback → link identity to DID
|
|
180
|
+
- File: `packages/mcp-i-cloudflare/src/runtime/oauth-handler.ts`
|
|
181
|
+
- Link key: `oauth:{provider}:{subject}` → `{ userDid, email?, name?, linkedAt, lastUsed }`
|
|
182
|
+
- Set `user_did` cookie post‑callback
|
|
183
|
+
|
|
184
|
+
4) Multi‑tenant storage keys
|
|
185
|
+
- File: `packages/mcp-i-cloudflare/src/services/consent.service.ts`
|
|
186
|
+
```ts
|
|
187
|
+
const userAgentKey = `delegation:user:${userDid}:agent:${agentDid}`;
|
|
188
|
+
await this.delegationStorage.set(userAgentKey, token, { expirationTtl: 24 * 60 * 60 });
|
|
189
|
+
await this.delegationStorage.set(`delegation:session:${sessionId}`, { token, userDid, agentDid }, { expirationTtl: 60 * 60 });
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
5) Identity modes (optional, clear behavior)
|
|
193
|
+
- File: `packages/mcp-i-core/src/identity/user-did-manager.ts`
|
|
194
|
+
- Add `mode: 'ephemeral' | 'persistent' | 'hybrid'` and gate behavior accordingly.
|
|
195
|
+
|
|
196
|
+
6) Consent page: include `oauth_identity` / `user_did` when available
|
|
197
|
+
- File: `packages/mcp-i-cloudflare/src/services/consent-page-renderer.ts`
|
|
198
|
+
- In the submission JS, conditionally attach both fields if present in session.
|
|
199
|
+
|
|
200
|
+
7) Audit logs
|
|
201
|
+
- Log: consent shown, approval submitted, delegation created, verification success/failure, OAuth link events.
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
### Verification and Chains
|
|
205
|
+
|
|
206
|
+
— Requirements
|
|
207
|
+
- Validate VC structure against MCP‑I §3.1 VC shape; verify signatures and trust roots.
|
|
208
|
+
- Verify delegation chains with parent VCs recursively; detect cycles; respect revocation.
|
|
209
|
+
- Use `resolve_delegation_chain(...)` first; only fallback to OAuth‑based verification if no valid VC chain exists.
|
|
210
|
+
|
|
211
|
+
— Behavior
|
|
212
|
+
- On any failure, return `{ code, message, details }` with appropriate HTTP code and parity wrapper.
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
### Privacy & Security
|
|
216
|
+
|
|
217
|
+
— Privacy service (optional but recommended)
|
|
218
|
+
- Handlers: export, delete (forget), opt‑out (switch user to ephemeral), review (list identities+delegations).
|
|
219
|
+
|
|
220
|
+
— Security hardening
|
|
221
|
+
- Rate limit identity linking and delegation issuance per subject and per session.
|
|
222
|
+
- Require email verification toggle for risky link operations.
|
|
223
|
+
- CSP, XSS hardening (already present in consent renderer), secure cookies, SameSite=strict.
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
### Migration & Compatibility
|
|
227
|
+
|
|
228
|
+
— Transitional plan for AgentShield parity
|
|
229
|
+
- Phase 4 immediately adds `issuerDid` into `metadata` when `issuer_did`/`subject_did` are not accepted yet.
|
|
230
|
+
- Coordinate dashboard/API update to accept spec names; once deployed, switch client to send first‑class fields and stop duplicating in `metadata`.
|
|
231
|
+
- Add `@validate-api-parity` to CI for any API file changes and ensure contracts in `@kya-os/contracts` are the single source of truth.
|
|
232
|
+
|
|
233
|
+
— Back‑compat
|
|
234
|
+
- New consent fields `oauth_identity`, `user_did` are optional.
|
|
235
|
+
- Handshake `clientInfo` optional.
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
### Observability & Tests
|
|
239
|
+
|
|
240
|
+
— Unit
|
|
241
|
+
- `UserDidManager` (all modes), OAuth→DID linking, storage keys, consent validation
|
|
242
|
+
|
|
243
|
+
— Integration
|
|
244
|
+
- OAuth login → consent → delegation; session continuity; multi‑tenant issuance
|
|
245
|
+
|
|
246
|
+
— E2E
|
|
247
|
+
- First‑time consent + later reuse; data deletion; chain validation happy/negative paths
|
|
248
|
+
|
|
249
|
+
— Metrics & logs
|
|
250
|
+
- Latency of DID ops (<100ms p95), issuance/verification rate, error codes distribution
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
### Implementation Checklist
|
|
254
|
+
|
|
255
|
+
Week 1
|
|
256
|
+
- Fix delegation creation with `issuerDid` + `subjectDid`
|
|
257
|
+
- Add `getUserDidForSession` and tests
|
|
258
|
+
- Extend consent schema with optional `oauth_identity`/`user_did`
|
|
259
|
+
|
|
260
|
+
Week 2
|
|
261
|
+
- OAuth callback linking to DID + tests
|
|
262
|
+
- Multi‑tenant storage keys + tests
|
|
263
|
+
- Optional: identity modes in `UserDidManager`
|
|
264
|
+
|
|
265
|
+
Week 3
|
|
266
|
+
- Privacy endpoints (export/delete/opt‑out/review) and tests
|
|
267
|
+
- Optional: handshake `clientInfo` + registry
|
|
268
|
+
- Parity validation command passes; docs updated
|
|
269
|
+
|
|
270
|
+
Success criteria
|
|
271
|
+
- User DID persists across sessions via OAuth
|
|
272
|
+
- Delegations include correct `issuerDid` (User) and `subjectDid` (Agent)
|
|
273
|
+
- No storage collisions across users for the same agent
|
|
274
|
+
- VC chain validated when present; OAuth fallback otherwise
|
|
275
|
+
- API parity checks clean; error formats consistent
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
### Risks & Mitigations
|
|
279
|
+
|
|
280
|
+
— Performance: cache user DID and session delegations; async persistence
|
|
281
|
+
— Parity drift: block merges on `@validate-api-parity`; contracts as single source of truth
|
|
282
|
+
— Security: link throttling, optional email verification, strict audit logs
|
|
283
|
+
— Privacy: delete/export/opt‑out endpoints; secure storage scopes
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
### Notes on Current Code Reality (validated)
|
|
287
|
+
- `consent.service.ts` currently posts `{ agent_did, scopes, expires_in_days }` and lacks `issuerDid` → must be fixed (Priority 1).
|
|
288
|
+
- `oauth-handler.ts` performs token exchange but does not yet link to User DID → add linking.
|
|
289
|
+
- `user-did-manager.ts` supports ephemeral DIDs; extend with modes if needed.
|
|
290
|
+
- `consentApprovalRequestSchema` lacks `oauth_identity`/`user_did` → add optional fields to support persistence (back‑compatible).
|
|
291
|
+
- `HandshakeRequestSchema` does not include `clientInfo` → optional addition for future reputation mapping.
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
### Deliverables
|
|
295
|
+
- Updated contracts: consent schema (optional fields), optional handshake `clientInfo`
|
|
296
|
+
- Updated services: consent service, OAuth handler, consent renderer JS
|
|
297
|
+
- Updated storage keys: user+agent, session fast path
|
|
298
|
+
- Optional identity modes + privacy service
|
|
299
|
+
- Docs and parity validation green
|
|
300
|
+
|
|
301
|
+
# Phase 4: User DID & Identity Linking Implementation Plan
|
|
302
|
+
|
|
303
|
+
**Document Version:** 1.1
|
|
304
|
+
**Created:** November 2024
|
|
305
|
+
**Updated:** January 2025
|
|
306
|
+
**Status:** Ready for Implementation
|
|
307
|
+
**Priority:** CRITICAL - Addresses fundamental identity architecture gaps
|
|
308
|
+
**Branch:** feat/delegation-handling
|
|
309
|
+
|
|
310
|
+
## Executive Summary
|
|
311
|
+
|
|
312
|
+
This document outlines the implementation plan for adding User DID persistence and OAuth identity linking to the MCP-I framework. The plan addresses critical issues identified during review including API schema mismatches, disconnected OAuth/consent flows, and missing User DID integration. Since we haven't launched yet, this plan assumes no existing users and implements the correct architecture from the start.
|
|
313
|
+
|
|
314
|
+
## Prerequisites Complete ✅
|
|
315
|
+
|
|
316
|
+
The following foundational work has been completed in the current branch (feat/delegation-handling):
|
|
317
|
+
|
|
318
|
+
### 1. Scaffolder Refactor (V3 Architecture) - COMPLETE
|
|
319
|
+
- **MCPICloudflareServer class created**: All services now hidden in the package
|
|
320
|
+
- **Clean scaffolded output**: Users only see ~100 lines of configuration
|
|
321
|
+
- **Services moved to package**: DelegationService, ProofService, AdminService, ConsentService
|
|
322
|
+
- **Constants extracted**: No more hardcoded URLs in templates
|
|
323
|
+
|
|
324
|
+
### 2. Consent Service Implementation - COMPLETE
|
|
325
|
+
- **ConsentService class created**: Full consent flow implementation
|
|
326
|
+
- **Transport detection**: Automatic HTTP/SSE/STDIO detection
|
|
327
|
+
- **Consent rendering**: Complete with XSS protection
|
|
328
|
+
- **Integration ready**: Hooks in place for OAuth and User DID
|
|
329
|
+
|
|
330
|
+
### 3. Proof Submission Fix - COMPLETE
|
|
331
|
+
- **Automatic submission**: Proofs now submitted after tool execution
|
|
332
|
+
- **ProofService integrated**: Proper initialization in runtime
|
|
333
|
+
- **AgentShield integration**: Proofs visible in dashboard
|
|
334
|
+
|
|
335
|
+
### What This Means for Phase 4
|
|
336
|
+
With the scaffolder refactor and consent service complete, we have:
|
|
337
|
+
- ✅ Clean architecture to build upon
|
|
338
|
+
- ✅ ConsentService ready for OAuth integration (Part B)
|
|
339
|
+
- ✅ MCPICloudflareServer ready for User DID fixes (Part A)
|
|
340
|
+
- ✅ Infrastructure in place for storage improvements (Part C)
|
|
341
|
+
|
|
342
|
+
**Time Saved:** ~5 days of implementation already complete
|
|
343
|
+
**Adjusted Timeline:** 3-4 days remaining for Phase 4 implementation
|
|
344
|
+
|
|
345
|
+
## Critical Issues Identified During Review
|
|
346
|
+
|
|
347
|
+
### 1. API Schema Mismatch (CRITICAL)
|
|
348
|
+
- **Current State**: Consent service sends simplified request (agent_did, scopes, expires_in_days)
|
|
349
|
+
- **Expected**: AgentShield API expects full DelegationRecord with issuerDid and subjectDid
|
|
350
|
+
- **Impact**: Current implementation likely fails or creates invalid delegations
|
|
351
|
+
- **Evidence**: `consent.service.ts:358-366` vs `schemas.ts:153-155`
|
|
352
|
+
|
|
353
|
+
### 2. OAuth Identity Not Captured
|
|
354
|
+
- **Current State**: Consent flow doesn't extract OAuth identity from approval requests
|
|
355
|
+
- **Problem**: OAuth handler exists (`oauth-handler.ts`) but isn't integrated with consent flow
|
|
356
|
+
- **Impact**: Can't link OAuth identity to User DIDs for persistence
|
|
357
|
+
|
|
358
|
+
### 3. User DID Not Used as IssuerDid
|
|
359
|
+
- **Current State**: UserDidManager generates DIDs but they're not passed to delegation creation
|
|
360
|
+
- **Evidence**: TODO at `consent.service.ts:486-501` confirms this is known issue
|
|
361
|
+
- **Impact**: All delegations missing proper issuerDid (User DID)
|
|
362
|
+
|
|
363
|
+
### 4. MCP Client Info Not Available
|
|
364
|
+
- **Current State**: Handshake schema doesn't include clientInfo.name
|
|
365
|
+
- **Evidence**: `handshake.ts:7-12` only has optional agentDid
|
|
366
|
+
- **Impact**: Can't map MCP clients to reputation DIDs as planned
|
|
367
|
+
|
|
368
|
+
### 5. No Migration Strategy
|
|
369
|
+
- **Problem**: Existing delegations use ephemeral DIDs that become invalid
|
|
370
|
+
- **Impact**: Breaking change without backward compatibility
|
|
371
|
+
|
|
372
|
+
### 6. Multi-Tenant Conflicts
|
|
373
|
+
- **Current State**: Multiple users delegating to same agent overwrite each other
|
|
374
|
+
- **Evidence**: Known issue documented at `consent.service.ts:486-506`
|
|
375
|
+
|
|
376
|
+
## Revised Implementation Plan
|
|
377
|
+
|
|
378
|
+
### Part A: Fix Core Delegation Flow (Priority 1 - 2 days)
|
|
379
|
+
|
|
380
|
+
#### A.1: Update Delegation Creation to Include User DID
|
|
381
|
+
|
|
382
|
+
**Location**: `packages/mcp-i-cloudflare/src/services/consent.service.ts`
|
|
383
|
+
|
|
384
|
+
**Current Code** (lines 358-366):
|
|
385
|
+
```typescript
|
|
386
|
+
const delegationRequest = {
|
|
387
|
+
agent_did: request.agent_did,
|
|
388
|
+
scopes: request.scopes,
|
|
389
|
+
expires_in_days: expiresInDays,
|
|
390
|
+
...(request.customFields && Object.keys(request.customFields).length > 0
|
|
391
|
+
? { metadata: request.customFields }
|
|
392
|
+
: {}),
|
|
393
|
+
};
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
**Updated Code**:
|
|
397
|
+
```typescript
|
|
398
|
+
// Extract or generate User DID
|
|
399
|
+
const userDid = await this.getUserDidForSession(request.session_id);
|
|
400
|
+
|
|
401
|
+
const delegationRequest = {
|
|
402
|
+
// Core delegation fields
|
|
403
|
+
issuer_did: userDid, // NEW: User DID (who grants permission)
|
|
404
|
+
subject_did: request.agent_did, // RENAMED: Agent DID (who receives permission)
|
|
405
|
+
scopes: request.scopes,
|
|
406
|
+
expires_in_days: expiresInDays,
|
|
407
|
+
|
|
408
|
+
// Optional OAuth linking (for future persistence)
|
|
409
|
+
oauth_identity: request.oauth_identity ? {
|
|
410
|
+
provider: request.oauth_identity.provider,
|
|
411
|
+
subject: request.oauth_identity.subject,
|
|
412
|
+
email: request.oauth_identity.email
|
|
413
|
+
} : undefined
|
|
414
|
+
|
|
415
|
+
// Custom metadata
|
|
416
|
+
...(request.customFields && Object.keys(request.customFields).length > 0
|
|
417
|
+
? { metadata: request.customFields }
|
|
418
|
+
: {}),
|
|
419
|
+
};
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
**Expected Outcome**:
|
|
423
|
+
- Delegations include proper issuerDid (User DID)
|
|
424
|
+
- OAuth identity captured for future linking
|
|
425
|
+
- API properly structured from the start
|
|
426
|
+
|
|
427
|
+
**Test Coverage**:
|
|
428
|
+
```typescript
|
|
429
|
+
describe('Delegation Creation', () => {
|
|
430
|
+
it('should include issuerDid when creating delegation', async () => {
|
|
431
|
+
const result = await consentService.createDelegation(request);
|
|
432
|
+
expect(result.delegation.issuerDid).toBeDefined();
|
|
433
|
+
expect(result.delegation.issuerDid).toMatch(/^did:key:z6Mk/);
|
|
434
|
+
});
|
|
435
|
+
|
|
436
|
+
it('should capture OAuth identity when provided', async () => {
|
|
437
|
+
const request = { ...baseRequest, oauth_identity: { provider: 'google', subject: '123' }};
|
|
438
|
+
const result = await consentService.createDelegation(request);
|
|
439
|
+
expect(result.delegation.oauth_identity).toBeDefined();
|
|
440
|
+
});
|
|
441
|
+
});
|
|
442
|
+
```
|
|
443
|
+
|
|
444
|
+
#### A.2: Add getUserDidForSession Method
|
|
445
|
+
|
|
446
|
+
**Location**: `packages/mcp-i-cloudflare/src/services/consent.service.ts`
|
|
447
|
+
|
|
448
|
+
**New Method**:
|
|
449
|
+
```typescript
|
|
450
|
+
private async getUserDidForSession(sessionId: string): Promise<string> {
|
|
451
|
+
// Try to get existing User DID from session
|
|
452
|
+
const session = await this.sessionStorage.get(sessionId);
|
|
453
|
+
if (session?.userDid) {
|
|
454
|
+
return session.userDid;
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
// Generate new User DID using UserDidManager
|
|
458
|
+
const userDidManager = new UserDidManager({
|
|
459
|
+
crypto: this.cryptoProvider,
|
|
460
|
+
storage: this.userDidStorage // KV-based storage
|
|
461
|
+
});
|
|
462
|
+
|
|
463
|
+
const userDid = await userDidManager.getOrCreateUserDid(sessionId);
|
|
464
|
+
|
|
465
|
+
// Store in session for future use
|
|
466
|
+
await this.sessionStorage.set(sessionId, {
|
|
467
|
+
...session,
|
|
468
|
+
userDid
|
|
469
|
+
});
|
|
470
|
+
|
|
471
|
+
return userDid;
|
|
472
|
+
}
|
|
473
|
+
```
|
|
474
|
+
|
|
475
|
+
**Expected Outcome**:
|
|
476
|
+
- Consistent User DID per session
|
|
477
|
+
- Automatic generation if not exists
|
|
478
|
+
- Session-scoped persistence
|
|
479
|
+
|
|
480
|
+
**Test Coverage**:
|
|
481
|
+
```typescript
|
|
482
|
+
describe('getUserDidForSession', () => {
|
|
483
|
+
it('should return existing User DID from session', async () => {
|
|
484
|
+
const sessionId = 'test-session';
|
|
485
|
+
const expectedDid = 'did:key:z6MkExisting';
|
|
486
|
+
await sessionStorage.set(sessionId, { userDid: expectedDid });
|
|
487
|
+
|
|
488
|
+
const result = await consentService.getUserDidForSession(sessionId);
|
|
489
|
+
expect(result).toBe(expectedDid);
|
|
490
|
+
});
|
|
491
|
+
|
|
492
|
+
it('should generate new User DID if not in session', async () => {
|
|
493
|
+
const sessionId = 'new-session';
|
|
494
|
+
const result = await consentService.getUserDidForSession(sessionId);
|
|
495
|
+
expect(result).toMatch(/^did:key:z6Mk/);
|
|
496
|
+
});
|
|
497
|
+
});
|
|
498
|
+
```
|
|
499
|
+
|
|
500
|
+
### Part B: Integrate OAuth with Consent Flow (Priority 2 - 2 days)
|
|
501
|
+
|
|
502
|
+
#### B.1: Update ConsentApprovalRequest Schema
|
|
503
|
+
|
|
504
|
+
**Location**: `packages/contracts/src/consent/schemas.ts`
|
|
505
|
+
|
|
506
|
+
**Add OAuth Identity Fields**:
|
|
507
|
+
```typescript
|
|
508
|
+
export const consentApprovalRequestSchema = z.object({
|
|
509
|
+
// Existing fields
|
|
510
|
+
agent_did: z.string(),
|
|
511
|
+
session_id: z.string(),
|
|
512
|
+
scopes: z.array(z.string()),
|
|
513
|
+
project_id: z.string(),
|
|
514
|
+
|
|
515
|
+
// NEW: OAuth identity fields
|
|
516
|
+
oauth_identity: z.object({
|
|
517
|
+
provider: z.enum(['google', 'github', 'microsoft', 'custom']),
|
|
518
|
+
subject: z.string(), // OAuth user ID
|
|
519
|
+
email: z.string().email().optional(),
|
|
520
|
+
name: z.string().optional(),
|
|
521
|
+
}).optional(),
|
|
522
|
+
|
|
523
|
+
// NEW: Persistent User DID
|
|
524
|
+
user_did: z.string().optional(),
|
|
525
|
+
|
|
526
|
+
// Existing optional fields
|
|
527
|
+
termsAccepted: z.boolean().optional(),
|
|
528
|
+
customFields: z.record(z.unknown()).optional(),
|
|
529
|
+
});
|
|
530
|
+
```
|
|
531
|
+
|
|
532
|
+
**Expected Outcome**:
|
|
533
|
+
- Consent approval can include OAuth identity
|
|
534
|
+
- Clean API design from the start
|
|
535
|
+
- Supports persistent User DIDs
|
|
536
|
+
|
|
537
|
+
#### B.2: Extract OAuth Identity in Consent Page
|
|
538
|
+
|
|
539
|
+
**Location**: `packages/mcp-i-cloudflare/src/services/consent-page-renderer.ts`
|
|
540
|
+
|
|
541
|
+
**Update Consent Page JavaScript**:
|
|
542
|
+
```javascript
|
|
543
|
+
// In consent page template
|
|
544
|
+
async function approveConsent() {
|
|
545
|
+
// Extract OAuth identity from session/cookie if available
|
|
546
|
+
const oauthIdentity = await getOAuthIdentityFromSession();
|
|
547
|
+
|
|
548
|
+
const approvalRequest = {
|
|
549
|
+
agent_did: '${config.agentDid}',
|
|
550
|
+
session_id: '${config.sessionId}',
|
|
551
|
+
scopes: ${JSON.stringify(config.scopes)},
|
|
552
|
+
project_id: '${config.projectId}',
|
|
553
|
+
|
|
554
|
+
// Include OAuth identity if available
|
|
555
|
+
...(oauthIdentity && { oauth_identity: oauthIdentity }),
|
|
556
|
+
|
|
557
|
+
// Include User DID if already persistent
|
|
558
|
+
...(window.userDid && { user_did: window.userDid }),
|
|
559
|
+
|
|
560
|
+
termsAccepted: document.getElementById('terms-checkbox')?.checked,
|
|
561
|
+
};
|
|
562
|
+
|
|
563
|
+
const response = await fetch('/consent/approve', {
|
|
564
|
+
method: 'POST',
|
|
565
|
+
headers: { 'Content-Type': 'application/json' },
|
|
566
|
+
body: JSON.stringify(approvalRequest)
|
|
567
|
+
});
|
|
568
|
+
}
|
|
569
|
+
```
|
|
570
|
+
|
|
571
|
+
**Expected Outcome**:
|
|
572
|
+
- OAuth identity passed to approval endpoint
|
|
573
|
+
- User DID included when available
|
|
574
|
+
- Progressive enhancement approach
|
|
575
|
+
|
|
576
|
+
#### B.3: Connect OAuth Handler to User DID Creation
|
|
577
|
+
|
|
578
|
+
**Location**: `packages/mcp-i-cloudflare/src/runtime/oauth-handler.ts`
|
|
579
|
+
|
|
580
|
+
**Add Identity Linking**:
|
|
581
|
+
```typescript
|
|
582
|
+
export class OAuthHandler {
|
|
583
|
+
async handleCallback(request: Request): Promise<Response> {
|
|
584
|
+
// Existing OAuth token validation
|
|
585
|
+
const { provider, userInfo } = await this.validateOAuthCallback(request);
|
|
586
|
+
|
|
587
|
+
// NEW: Create or retrieve User DID for OAuth identity
|
|
588
|
+
const userDid = await this.linkOAuthToUserDid(provider, userInfo.sub);
|
|
589
|
+
|
|
590
|
+
// Store OAuth<->DID mapping
|
|
591
|
+
await this.identityStorage.set(
|
|
592
|
+
`oauth:${provider}:${userInfo.sub}`,
|
|
593
|
+
{
|
|
594
|
+
userDid,
|
|
595
|
+
email: userInfo.email,
|
|
596
|
+
name: userInfo.name,
|
|
597
|
+
linkedAt: new Date().toISOString(),
|
|
598
|
+
lastUsed: new Date().toISOString()
|
|
599
|
+
},
|
|
600
|
+
{ expirationTtl: 30 * 24 * 60 * 60 } // 30 days
|
|
601
|
+
);
|
|
602
|
+
|
|
603
|
+
// Set session cookie with User DID
|
|
604
|
+
return new Response(null, {
|
|
605
|
+
status: 302,
|
|
606
|
+
headers: {
|
|
607
|
+
'Location': '/consent',
|
|
608
|
+
'Set-Cookie': `user_did=${userDid}; HttpOnly; Secure; SameSite=Strict`
|
|
609
|
+
}
|
|
610
|
+
});
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
private async linkOAuthToUserDid(provider: string, subject: string): Promise<string> {
|
|
614
|
+
const linkKey = `oauth:${provider}:${subject}`;
|
|
615
|
+
|
|
616
|
+
// Check for existing link
|
|
617
|
+
const existing = await this.identityStorage.get(linkKey);
|
|
618
|
+
if (existing?.userDid) {
|
|
619
|
+
// Update last used timestamp
|
|
620
|
+
await this.identityStorage.set(linkKey, {
|
|
621
|
+
...existing,
|
|
622
|
+
lastUsed: new Date().toISOString()
|
|
623
|
+
});
|
|
624
|
+
return existing.userDid;
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
// Generate new persistent User DID
|
|
628
|
+
const userDidManager = new UserDidManager({
|
|
629
|
+
crypto: this.cryptoProvider,
|
|
630
|
+
storage: this.identityStorage
|
|
631
|
+
});
|
|
632
|
+
|
|
633
|
+
const userDid = await userDidManager.generateUserDid();
|
|
634
|
+
return userDid;
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
```
|
|
638
|
+
|
|
639
|
+
**Expected Outcome**:
|
|
640
|
+
- OAuth identities automatically linked to User DIDs
|
|
641
|
+
- Persistent mapping stored in KV
|
|
642
|
+
- Same User DID returned for same OAuth identity
|
|
643
|
+
|
|
644
|
+
**Test Coverage**:
|
|
645
|
+
```typescript
|
|
646
|
+
describe('OAuth to User DID Linking', () => {
|
|
647
|
+
it('should create new User DID for new OAuth identity', async () => {
|
|
648
|
+
const result = await oauthHandler.linkOAuthToUserDid('google', 'user123');
|
|
649
|
+
expect(result).toMatch(/^did:key:z6Mk/);
|
|
650
|
+
});
|
|
651
|
+
|
|
652
|
+
it('should return existing User DID for known OAuth identity', async () => {
|
|
653
|
+
const firstDid = await oauthHandler.linkOAuthToUserDid('google', 'user123');
|
|
654
|
+
const secondDid = await oauthHandler.linkOAuthToUserDid('google', 'user123');
|
|
655
|
+
expect(secondDid).toBe(firstDid);
|
|
656
|
+
});
|
|
657
|
+
|
|
658
|
+
it('should update lastUsed timestamp on retrieval', async () => {
|
|
659
|
+
await oauthHandler.linkOAuthToUserDid('google', 'user123');
|
|
660
|
+
const link = await identityStorage.get('oauth:google:user123');
|
|
661
|
+
const firstTime = link.lastUsed;
|
|
662
|
+
|
|
663
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
664
|
+
await oauthHandler.linkOAuthToUserDid('google', 'user123');
|
|
665
|
+
const updatedLink = await identityStorage.get('oauth:google:user123');
|
|
666
|
+
expect(updatedLink.lastUsed).not.toBe(firstTime);
|
|
667
|
+
});
|
|
668
|
+
});
|
|
669
|
+
```
|
|
670
|
+
|
|
671
|
+
### Part C: Fix Multi-Tenant Storage Conflicts (Priority 3 - 1 day)
|
|
672
|
+
|
|
673
|
+
#### C.1: Update Delegation Token Storage Keys
|
|
674
|
+
|
|
675
|
+
**Location**: `packages/mcp-i-cloudflare/src/services/consent.service.ts`
|
|
676
|
+
|
|
677
|
+
**Current Problem** (lines 486-501):
|
|
678
|
+
- Tokens stored with agent-scoped keys only
|
|
679
|
+
- Multiple users → same agent = overwrite
|
|
680
|
+
|
|
681
|
+
**Fix Storage Keys**:
|
|
682
|
+
```typescript
|
|
683
|
+
private async storeDelegationToken(
|
|
684
|
+
token: string,
|
|
685
|
+
userDid: string,
|
|
686
|
+
agentDid: string,
|
|
687
|
+
sessionId: string
|
|
688
|
+
): Promise<void> {
|
|
689
|
+
// Primary key: User + Agent (prevents conflicts)
|
|
690
|
+
const userAgentKey = `delegation:user:${userDid}:agent:${agentDid}`;
|
|
691
|
+
await this.delegationStorage.set(userAgentKey, token, {
|
|
692
|
+
expirationTtl: 24 * 60 * 60 // 24 hours
|
|
693
|
+
});
|
|
694
|
+
|
|
695
|
+
// Session key for fast lookup
|
|
696
|
+
const sessionKey = `delegation:session:${sessionId}`;
|
|
697
|
+
await this.delegationStorage.set(sessionKey, {
|
|
698
|
+
token,
|
|
699
|
+
userDid,
|
|
700
|
+
agentDid
|
|
701
|
+
}, {
|
|
702
|
+
expirationTtl: 60 * 60 // 1 hour
|
|
703
|
+
});
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
private async retrieveDelegationToken(
|
|
707
|
+
sessionId: string,
|
|
708
|
+
agentDid: string
|
|
709
|
+
): Promise<string | null> {
|
|
710
|
+
// Try session key first (fastest)
|
|
711
|
+
const sessionData = await this.delegationStorage.get(`delegation:session:${sessionId}`);
|
|
712
|
+
if (sessionData?.token) {
|
|
713
|
+
return sessionData.token;
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
// Try user+agent key
|
|
717
|
+
const userDid = await this.getUserDidForSession(sessionId);
|
|
718
|
+
if (userDid) {
|
|
719
|
+
const token = await this.delegationStorage.get(`delegation:user:${userDid}:agent:${agentDid}`);
|
|
720
|
+
if (token) {
|
|
721
|
+
return token;
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
return null;
|
|
726
|
+
}
|
|
727
|
+
```
|
|
728
|
+
|
|
729
|
+
**Expected Outcome**:
|
|
730
|
+
- No more multi-tenant conflicts
|
|
731
|
+
- Fast session-based lookup
|
|
732
|
+
- Clean storage architecture
|
|
733
|
+
|
|
734
|
+
**Test Coverage**:
|
|
735
|
+
```typescript
|
|
736
|
+
describe('Multi-tenant Delegation Storage', () => {
|
|
737
|
+
it('should store delegations per user+agent combination', async () => {
|
|
738
|
+
const user1Did = 'did:key:z6MkUser1';
|
|
739
|
+
const user2Did = 'did:key:z6MkUser2';
|
|
740
|
+
const agentDid = 'did:key:z6MkAgent';
|
|
741
|
+
|
|
742
|
+
await consentService.storeDelegationToken('token1', user1Did, agentDid, 'session1');
|
|
743
|
+
await consentService.storeDelegationToken('token2', user2Did, agentDid, 'session2');
|
|
744
|
+
|
|
745
|
+
const token1 = await delegationStorage.get(`delegation:user:${user1Did}:agent:${agentDid}`);
|
|
746
|
+
const token2 = await delegationStorage.get(`delegation:user:${user2Did}:agent:${agentDid}`);
|
|
747
|
+
|
|
748
|
+
expect(token1).toBe('token1');
|
|
749
|
+
expect(token2).toBe('token2');
|
|
750
|
+
});
|
|
751
|
+
});
|
|
752
|
+
```
|
|
753
|
+
|
|
754
|
+
### Part D: Identity Mode Configuration (Priority 4 - 1 day)
|
|
755
|
+
|
|
756
|
+
#### D.1: Support Different Identity Modes
|
|
757
|
+
|
|
758
|
+
**Location**: `packages/mcp-i-core/src/identity/user-did-manager.ts`
|
|
759
|
+
|
|
760
|
+
**Add Configuration for Identity Modes**:
|
|
761
|
+
```typescript
|
|
762
|
+
export interface UserDidManagerConfig {
|
|
763
|
+
// Existing fields...
|
|
764
|
+
|
|
765
|
+
/**
|
|
766
|
+
* Identity mode
|
|
767
|
+
* - 'ephemeral': Generate new DID per session (for development/testing)
|
|
768
|
+
* - 'persistent': Link to OAuth, reuse across sessions (for production)
|
|
769
|
+
* - 'hybrid': Ephemeral by default, persistent after OAuth login (flexible)
|
|
770
|
+
*/
|
|
771
|
+
mode: 'ephemeral' | 'persistent' | 'hybrid';
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
export class UserDidManager {
|
|
775
|
+
async getOrCreateUserDid(sessionId: string, oauthIdentity?: OAuthIdentity): Promise<string> {
|
|
776
|
+
// Mode-based behavior
|
|
777
|
+
switch (this.config.mode) {
|
|
778
|
+
case 'ephemeral':
|
|
779
|
+
// Testing mode - always generate new
|
|
780
|
+
return this.generateEphemeralDid(sessionId);
|
|
781
|
+
|
|
782
|
+
case 'persistent':
|
|
783
|
+
// Production mode - require OAuth identity
|
|
784
|
+
if (!oauthIdentity) {
|
|
785
|
+
throw new Error('OAuth identity required in persistent mode');
|
|
786
|
+
}
|
|
787
|
+
return this.getOrCreatePersistentDid(oauthIdentity);
|
|
788
|
+
|
|
789
|
+
case 'hybrid':
|
|
790
|
+
// Flexible mode - use OAuth if available
|
|
791
|
+
if (oauthIdentity) {
|
|
792
|
+
return this.getOrCreatePersistentDid(oauthIdentity);
|
|
793
|
+
} else {
|
|
794
|
+
return this.generateEphemeralDid(sessionId);
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
```
|
|
800
|
+
|
|
801
|
+
**Expected Outcome**:
|
|
802
|
+
- Support for different deployment scenarios
|
|
803
|
+
- Clear separation between dev/test/production modes
|
|
804
|
+
- Flexible configuration based on needs
|
|
805
|
+
|
|
806
|
+
### Part E: Security & Privacy Enhancements (Priority 5 - 2 days)
|
|
807
|
+
|
|
808
|
+
#### E.1: OAuth Account Verification
|
|
809
|
+
|
|
810
|
+
**Location**: `packages/mcp-i-cloudflare/src/runtime/oauth-handler.ts`
|
|
811
|
+
|
|
812
|
+
**Add Verification Step**:
|
|
813
|
+
```typescript
|
|
814
|
+
private async verifyOAuthAccountOwnership(
|
|
815
|
+
provider: string,
|
|
816
|
+
subject: string,
|
|
817
|
+
email?: string
|
|
818
|
+
): Promise<boolean> {
|
|
819
|
+
// For account linking, require email verification
|
|
820
|
+
if (email && this.config.requireEmailVerification) {
|
|
821
|
+
const verificationToken = await this.generateVerificationToken();
|
|
822
|
+
await this.sendVerificationEmail(email, verificationToken);
|
|
823
|
+
|
|
824
|
+
// Store pending verification
|
|
825
|
+
await this.pendingVerifications.set(
|
|
826
|
+
`verify:${provider}:${subject}`,
|
|
827
|
+
{ token: verificationToken, email },
|
|
828
|
+
{ expirationTtl: 15 * 60 } // 15 minutes
|
|
829
|
+
);
|
|
830
|
+
|
|
831
|
+
return false; // Requires verification completion
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
// Check for suspicious patterns
|
|
835
|
+
const recentLinks = await this.getRecentLinks(subject);
|
|
836
|
+
if (recentLinks.length > this.config.maxLinksPerHour) {
|
|
837
|
+
console.warn('Suspicious linking activity detected:', subject);
|
|
838
|
+
return false;
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
return true;
|
|
842
|
+
}
|
|
843
|
+
```
|
|
844
|
+
|
|
845
|
+
**Expected Outcome**:
|
|
846
|
+
- Prevents unauthorized account linking
|
|
847
|
+
- Email verification for sensitive operations
|
|
848
|
+
- Rate limiting on identity linking
|
|
849
|
+
|
|
850
|
+
#### E.2: Privacy Controls
|
|
851
|
+
|
|
852
|
+
**Location**: `packages/mcp-i-cloudflare/src/services/privacy.service.ts`
|
|
853
|
+
|
|
854
|
+
**New Privacy Service**:
|
|
855
|
+
```typescript
|
|
856
|
+
export class PrivacyService {
|
|
857
|
+
async handlePrivacyRequest(request: PrivacyRequest): Promise<PrivacyResponse> {
|
|
858
|
+
switch (request.type) {
|
|
859
|
+
case 'export':
|
|
860
|
+
// GDPR: Right to data portability
|
|
861
|
+
return this.exportUserData(request.userDid);
|
|
862
|
+
|
|
863
|
+
case 'delete':
|
|
864
|
+
// GDPR: Right to be forgotten
|
|
865
|
+
return this.deleteUserData(request.userDid);
|
|
866
|
+
|
|
867
|
+
case 'opt-out':
|
|
868
|
+
// Switch to ephemeral mode for user
|
|
869
|
+
return this.setUserMode(request.userDid, 'ephemeral');
|
|
870
|
+
|
|
871
|
+
case 'review':
|
|
872
|
+
// Show all linked identities and delegations
|
|
873
|
+
return this.getUserDataSummary(request.userDid);
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
private async deleteUserData(userDid: string): Promise<PrivacyResponse> {
|
|
878
|
+
// Delete OAuth links
|
|
879
|
+
const links = await this.identityStorage.list({ prefix: `oauth:*:*` });
|
|
880
|
+
for (const link of links) {
|
|
881
|
+
if (link.value.userDid === userDid) {
|
|
882
|
+
await this.identityStorage.delete(link.key);
|
|
883
|
+
}
|
|
884
|
+
}
|
|
885
|
+
|
|
886
|
+
// Delete delegations
|
|
887
|
+
await this.delegationStorage.delete(`delegation:user:${userDid}:*`);
|
|
888
|
+
|
|
889
|
+
// Delete User DID
|
|
890
|
+
await this.userDidStorage.delete(userDid);
|
|
891
|
+
|
|
892
|
+
return { success: true, message: 'All user data deleted' };
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
```
|
|
896
|
+
|
|
897
|
+
**Expected Outcome**:
|
|
898
|
+
- GDPR compliance
|
|
899
|
+
- User control over data
|
|
900
|
+
- Privacy-first design
|
|
901
|
+
|
|
902
|
+
**Test Coverage**:
|
|
903
|
+
```typescript
|
|
904
|
+
describe('Privacy Controls', () => {
|
|
905
|
+
it('should delete all user data on request', async () => {
|
|
906
|
+
const userDid = 'did:key:z6MkUser';
|
|
907
|
+
await privacyService.deleteUserData(userDid);
|
|
908
|
+
|
|
909
|
+
const links = await identityStorage.list({ prefix: `oauth:` });
|
|
910
|
+
const userLinks = links.filter(l => l.value.userDid === userDid);
|
|
911
|
+
expect(userLinks).toHaveLength(0);
|
|
912
|
+
});
|
|
913
|
+
|
|
914
|
+
it('should export user data in portable format', async () => {
|
|
915
|
+
const result = await privacyService.exportUserData(userDid);
|
|
916
|
+
expect(result.data).toHaveProperty('identities');
|
|
917
|
+
expect(result.data).toHaveProperty('delegations');
|
|
918
|
+
expect(result.format).toBe('json');
|
|
919
|
+
});
|
|
920
|
+
});
|
|
921
|
+
```
|
|
922
|
+
|
|
923
|
+
### Part F: MCP Client Mapping (Optional - 1 day)
|
|
924
|
+
|
|
925
|
+
Since MCP handshake doesn't include clientInfo.name, we'll make this optional:
|
|
926
|
+
|
|
927
|
+
#### F.1: Extend Handshake Schema (If Possible)
|
|
928
|
+
|
|
929
|
+
**Location**: `packages/contracts/src/handshake.ts`
|
|
930
|
+
|
|
931
|
+
```typescript
|
|
932
|
+
export const HandshakeRequestSchema = z.object({
|
|
933
|
+
agentDid: z.string().optional(),
|
|
934
|
+
|
|
935
|
+
// NEW: Optional client information
|
|
936
|
+
clientInfo: z.object({
|
|
937
|
+
name: z.string(), // "Claude Desktop", "OpenAI GPT", etc.
|
|
938
|
+
version: z.string(), // "1.0.0"
|
|
939
|
+
platform: z.string(), // "desktop", "web", "mobile"
|
|
940
|
+
}).optional(),
|
|
941
|
+
});
|
|
942
|
+
```
|
|
943
|
+
|
|
944
|
+
#### F.2: Registry-Based Mapping
|
|
945
|
+
|
|
946
|
+
**Location**: `packages/mcp-i-core/src/client/registry.ts`
|
|
947
|
+
|
|
948
|
+
```typescript
|
|
949
|
+
export const MCP_CLIENT_REGISTRY = {
|
|
950
|
+
// Well-known clients with reputation DIDs
|
|
951
|
+
'Claude Desktop': {
|
|
952
|
+
did: 'did:web:knowthat.ai:clients:claude',
|
|
953
|
+
reputation: 'verified',
|
|
954
|
+
firstSeen: '2024-01-01',
|
|
955
|
+
},
|
|
956
|
+
'OpenAI GPT': {
|
|
957
|
+
did: 'did:web:knowthat.ai:clients:openai',
|
|
958
|
+
reputation: 'verified',
|
|
959
|
+
firstSeen: '2024-01-01',
|
|
960
|
+
},
|
|
961
|
+
// Add more as they're discovered
|
|
962
|
+
};
|
|
963
|
+
|
|
964
|
+
export function getClientDid(clientName?: string): string | undefined {
|
|
965
|
+
if (!clientName) return undefined;
|
|
966
|
+
return MCP_CLIENT_REGISTRY[clientName]?.did;
|
|
967
|
+
}
|
|
968
|
+
```
|
|
969
|
+
|
|
970
|
+
**Expected Outcome**:
|
|
971
|
+
- Optional enhancement
|
|
972
|
+
- Graceful degradation if not available
|
|
973
|
+
- Foundation for future reputation system
|
|
974
|
+
|
|
975
|
+
## Implementation Schedule
|
|
976
|
+
|
|
977
|
+
### Week 1: Core Fixes
|
|
978
|
+
- Day 1-2: Part A - Fix Core Delegation Flow
|
|
979
|
+
- [ ] Update delegation creation to include issuerDid
|
|
980
|
+
- [ ] Add getUserDidForSession method
|
|
981
|
+
- [ ] Write and run tests
|
|
982
|
+
|
|
983
|
+
- Day 3-4: Part B - OAuth Integration (partial)
|
|
984
|
+
- [ ] Update schemas
|
|
985
|
+
- [ ] Extract OAuth identity in consent page
|
|
986
|
+
- [ ] Begin OAuth handler updates
|
|
987
|
+
|
|
988
|
+
### Week 2: Integration & Migration
|
|
989
|
+
- Day 5: Part B - Complete OAuth Integration
|
|
990
|
+
- [ ] Finish OAuth to User DID linking
|
|
991
|
+
- [ ] Test OAuth flow end-to-end
|
|
992
|
+
|
|
993
|
+
- Day 6: Part C - Fix Storage Conflicts
|
|
994
|
+
- [ ] Update delegation storage keys
|
|
995
|
+
- [ ] Test multi-tenant scenarios
|
|
996
|
+
|
|
997
|
+
- Day 7-8: Part D - Identity Mode Configuration
|
|
998
|
+
- [ ] Implement mode selection (ephemeral/persistent/hybrid)
|
|
999
|
+
- [ ] Add mode-specific logic
|
|
1000
|
+
- [ ] Test different deployment scenarios
|
|
1001
|
+
|
|
1002
|
+
### Week 3: Security & Polish
|
|
1003
|
+
- Day 9-10: Part E - Security & Privacy
|
|
1004
|
+
- [ ] OAuth verification
|
|
1005
|
+
- [ ] Privacy controls
|
|
1006
|
+
- [ ] GDPR compliance testing
|
|
1007
|
+
|
|
1008
|
+
- Day 11: Part F - Optional MCP Client Mapping
|
|
1009
|
+
- [ ] Extend handshake if possible
|
|
1010
|
+
- [ ] Set up client registry
|
|
1011
|
+
|
|
1012
|
+
- Day 12: Integration Testing & Documentation
|
|
1013
|
+
- [ ] Full end-to-end testing
|
|
1014
|
+
- [ ] Update documentation
|
|
1015
|
+
- [ ] Performance testing
|
|
1016
|
+
|
|
1017
|
+
## Success Metrics
|
|
1018
|
+
|
|
1019
|
+
### Functional Requirements
|
|
1020
|
+
- [ ] User DIDs persist across sessions when using OAuth
|
|
1021
|
+
- [ ] Delegations include correct issuerDid (User) and subjectDid (Agent)
|
|
1022
|
+
- [ ] OAuth identity correctly linked to User DIDs
|
|
1023
|
+
- [ ] Multi-tenant conflicts resolved
|
|
1024
|
+
- [ ] Clean architecture from the start
|
|
1025
|
+
|
|
1026
|
+
### Non-Functional Requirements
|
|
1027
|
+
- [ ] <100ms overhead for DID operations
|
|
1028
|
+
- [ ] GDPR compliance for data operations
|
|
1029
|
+
- [ ] 95% test coverage for new code
|
|
1030
|
+
- [ ] Clear separation between dev/test/prod modes
|
|
1031
|
+
|
|
1032
|
+
### Security Requirements
|
|
1033
|
+
- [ ] OAuth account verification prevents unauthorized linking
|
|
1034
|
+
- [ ] Rate limiting on identity operations
|
|
1035
|
+
- [ ] Audit trail for all identity changes
|
|
1036
|
+
- [ ] Secure token storage with encryption
|
|
1037
|
+
|
|
1038
|
+
## Risk Mitigation
|
|
1039
|
+
|
|
1040
|
+
### Risk 1: Performance Impact
|
|
1041
|
+
- **Mitigation**: Caching, async operations
|
|
1042
|
+
- **Monitoring**: Track DID operation latency
|
|
1043
|
+
|
|
1044
|
+
### Risk 2: Privacy Concerns
|
|
1045
|
+
- **Mitigation**: Clear mode selection (ephemeral/persistent/hybrid), data deletion API
|
|
1046
|
+
- **Compliance**: GDPR audit before release
|
|
1047
|
+
|
|
1048
|
+
### Risk 3: OAuth Provider Issues
|
|
1049
|
+
- **Mitigation**: Support multiple providers, graceful fallback to ephemeral
|
|
1050
|
+
- **Monitoring**: Track OAuth success rates
|
|
1051
|
+
|
|
1052
|
+
## Testing Strategy
|
|
1053
|
+
|
|
1054
|
+
### Unit Tests
|
|
1055
|
+
- UserDidManager with all three modes
|
|
1056
|
+
- OAuth to DID linking logic
|
|
1057
|
+
- Multi-tenant storage operations
|
|
1058
|
+
- Privacy service operations
|
|
1059
|
+
|
|
1060
|
+
### Integration Tests
|
|
1061
|
+
- Full OAuth login → consent → delegation flow
|
|
1062
|
+
- Session continuity across multiple requests
|
|
1063
|
+
- Mode switching (ephemeral → persistent → hybrid)
|
|
1064
|
+
- Multi-user, multi-agent scenarios
|
|
1065
|
+
|
|
1066
|
+
### E2E Tests
|
|
1067
|
+
- User logs in with Google → approves delegation → uses tool
|
|
1068
|
+
- User returns next day → same DID → previous delegations work
|
|
1069
|
+
- User deletes account → all data removed
|
|
1070
|
+
|
|
1071
|
+
### Performance Tests
|
|
1072
|
+
- 1000 concurrent DID operations
|
|
1073
|
+
- OAuth linking under load
|
|
1074
|
+
- Storage operations with 10k+ entries
|
|
1075
|
+
|
|
1076
|
+
## Documentation Updates
|
|
1077
|
+
|
|
1078
|
+
### API Documentation
|
|
1079
|
+
- New fields in ConsentApprovalRequest
|
|
1080
|
+
- OAuth identity linking endpoints
|
|
1081
|
+
- Privacy control endpoints
|
|
1082
|
+
|
|
1083
|
+
### Configuration Guide
|
|
1084
|
+
- How to choose between identity modes
|
|
1085
|
+
- Setting up OAuth providers
|
|
1086
|
+
- Configuring for different environments
|
|
1087
|
+
|
|
1088
|
+
### User Guide
|
|
1089
|
+
- Benefits of persistent identity
|
|
1090
|
+
- Privacy controls and data deletion
|
|
1091
|
+
- OAuth account linking process
|
|
1092
|
+
|
|
1093
|
+
## Conclusion
|
|
1094
|
+
|
|
1095
|
+
This plan addresses all critical issues identified in the review and implements the correct architecture from the start. The implementation is broken into manageable phases with clear dependencies and success metrics.
|
|
1096
|
+
|
|
1097
|
+
The key improvements include:
|
|
1098
|
+
1. Proper User DID integration as issuerDid
|
|
1099
|
+
2. OAuth identity linking for persistence
|
|
1100
|
+
3. Multi-tenant conflict resolution
|
|
1101
|
+
4. Comprehensive security and privacy controls
|
|
1102
|
+
5. Clear mode selection for different deployment scenarios
|
|
1103
|
+
|
|
1104
|
+
By following this plan, we'll establish a robust identity foundation that enables true user persistence while maintaining the flexibility to support both ephemeral and persistent modes based on use case requirements.
|
|
1105
|
+
|
|
1106
|
+
## Comparison to Initial Analysis
|
|
1107
|
+
|
|
1108
|
+
### What Changed from Original Plan
|
|
1109
|
+
|
|
1110
|
+
The initial analysis suggested a simpler OAuth bridging approach. After review feedback, the plan now addresses:
|
|
1111
|
+
|
|
1112
|
+
1. **API Schema Alignment**: Fixed to send full DelegationRecord with issuerDid and subjectDid
|
|
1113
|
+
2. **OAuth Integration**: Properly integrated with consent flow (not separate)
|
|
1114
|
+
3. **User DID Usage**: Actually used as issuerDid (was missing before)
|
|
1115
|
+
4. **No Legacy Support**: Since we haven't launched, no need for backward compatibility
|
|
1116
|
+
|
|
1117
|
+
### What Remains from Original Plan
|
|
1118
|
+
|
|
1119
|
+
1. **Core Concept**: OAuth identity → User DID linking for persistence
|
|
1120
|
+
2. **Three-Layer DIDs**: Server/Bouncer, Agent, and User DIDs
|
|
1121
|
+
3. **MCP Client Mapping**: Optional enhancement for reputation tracking
|
|
1122
|
+
4. **Session Continuity**: Tracking users across chat sessions
|
|
1123
|
+
|
|
1124
|
+
## MCP-I Specification Alignment
|
|
1125
|
+
|
|
1126
|
+
### Full Compliance with MCP-I Spec
|
|
1127
|
+
|
|
1128
|
+
This implementation aligns with the [MCP-I specification](https://modelcontextprotocol-identity.io) and [schemas](https://schema.modelcontextprotocol-identity.io/):
|
|
1129
|
+
|
|
1130
|
+
1. **DID Architecture** ✅
|
|
1131
|
+
- Server DID: `did:web:` or `did:key:` format per spec
|
|
1132
|
+
- Agent DID: Properly used as subjectDid in delegations
|
|
1133
|
+
- User DID: Properly used as issuerDid in delegations
|
|
1134
|
+
|
|
1135
|
+
2. **Delegation Model** ✅
|
|
1136
|
+
- Format: User (issuerDid) → Agent (subjectDid)
|
|
1137
|
+
- Includes scopes, constraints, and expiration
|
|
1138
|
+
- Follows W3C Verifiable Credential wrapper format
|
|
1139
|
+
|
|
1140
|
+
3. **Proof Format** ✅
|
|
1141
|
+
- JWS compact format (header.payload.signature)
|
|
1142
|
+
- All required meta fields present
|
|
1143
|
+
- SHA-256 hashing with proper prefixes
|
|
1144
|
+
|
|
1145
|
+
4. **Consent Flow** ✅
|
|
1146
|
+
- Required parameters: tool, scopes, agent_did, session_id, project_id
|
|
1147
|
+
- Proper approval handling
|
|
1148
|
+
- Delegation creation upon approval
|
|
1149
|
+
|
|
1150
|
+
5. **Security Requirements** ✅
|
|
1151
|
+
- Ed25519 signatures
|
|
1152
|
+
- Proper nonce handling
|
|
1153
|
+
- Session-based security
|
|
1154
|
+
|
|
1155
|
+
### Key Alignment Points
|
|
1156
|
+
|
|
1157
|
+
- **issuerDid**: Always the User DID (who grants permission)
|
|
1158
|
+
- **subjectDid**: Always the Agent DID (who receives permission)
|
|
1159
|
+
- **Delegation Storage**: Properly scoped to prevent multi-tenant conflicts
|
|
1160
|
+
- **OAuth Integration**: Enhances but doesn't replace DID-based identity
|
|
1161
|
+
|
|
1162
|
+
### Level 3 Enterprise Features
|
|
1163
|
+
|
|
1164
|
+
While this plan doesn't implement full Level 3 compliance (OAuth 2.1 bridging, anomaly detection), it provides:
|
|
1165
|
+
- Foundation for OAuth identity management
|
|
1166
|
+
- Clear path to Level 3 if needed
|
|
1167
|
+
- Level 1-2 compliance out of the box
|
|
1168
|
+
|
|
1169
|
+
The implementation maintains full spec compliance while addressing real-world needs for persistent user identity across sessions.
|