@kya-os/mcp-i-core 1.3.10-canary.clientinfo.20251126124133 → 1.3.11
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 +1 -1
- package/.turbo/turbo-test$colon$coverage.log +3419 -3072
- package/.turbo/turbo-test.log +1805 -1680
- package/coverage/coverage-final.json +59 -56
- package/dist/config/remote-config.d.ts +51 -0
- package/dist/config/remote-config.d.ts.map +1 -1
- package/dist/config/remote-config.js +74 -0
- package/dist/config/remote-config.js.map +1 -1
- package/dist/config.d.ts +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +4 -1
- package/dist/config.js.map +1 -1
- package/dist/delegation/did-key-resolver.d.ts +64 -0
- package/dist/delegation/did-key-resolver.d.ts.map +1 -0
- package/dist/delegation/did-key-resolver.js +159 -0
- package/dist/delegation/did-key-resolver.js.map +1 -0
- package/dist/delegation/utils.d.ts +76 -0
- package/dist/delegation/utils.d.ts.map +1 -1
- package/dist/delegation/utils.js +117 -0
- package/dist/delegation/utils.js.map +1 -1
- package/dist/identity/idp-token-resolver.d.ts +17 -1
- package/dist/identity/idp-token-resolver.d.ts.map +1 -1
- package/dist/identity/idp-token-resolver.js +34 -6
- package/dist/identity/idp-token-resolver.js.map +1 -1
- package/dist/identity/idp-token-storage.interface.d.ts +38 -7
- package/dist/identity/idp-token-storage.interface.d.ts.map +1 -1
- package/dist/identity/idp-token-storage.interface.js +2 -0
- package/dist/identity/idp-token-storage.interface.js.map +1 -1
- package/dist/identity/user-did-manager.d.ts +95 -12
- package/dist/identity/user-did-manager.d.ts.map +1 -1
- package/dist/identity/user-did-manager.js +107 -25
- package/dist/identity/user-did-manager.js.map +1 -1
- package/dist/index.d.ts +6 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +24 -2
- package/dist/index.js.map +1 -1
- package/dist/runtime/base.d.ts +25 -8
- package/dist/runtime/base.d.ts.map +1 -1
- package/dist/runtime/base.js +74 -21
- package/dist/runtime/base.js.map +1 -1
- package/dist/services/session-registration.service.d.ts.map +1 -1
- package/dist/services/session-registration.service.js +10 -90
- package/dist/services/session-registration.service.js.map +1 -1
- package/dist/services/tool-context-builder.d.ts +18 -1
- package/dist/services/tool-context-builder.d.ts.map +1 -1
- package/dist/services/tool-context-builder.js +63 -10
- package/dist/services/tool-context-builder.js.map +1 -1
- package/dist/services/tool-protection.service.d.ts +6 -3
- package/dist/services/tool-protection.service.d.ts.map +1 -1
- package/dist/services/tool-protection.service.js +89 -34
- package/dist/services/tool-protection.service.js.map +1 -1
- package/dist/utils/base58.d.ts +31 -0
- package/dist/utils/base58.d.ts.map +1 -0
- package/dist/utils/base58.js +103 -0
- package/dist/utils/base58.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 +53 -0
- package/dist/utils/did-helpers.js.map +1 -1
- package/package.json +3 -3
- package/src/__tests__/identity/user-did-manager.test.ts +64 -45
- package/src/__tests__/integration/full-flow.test.ts +23 -10
- package/src/__tests__/runtime/base-extensions.test.ts +23 -21
- package/src/__tests__/runtime/proof-client-did.test.ts +19 -18
- package/src/__tests__/services/agentshield-integration.test.ts +10 -3
- package/src/__tests__/services/tool-protection-merged-config.test.ts +485 -0
- package/src/__tests__/services/tool-protection.service.test.ts +18 -11
- package/src/config/__tests__/merged-config.spec.ts +445 -0
- package/src/config/remote-config.ts +90 -0
- package/src/config.ts +3 -0
- package/src/delegation/__tests__/did-key-resolver.test.ts +265 -0
- package/src/delegation/__tests__/vc-issuer.test.ts +1 -1
- package/src/delegation/did-key-resolver.ts +179 -0
- package/src/delegation/utils.ts +179 -0
- package/src/identity/idp-token-resolver.ts +41 -7
- package/src/identity/idp-token-storage.interface.ts +42 -7
- package/src/identity/user-did-manager.ts +185 -29
- package/src/index.ts +42 -3
- package/src/runtime/base.ts +84 -21
- package/src/services/session-registration.service.ts +26 -121
- package/src/services/tool-context-builder.ts +75 -10
- package/src/services/tool-protection.service.ts +176 -88
- package/src/utils/__tests__/did-helpers.test.ts +55 -0
- package/src/utils/base58.ts +109 -0
- package/src/utils/did-helpers.ts +60 -0
- package/dist/__tests__/utils/mock-providers.d.ts +0 -103
- package/dist/__tests__/utils/mock-providers.d.ts.map +0 -1
- package/dist/__tests__/utils/mock-providers.js +0 -293
- package/dist/__tests__/utils/mock-providers.js.map +0 -1
|
@@ -4,11 +4,14 @@
|
|
|
4
4
|
* Resolves User DID to IDP access token (MH-7 requirement).
|
|
5
5
|
* Handles token lookup, expiration checking, and automatic refresh.
|
|
6
6
|
*
|
|
7
|
+
* Updated for CRED-003: Returns full token data including usage metadata
|
|
8
|
+
* to support credential providers with custom token usage patterns.
|
|
9
|
+
*
|
|
7
10
|
* @package @kya-os/mcp-i-core
|
|
8
11
|
*/
|
|
9
12
|
|
|
10
13
|
import type { IdpTokens } from "@kya-os/contracts/config";
|
|
11
|
-
import type { IIdpTokenStorage } from "./idp-token-storage.interface.js";
|
|
14
|
+
import type { IIdpTokenStorage, IdpTokensWithMetadata } from "./idp-token-storage.interface.js";
|
|
12
15
|
|
|
13
16
|
export interface IdpTokenResolverConfig {
|
|
14
17
|
/** Token storage implementation */
|
|
@@ -68,6 +71,27 @@ export class IdpTokenResolver {
|
|
|
68
71
|
provider: string,
|
|
69
72
|
scopes: string[]
|
|
70
73
|
): Promise<string | null> {
|
|
74
|
+
const tokenData = await this.resolveTokenDataFromDid(userDid, provider, scopes);
|
|
75
|
+
return tokenData?.access_token ?? null;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Resolve User DID to full IDP token data (CRED-003)
|
|
80
|
+
*
|
|
81
|
+
* Returns the full token data including usage metadata for credential providers.
|
|
82
|
+
* This allows ToolContextBuilder to construct appropriate headers based on
|
|
83
|
+
* tokenUsage (cookie/bearer/header) and cookieFormat.
|
|
84
|
+
*
|
|
85
|
+
* @param userDid - User DID to resolve
|
|
86
|
+
* @param provider - OAuth provider name or credential provider
|
|
87
|
+
* @param scopes - Required scopes for token
|
|
88
|
+
* @returns Full token data with metadata or null if not found/expired
|
|
89
|
+
*/
|
|
90
|
+
async resolveTokenDataFromDid(
|
|
91
|
+
userDid: string,
|
|
92
|
+
provider: string,
|
|
93
|
+
scopes: string[]
|
|
94
|
+
): Promise<IdpTokensWithMetadata | null> {
|
|
71
95
|
// 1. Look up token from storage
|
|
72
96
|
const storedToken = await this.config.tokenStorage.getToken(
|
|
73
97
|
userDid,
|
|
@@ -95,6 +119,7 @@ export class IdpTokenResolver {
|
|
|
95
119
|
});
|
|
96
120
|
|
|
97
121
|
// 3. Refresh if refresh_token available
|
|
122
|
+
// Note: Credential tokens don't support refresh - they require re-authentication
|
|
98
123
|
if (storedToken.refresh_token) {
|
|
99
124
|
const refreshed = await this.config.oauthService.refreshToken(
|
|
100
125
|
provider,
|
|
@@ -102,12 +127,20 @@ export class IdpTokenResolver {
|
|
|
102
127
|
);
|
|
103
128
|
|
|
104
129
|
if (refreshed) {
|
|
105
|
-
// 4. Update storage with new tokens
|
|
130
|
+
// 4. Update storage with new tokens, preserving usage metadata
|
|
131
|
+
const refreshedWithMetadata: IdpTokensWithMetadata = {
|
|
132
|
+
...refreshed,
|
|
133
|
+
tokenUsage: storedToken.tokenUsage,
|
|
134
|
+
tokenHeader: storedToken.tokenHeader,
|
|
135
|
+
cookieFormat: storedToken.cookieFormat,
|
|
136
|
+
apiHeaders: storedToken.apiHeaders,
|
|
137
|
+
};
|
|
138
|
+
|
|
106
139
|
await this.config.tokenStorage.storeToken(
|
|
107
140
|
userDid,
|
|
108
141
|
provider,
|
|
109
142
|
scopes,
|
|
110
|
-
|
|
143
|
+
refreshedWithMetadata
|
|
111
144
|
);
|
|
112
145
|
|
|
113
146
|
this.config.logger("[IdpTokenResolver] Token refreshed successfully", {
|
|
@@ -116,8 +149,8 @@ export class IdpTokenResolver {
|
|
|
116
149
|
expiresAt: new Date(refreshed.expires_at).toISOString(),
|
|
117
150
|
});
|
|
118
151
|
|
|
119
|
-
// 5. Return new
|
|
120
|
-
return
|
|
152
|
+
// 5. Return new token data
|
|
153
|
+
return refreshedWithMetadata;
|
|
121
154
|
} else {
|
|
122
155
|
this.config.logger("[IdpTokenResolver] Token refresh failed", {
|
|
123
156
|
userDid: userDid.substring(0, 20) + "...",
|
|
@@ -134,14 +167,15 @@ export class IdpTokenResolver {
|
|
|
134
167
|
}
|
|
135
168
|
}
|
|
136
169
|
|
|
137
|
-
// 4. Return valid
|
|
170
|
+
// 4. Return valid token data
|
|
138
171
|
this.config.logger("[IdpTokenResolver] Token resolved successfully", {
|
|
139
172
|
userDid: userDid.substring(0, 20) + "...",
|
|
140
173
|
provider,
|
|
141
174
|
expiresAt: new Date(storedToken.expires_at).toISOString(),
|
|
175
|
+
tokenUsage: storedToken.tokenUsage,
|
|
142
176
|
});
|
|
143
177
|
|
|
144
|
-
return storedToken
|
|
178
|
+
return storedToken;
|
|
145
179
|
}
|
|
146
180
|
}
|
|
147
181
|
|
|
@@ -5,11 +5,46 @@
|
|
|
5
5
|
* Platform-specific implementations (Cloudflare KV, Node.js database, etc.)
|
|
6
6
|
* implement this interface.
|
|
7
7
|
*
|
|
8
|
+
* Supports both OAuth tokens and credential-based session tokens (CRED-003).
|
|
9
|
+
*
|
|
8
10
|
* @package @kya-os/mcp-i-core
|
|
9
11
|
*/
|
|
10
12
|
|
|
11
13
|
import type { IdpTokens } from "@kya-os/contracts/config";
|
|
12
14
|
|
|
15
|
+
/**
|
|
16
|
+
* Token usage metadata for credential providers (CRED-003)
|
|
17
|
+
*
|
|
18
|
+
* Specifies how the token should be used in subsequent API calls.
|
|
19
|
+
*/
|
|
20
|
+
export interface TokenUsageMetadata {
|
|
21
|
+
/**
|
|
22
|
+
* How to use the token in requests
|
|
23
|
+
* - "cookie": Send as Cookie header
|
|
24
|
+
* - "bearer": Send as Authorization: Bearer xxx
|
|
25
|
+
* - "header": Send as custom header (specify tokenHeader)
|
|
26
|
+
*/
|
|
27
|
+
tokenUsage?: "cookie" | "bearer" | "header";
|
|
28
|
+
|
|
29
|
+
/** Custom header name when tokenUsage is "header" */
|
|
30
|
+
tokenHeader?: string;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Cookie format template when tokenUsage is "cookie"
|
|
34
|
+
* Use {{token}} placeholder for the token value
|
|
35
|
+
* @example "CIX={{token}}; customerCookie={{token}}"
|
|
36
|
+
*/
|
|
37
|
+
cookieFormat?: string;
|
|
38
|
+
|
|
39
|
+
/** Additional headers to include in API calls */
|
|
40
|
+
apiHeaders?: Record<string, string>;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Extended IdpTokens with usage metadata (CRED-003)
|
|
45
|
+
*/
|
|
46
|
+
export interface IdpTokensWithMetadata extends IdpTokens, TokenUsageMetadata {}
|
|
47
|
+
|
|
13
48
|
/**
|
|
14
49
|
* Interface for IDP token storage
|
|
15
50
|
*/
|
|
@@ -18,36 +53,36 @@ export interface IIdpTokenStorage {
|
|
|
18
53
|
* Store IDP tokens
|
|
19
54
|
*
|
|
20
55
|
* @param userDid - User DID to associate tokens with
|
|
21
|
-
* @param provider - OAuth provider name
|
|
56
|
+
* @param provider - OAuth provider name or credential provider
|
|
22
57
|
* @param scopes - Scopes granted for these tokens
|
|
23
|
-
* @param tokens - IDP tokens to store
|
|
58
|
+
* @param tokens - IDP tokens to store (may include usage metadata for credentials)
|
|
24
59
|
*/
|
|
25
60
|
storeToken(
|
|
26
61
|
userDid: string,
|
|
27
62
|
provider: string,
|
|
28
63
|
scopes: string[],
|
|
29
|
-
tokens: IdpTokens
|
|
64
|
+
tokens: IdpTokens | IdpTokensWithMetadata
|
|
30
65
|
): Promise<void>;
|
|
31
66
|
|
|
32
67
|
/**
|
|
33
68
|
* Retrieve IDP tokens
|
|
34
69
|
*
|
|
35
70
|
* @param userDid - User DID to retrieve tokens for
|
|
36
|
-
* @param provider - OAuth provider name
|
|
71
|
+
* @param provider - OAuth provider name or credential provider
|
|
37
72
|
* @param scopes - Scopes to retrieve tokens for
|
|
38
|
-
* @returns IDP tokens or null if not found
|
|
73
|
+
* @returns IDP tokens with optional usage metadata or null if not found
|
|
39
74
|
*/
|
|
40
75
|
getToken(
|
|
41
76
|
userDid: string,
|
|
42
77
|
provider: string,
|
|
43
78
|
scopes: string[]
|
|
44
|
-
): Promise<
|
|
79
|
+
): Promise<IdpTokensWithMetadata | null>;
|
|
45
80
|
|
|
46
81
|
/**
|
|
47
82
|
* Delete IDP tokens
|
|
48
83
|
*
|
|
49
84
|
* @param userDid - User DID
|
|
50
|
-
* @param provider - OAuth provider name
|
|
85
|
+
* @param provider - OAuth provider name or credential provider
|
|
51
86
|
* @param scopes - Scopes
|
|
52
87
|
*/
|
|
53
88
|
deleteToken(
|
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* User DID Manager
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
* Generates did:key DIDs for users when they join a chat session.
|
|
4
|
+
* Manages user DIDs for MCP-I sessions.
|
|
6
5
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
6
|
+
* Phase 5: Anonymous Sessions Until OAuth
|
|
7
|
+
* - Sessions start anonymous (no userDid) until OAuth completes
|
|
8
|
+
* - User DIDs are resolved via AgentShield identity/resolve after OAuth
|
|
9
|
+
* - Eliminates DID fragmentation (same user = same DID across sessions)
|
|
10
|
+
*
|
|
11
|
+
* DID Resolution Priority:
|
|
12
|
+
* 1. OAuth mapping lookup (persistent)
|
|
13
|
+
* 2. Session storage lookup
|
|
14
|
+
* 3. Return null (session stays anonymous)
|
|
9
15
|
*/
|
|
10
16
|
|
|
11
17
|
import { CryptoProvider } from '../providers/base';
|
|
@@ -35,6 +41,35 @@ export interface OAuthIdentity {
|
|
|
35
41
|
name?: string;
|
|
36
42
|
}
|
|
37
43
|
|
|
44
|
+
/**
|
|
45
|
+
* User key pair for signing VCs
|
|
46
|
+
*
|
|
47
|
+
* Contains both public and private keys in base64 format.
|
|
48
|
+
* SECURITY: Private keys should be encrypted at rest.
|
|
49
|
+
*/
|
|
50
|
+
export interface UserKeyPair {
|
|
51
|
+
/**
|
|
52
|
+
* User DID (did:key format)
|
|
53
|
+
*/
|
|
54
|
+
did: string;
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Public key in base64 format
|
|
58
|
+
*/
|
|
59
|
+
publicKey: string;
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Private key in base64 format
|
|
63
|
+
* SECURITY: Should be encrypted at rest in production
|
|
64
|
+
*/
|
|
65
|
+
privateKey: string;
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Key ID (for JWS header)
|
|
69
|
+
*/
|
|
70
|
+
keyId: string;
|
|
71
|
+
}
|
|
72
|
+
|
|
38
73
|
/**
|
|
39
74
|
* User DID storage interface
|
|
40
75
|
*/
|
|
@@ -65,6 +100,35 @@ export interface UserDidStorage {
|
|
|
65
100
|
* If not implemented, OAuth-based storage will be skipped
|
|
66
101
|
*/
|
|
67
102
|
setByOAuth?(provider: string, subject: string, did: string, ttl?: number): Promise<void>;
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Get user key pair for a session (optional - for VC signing)
|
|
106
|
+
* If not implemented, VC issuance will not be available for this session
|
|
107
|
+
*/
|
|
108
|
+
getKeyPair?(sessionId: string): Promise<UserKeyPair | null>;
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Store user key pair for a session (optional - for VC signing)
|
|
112
|
+
* SECURITY: Implementation should encrypt private keys at rest
|
|
113
|
+
*/
|
|
114
|
+
setKeyPair?(sessionId: string, keyPair: UserKeyPair, ttl?: number): Promise<void>;
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Get user key pair by OAuth identity (optional - for persistent key storage)
|
|
118
|
+
* If not implemented, OAuth-based key lookup will be skipped
|
|
119
|
+
*/
|
|
120
|
+
getKeyPairByOAuth?(provider: string, subject: string): Promise<UserKeyPair | null>;
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Store user key pair for OAuth identity (optional - for persistent key storage)
|
|
124
|
+
* SECURITY: Implementation should encrypt private keys at rest
|
|
125
|
+
*/
|
|
126
|
+
setKeyPairByOAuth?(
|
|
127
|
+
provider: string,
|
|
128
|
+
subject: string,
|
|
129
|
+
keyPair: UserKeyPair,
|
|
130
|
+
ttl?: number
|
|
131
|
+
): Promise<void>;
|
|
68
132
|
}
|
|
69
133
|
|
|
70
134
|
/**
|
|
@@ -102,28 +166,84 @@ export interface UserDidManagerConfig {
|
|
|
102
166
|
export class UserDidManager {
|
|
103
167
|
private config: UserDidManagerConfig;
|
|
104
168
|
private sessionDidCache = new Map<string, string>();
|
|
169
|
+
private sessionKeyPairCache = new Map<string, UserKeyPair>();
|
|
105
170
|
|
|
106
171
|
constructor(config: UserDidManagerConfig) {
|
|
107
172
|
this.config = config;
|
|
108
173
|
}
|
|
109
174
|
|
|
110
175
|
/**
|
|
111
|
-
*
|
|
176
|
+
* Get key pair for a session (for VC signing)
|
|
177
|
+
*
|
|
178
|
+
* Returns the key pair if available, null otherwise.
|
|
179
|
+
* Key pairs are stored when DIDs are generated.
|
|
180
|
+
*
|
|
181
|
+
* @param sessionId - MCP session ID
|
|
182
|
+
* @param oauthIdentity - Optional OAuth identity for persistent lookup
|
|
183
|
+
* @returns UserKeyPair or null if not available
|
|
184
|
+
*/
|
|
185
|
+
async getKeyPairForSession(
|
|
186
|
+
sessionId: string,
|
|
187
|
+
oauthIdentity?: OAuthIdentity | null
|
|
188
|
+
): Promise<UserKeyPair | null> {
|
|
189
|
+
// Check in-memory cache first
|
|
190
|
+
if (this.sessionKeyPairCache.has(sessionId)) {
|
|
191
|
+
return this.sessionKeyPairCache.get(sessionId)!;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// Check OAuth-based persistent storage if available
|
|
195
|
+
if (
|
|
196
|
+
oauthIdentity?.provider &&
|
|
197
|
+
oauthIdentity?.subject &&
|
|
198
|
+
this.config.storage?.getKeyPairByOAuth
|
|
199
|
+
) {
|
|
200
|
+
try {
|
|
201
|
+
const keyPair = await this.config.storage.getKeyPairByOAuth(
|
|
202
|
+
oauthIdentity.provider,
|
|
203
|
+
oauthIdentity.subject
|
|
204
|
+
);
|
|
205
|
+
if (keyPair) {
|
|
206
|
+
this.sessionKeyPairCache.set(sessionId, keyPair);
|
|
207
|
+
return keyPair;
|
|
208
|
+
}
|
|
209
|
+
} catch (error) {
|
|
210
|
+
console.warn('[UserDidManager] OAuth key pair lookup failed:', error);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// Check session storage if available
|
|
215
|
+
if (this.config.storage?.getKeyPair) {
|
|
216
|
+
try {
|
|
217
|
+
const keyPair = await this.config.storage.getKeyPair(sessionId);
|
|
218
|
+
if (keyPair) {
|
|
219
|
+
this.sessionKeyPairCache.set(sessionId, keyPair);
|
|
220
|
+
return keyPair;
|
|
221
|
+
}
|
|
222
|
+
} catch (error) {
|
|
223
|
+
console.warn('[UserDidManager] Session key pair lookup failed:', error);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
return null;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Get user DID for a session (Phase 5: No ephemeral generation)
|
|
112
232
|
*
|
|
113
233
|
* If a user DID already exists for the session, it is returned.
|
|
114
|
-
* If OAuth identity is provided, checks for persistent user DID mapping
|
|
115
|
-
*
|
|
234
|
+
* If OAuth identity is provided, checks for persistent user DID mapping.
|
|
235
|
+
* Returns null if no DID found - session stays anonymous until OAuth completes.
|
|
116
236
|
*
|
|
117
237
|
* @param sessionId - MCP session ID
|
|
118
238
|
* @param oauthIdentity - Optional OAuth identity for persistent user DID lookup
|
|
119
|
-
* @returns User DID (did:key format)
|
|
239
|
+
* @returns User DID (did:key format) or null if session is anonymous
|
|
120
240
|
*
|
|
121
241
|
* @remarks
|
|
122
|
-
* -
|
|
123
|
-
* -
|
|
124
|
-
* -
|
|
242
|
+
* - Phase 5: Sessions start anonymous, no ephemeral DID generation
|
|
243
|
+
* - User DIDs are resolved via AgentShield after OAuth completes
|
|
244
|
+
* - Returns null if no existing DID found (instead of generating ephemeral)
|
|
125
245
|
*/
|
|
126
|
-
async getOrCreateUserDid(sessionId: string, oauthIdentity?: OAuthIdentity | null): Promise<string> {
|
|
246
|
+
async getOrCreateUserDid(sessionId: string, oauthIdentity?: OAuthIdentity | null): Promise<string | null> {
|
|
127
247
|
// Check cache first
|
|
128
248
|
if (this.sessionDidCache.has(sessionId)) {
|
|
129
249
|
return this.sessionDidCache.get(sessionId)!;
|
|
@@ -187,29 +307,45 @@ export class UserDidManager {
|
|
|
187
307
|
return storedDid;
|
|
188
308
|
}
|
|
189
309
|
} catch (error) {
|
|
190
|
-
// Log but continue - will
|
|
191
|
-
console.warn('[UserDidManager] Storage.get failed
|
|
310
|
+
// Log but continue - session will be anonymous
|
|
311
|
+
console.warn('[UserDidManager] Storage.get failed:', error);
|
|
192
312
|
}
|
|
193
313
|
}
|
|
194
314
|
|
|
195
|
-
//
|
|
196
|
-
|
|
315
|
+
// PHASE 5: No ephemeral DID generation - session stays anonymous
|
|
316
|
+
// User DID will be resolved via AgentShield after OAuth completes
|
|
317
|
+
return null;
|
|
318
|
+
}
|
|
197
319
|
|
|
198
|
-
|
|
320
|
+
/**
|
|
321
|
+
* Set user DID for a session (Phase 5: After OAuth resolution)
|
|
322
|
+
*
|
|
323
|
+
* Called after AgentShield identity/resolve returns a persistent user DID.
|
|
324
|
+
* Caches the DID and optionally stores in session storage.
|
|
325
|
+
*
|
|
326
|
+
* @param sessionId - MCP session ID
|
|
327
|
+
* @param userDid - Persistent user DID from AgentShield
|
|
328
|
+
* @param oauthIdentity - OAuth identity for creating persistent mappings
|
|
329
|
+
*/
|
|
330
|
+
async setUserDidForSession(
|
|
331
|
+
sessionId: string,
|
|
332
|
+
userDid: string,
|
|
333
|
+
oauthIdentity?: OAuthIdentity | null
|
|
334
|
+
): Promise<void> {
|
|
335
|
+
// Cache in memory
|
|
199
336
|
this.sessionDidCache.set(sessionId, userDid);
|
|
200
337
|
|
|
201
|
-
// Store
|
|
338
|
+
// Store in session storage if available
|
|
202
339
|
if (this.config.storage) {
|
|
203
340
|
try {
|
|
204
341
|
await this.config.storage.set(sessionId, userDid, 1800); // 30 minutes TTL
|
|
205
342
|
} catch (error) {
|
|
206
|
-
|
|
207
|
-
console.warn('[UserDidManager] Storage.set failed, continuing with cached DID:', error);
|
|
343
|
+
console.warn('[UserDidManager] Failed to store user DID in session storage:', error);
|
|
208
344
|
}
|
|
209
345
|
}
|
|
210
346
|
|
|
211
|
-
//
|
|
212
|
-
if (oauthIdentity
|
|
347
|
+
// Create OAuth mapping if provided
|
|
348
|
+
if (oauthIdentity?.provider && oauthIdentity?.subject && this.config.storage?.setByOAuth) {
|
|
213
349
|
try {
|
|
214
350
|
await this.config.storage.setByOAuth(
|
|
215
351
|
oauthIdentity.provider,
|
|
@@ -217,17 +353,14 @@ export class UserDidManager {
|
|
|
217
353
|
userDid,
|
|
218
354
|
90 * 24 * 60 * 60 // 90 days TTL for persistent mapping
|
|
219
355
|
);
|
|
220
|
-
console.log('[UserDidManager] Created
|
|
356
|
+
console.log('[UserDidManager] Created OAuth → DID mapping:', {
|
|
221
357
|
provider: oauthIdentity.provider,
|
|
222
358
|
userDid: userDid.substring(0, 20) + '...',
|
|
223
359
|
});
|
|
224
360
|
} catch (error) {
|
|
225
|
-
// Log but continue - mapping creation failed, but DID is still valid
|
|
226
361
|
console.warn('[UserDidManager] Failed to create OAuth mapping:', error);
|
|
227
362
|
}
|
|
228
363
|
}
|
|
229
|
-
|
|
230
|
-
return userDid;
|
|
231
364
|
}
|
|
232
365
|
|
|
233
366
|
/**
|
|
@@ -237,6 +370,19 @@ export class UserDidManager {
|
|
|
237
370
|
* did:web can be used if configured, but requires additional setup.
|
|
238
371
|
*/
|
|
239
372
|
private async generateUserDid(): Promise<string> {
|
|
373
|
+
const keyPairData = await this.generateUserDidWithKeyPair();
|
|
374
|
+
return keyPairData.did;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
/**
|
|
378
|
+
* Generate a new ephemeral user DID with full key pair
|
|
379
|
+
*
|
|
380
|
+
* Returns the DID along with the key pair for VC signing.
|
|
381
|
+
* Uses did:key format by default.
|
|
382
|
+
*
|
|
383
|
+
* @returns UserKeyPair containing DID, public key, private key, and key ID
|
|
384
|
+
*/
|
|
385
|
+
private async generateUserDidWithKeyPair(): Promise<UserKeyPair> {
|
|
240
386
|
if (this.config.useDidWeb && this.config.didWebBaseUrl) {
|
|
241
387
|
// Generate did:web (requires web server setup)
|
|
242
388
|
// For now, fall back to did:key
|
|
@@ -246,12 +392,22 @@ export class UserDidManager {
|
|
|
246
392
|
|
|
247
393
|
// Generate Ed25519 keypair for user DID
|
|
248
394
|
const keyPair = await this.config.crypto.generateKeyPair();
|
|
249
|
-
|
|
395
|
+
|
|
250
396
|
// Extract public key bytes (32 bytes for Ed25519)
|
|
251
397
|
const publicKeyBytes = this.base64ToBytes(keyPair.publicKey);
|
|
252
|
-
|
|
398
|
+
|
|
253
399
|
// Generate did:key from public key
|
|
254
|
-
|
|
400
|
+
const did = this.generateDidKeyFromPublicKey(publicKeyBytes);
|
|
401
|
+
|
|
402
|
+
// Key ID is the DID with #keys-1 fragment (standard for did:key)
|
|
403
|
+
const keyId = `${did}#keys-1`;
|
|
404
|
+
|
|
405
|
+
return {
|
|
406
|
+
did,
|
|
407
|
+
publicKey: keyPair.publicKey,
|
|
408
|
+
privateKey: keyPair.privateKey,
|
|
409
|
+
keyId,
|
|
410
|
+
};
|
|
255
411
|
}
|
|
256
412
|
|
|
257
413
|
/**
|
package/src/index.ts
CHANGED
|
@@ -201,6 +201,22 @@ export { MemoryStatusListStorage } from "./delegation/storage/memory-statuslist-
|
|
|
201
201
|
|
|
202
202
|
export { MemoryDelegationGraphStorage } from "./delegation/storage/memory-graph-storage";
|
|
203
203
|
|
|
204
|
+
// DID:key Resolver (Phase 3 VC Verification)
|
|
205
|
+
export {
|
|
206
|
+
createDidKeyResolver,
|
|
207
|
+
isEd25519DidKey,
|
|
208
|
+
extractPublicKeyFromDidKey,
|
|
209
|
+
publicKeyToJwk,
|
|
210
|
+
resolveDidKeySync,
|
|
211
|
+
} from "./delegation/did-key-resolver";
|
|
212
|
+
|
|
213
|
+
// Base58 Utilities (for did:key encoding/decoding)
|
|
214
|
+
export {
|
|
215
|
+
base58Encode,
|
|
216
|
+
base58Decode,
|
|
217
|
+
isValidBase58,
|
|
218
|
+
} from "./utils/base58";
|
|
219
|
+
|
|
204
220
|
// Compliance Verification (with JSON Schema draft-07 support)
|
|
205
221
|
export {
|
|
206
222
|
SchemaVerifier,
|
|
@@ -220,7 +236,24 @@ export {
|
|
|
220
236
|
getSchemaStats,
|
|
221
237
|
} from "./compliance/schema-registry";
|
|
222
238
|
|
|
223
|
-
export {
|
|
239
|
+
export {
|
|
240
|
+
canonicalizeJSON,
|
|
241
|
+
createUnsignedVCJWT,
|
|
242
|
+
completeVCJWT,
|
|
243
|
+
parseVCJWT,
|
|
244
|
+
type VCJWTHeader,
|
|
245
|
+
type VCJWTPayload,
|
|
246
|
+
type EncodeVCAsJWTOptions,
|
|
247
|
+
} from "./delegation/utils";
|
|
248
|
+
|
|
249
|
+
// Base64 utilities for VC JWT encoding
|
|
250
|
+
export {
|
|
251
|
+
base64urlEncodeFromBytes,
|
|
252
|
+
base64urlEncodeFromString,
|
|
253
|
+
base64urlDecodeToBytes,
|
|
254
|
+
base64urlDecodeToString,
|
|
255
|
+
bytesToBase64,
|
|
256
|
+
} from "./utils/base64";
|
|
224
257
|
|
|
225
258
|
// Re-export commonly used types from contracts
|
|
226
259
|
// Note: @kya-os/contracts exports are at the root level
|
|
@@ -263,9 +296,15 @@ export { UserDidManager } from "./identity/user-did-manager";
|
|
|
263
296
|
export type {
|
|
264
297
|
UserDidStorage,
|
|
265
298
|
UserDidManagerConfig,
|
|
299
|
+
UserKeyPair,
|
|
300
|
+
OAuthIdentity,
|
|
266
301
|
} from "./identity/user-did-manager";
|
|
267
302
|
|
|
268
|
-
// IDP Token Resolver (Phase 1 - MH-7)
|
|
303
|
+
// IDP Token Resolver (Phase 1 - MH-7, updated for CRED-003)
|
|
269
304
|
export { IdpTokenResolver } from "./identity/idp-token-resolver";
|
|
270
305
|
export type { IdpTokenResolverConfig } from "./identity/idp-token-resolver";
|
|
271
|
-
export type {
|
|
306
|
+
export type {
|
|
307
|
+
IIdpTokenStorage,
|
|
308
|
+
TokenUsageMetadata,
|
|
309
|
+
IdpTokensWithMetadata,
|
|
310
|
+
} from "./identity/idp-token-storage.interface";
|