@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.
Files changed (90) hide show
  1. package/.claude/settings.local.json +9 -0
  2. package/.turbo/turbo-build.log +1 -1
  3. package/.turbo/turbo-test$colon$coverage.log +3419 -3072
  4. package/.turbo/turbo-test.log +1805 -1680
  5. package/coverage/coverage-final.json +59 -56
  6. package/dist/config/remote-config.d.ts +51 -0
  7. package/dist/config/remote-config.d.ts.map +1 -1
  8. package/dist/config/remote-config.js +74 -0
  9. package/dist/config/remote-config.js.map +1 -1
  10. package/dist/config.d.ts +1 -1
  11. package/dist/config.d.ts.map +1 -1
  12. package/dist/config.js +4 -1
  13. package/dist/config.js.map +1 -1
  14. package/dist/delegation/did-key-resolver.d.ts +64 -0
  15. package/dist/delegation/did-key-resolver.d.ts.map +1 -0
  16. package/dist/delegation/did-key-resolver.js +159 -0
  17. package/dist/delegation/did-key-resolver.js.map +1 -0
  18. package/dist/delegation/utils.d.ts +76 -0
  19. package/dist/delegation/utils.d.ts.map +1 -1
  20. package/dist/delegation/utils.js +117 -0
  21. package/dist/delegation/utils.js.map +1 -1
  22. package/dist/identity/idp-token-resolver.d.ts +17 -1
  23. package/dist/identity/idp-token-resolver.d.ts.map +1 -1
  24. package/dist/identity/idp-token-resolver.js +34 -6
  25. package/dist/identity/idp-token-resolver.js.map +1 -1
  26. package/dist/identity/idp-token-storage.interface.d.ts +38 -7
  27. package/dist/identity/idp-token-storage.interface.d.ts.map +1 -1
  28. package/dist/identity/idp-token-storage.interface.js +2 -0
  29. package/dist/identity/idp-token-storage.interface.js.map +1 -1
  30. package/dist/identity/user-did-manager.d.ts +95 -12
  31. package/dist/identity/user-did-manager.d.ts.map +1 -1
  32. package/dist/identity/user-did-manager.js +107 -25
  33. package/dist/identity/user-did-manager.js.map +1 -1
  34. package/dist/index.d.ts +6 -3
  35. package/dist/index.d.ts.map +1 -1
  36. package/dist/index.js +24 -2
  37. package/dist/index.js.map +1 -1
  38. package/dist/runtime/base.d.ts +25 -8
  39. package/dist/runtime/base.d.ts.map +1 -1
  40. package/dist/runtime/base.js +74 -21
  41. package/dist/runtime/base.js.map +1 -1
  42. package/dist/services/session-registration.service.d.ts.map +1 -1
  43. package/dist/services/session-registration.service.js +10 -90
  44. package/dist/services/session-registration.service.js.map +1 -1
  45. package/dist/services/tool-context-builder.d.ts +18 -1
  46. package/dist/services/tool-context-builder.d.ts.map +1 -1
  47. package/dist/services/tool-context-builder.js +63 -10
  48. package/dist/services/tool-context-builder.js.map +1 -1
  49. package/dist/services/tool-protection.service.d.ts +6 -3
  50. package/dist/services/tool-protection.service.d.ts.map +1 -1
  51. package/dist/services/tool-protection.service.js +89 -34
  52. package/dist/services/tool-protection.service.js.map +1 -1
  53. package/dist/utils/base58.d.ts +31 -0
  54. package/dist/utils/base58.d.ts.map +1 -0
  55. package/dist/utils/base58.js +103 -0
  56. package/dist/utils/base58.js.map +1 -0
  57. package/dist/utils/did-helpers.d.ts +33 -0
  58. package/dist/utils/did-helpers.d.ts.map +1 -1
  59. package/dist/utils/did-helpers.js +53 -0
  60. package/dist/utils/did-helpers.js.map +1 -1
  61. package/package.json +3 -3
  62. package/src/__tests__/identity/user-did-manager.test.ts +64 -45
  63. package/src/__tests__/integration/full-flow.test.ts +23 -10
  64. package/src/__tests__/runtime/base-extensions.test.ts +23 -21
  65. package/src/__tests__/runtime/proof-client-did.test.ts +19 -18
  66. package/src/__tests__/services/agentshield-integration.test.ts +10 -3
  67. package/src/__tests__/services/tool-protection-merged-config.test.ts +485 -0
  68. package/src/__tests__/services/tool-protection.service.test.ts +18 -11
  69. package/src/config/__tests__/merged-config.spec.ts +445 -0
  70. package/src/config/remote-config.ts +90 -0
  71. package/src/config.ts +3 -0
  72. package/src/delegation/__tests__/did-key-resolver.test.ts +265 -0
  73. package/src/delegation/__tests__/vc-issuer.test.ts +1 -1
  74. package/src/delegation/did-key-resolver.ts +179 -0
  75. package/src/delegation/utils.ts +179 -0
  76. package/src/identity/idp-token-resolver.ts +41 -7
  77. package/src/identity/idp-token-storage.interface.ts +42 -7
  78. package/src/identity/user-did-manager.ts +185 -29
  79. package/src/index.ts +42 -3
  80. package/src/runtime/base.ts +84 -21
  81. package/src/services/session-registration.service.ts +26 -121
  82. package/src/services/tool-context-builder.ts +75 -10
  83. package/src/services/tool-protection.service.ts +176 -88
  84. package/src/utils/__tests__/did-helpers.test.ts +55 -0
  85. package/src/utils/base58.ts +109 -0
  86. package/src/utils/did-helpers.ts +60 -0
  87. package/dist/__tests__/utils/mock-providers.d.ts +0 -103
  88. package/dist/__tests__/utils/mock-providers.d.ts.map +0 -1
  89. package/dist/__tests__/utils/mock-providers.js +0 -293
  90. 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
- refreshed
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 access_token
120
- return refreshed.access_token;
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 access_token
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.access_token;
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<IdpTokens | null>;
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
- * Handles ephemeral user DID generation for MCP-I sessions.
5
- * Generates did:key DIDs for users when they join a chat session.
4
+ * Manages user DIDs for MCP-I sessions.
6
5
  *
7
- * This enables tracking which client/user initiated tool calls without
8
- * requiring user registration or persistent identity.
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
- * Generate or retrieve user DID for a session
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 first.
115
- * Otherwise, a new ephemeral did:key is generated.
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
- * - If OAuth identity provided, checks for existing mapping first
123
- * - Falls back to ephemeral DID generation if OAuth unavailable
124
- * - Caches result in session storage for performance
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 generate new DID
191
- console.warn('[UserDidManager] Storage.get failed, generating new DID:', error);
310
+ // Log but continue - session will be anonymous
311
+ console.warn('[UserDidManager] Storage.get failed:', error);
192
312
  }
193
313
  }
194
314
 
195
- // PRIORITY 3: Generate new user DID
196
- const userDid = await this.generateUserDid();
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
- // Cache it
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 it if storage is available
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
- // Log but continue - DID is cached and will be returned
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
- // If OAuth identity provided, create persistent mapping
212
- if (oauthIdentity && oauthIdentity.provider && oauthIdentity.subject && this.config.storage?.setByOAuth) {
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 persistent OAuth mapping for new user DID:', {
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
- return this.generateDidKeyFromPublicKey(publicKeyBytes);
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 { canonicalizeJSON } from "./delegation/utils";
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 { IIdpTokenStorage } from "./identity/idp-token-storage.interface";
306
+ export type {
307
+ IIdpTokenStorage,
308
+ TokenUsageMetadata,
309
+ IdpTokensWithMetadata,
310
+ } from "./identity/idp-token-storage.interface";