@kya-os/mcp-i-cloudflare 1.13.0 → 1.13.2

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 (33) hide show
  1. package/dist/helpers/env-mapper.d.ts.map +1 -1
  2. package/dist/helpers/env-mapper.js +6 -0
  3. package/dist/helpers/env-mapper.js.map +1 -1
  4. package/dist/runtime/oauth-handler.d.ts.map +1 -1
  5. package/dist/runtime/oauth-handler.js +12 -1
  6. package/dist/runtime/oauth-handler.js.map +1 -1
  7. package/dist/runtime/oidc/idp-scopes.d.ts +26 -0
  8. package/dist/runtime/oidc/idp-scopes.d.ts.map +1 -0
  9. package/dist/runtime/oidc/idp-scopes.js +24 -0
  10. package/dist/runtime/oidc/idp-scopes.js.map +1 -0
  11. package/dist/services/batch-queue.d.ts +103 -0
  12. package/dist/services/batch-queue.d.ts.map +1 -0
  13. package/dist/services/batch-queue.js +180 -0
  14. package/dist/services/batch-queue.js.map +1 -0
  15. package/dist/services/consent.service.d.ts +7 -0
  16. package/dist/services/consent.service.d.ts.map +1 -1
  17. package/dist/services/consent.service.js +118 -61
  18. package/dist/services/consent.service.js.map +1 -1
  19. package/dist/services/kya-os-events.service.d.ts +131 -0
  20. package/dist/services/kya-os-events.service.d.ts.map +1 -0
  21. package/dist/services/kya-os-events.service.js +135 -0
  22. package/dist/services/kya-os-events.service.js.map +1 -0
  23. package/dist/services/proof-batch-queue.d.ts +15 -67
  24. package/dist/services/proof-batch-queue.d.ts.map +1 -1
  25. package/dist/services/proof-batch-queue.js +12 -147
  26. package/dist/services/proof-batch-queue.js.map +1 -1
  27. package/dist/services/proof.service.d.ts +7 -0
  28. package/dist/services/proof.service.d.ts.map +1 -1
  29. package/dist/services/proof.service.js +35 -0
  30. package/dist/services/proof.service.js.map +1 -1
  31. package/dist/types.d.ts +2 -0
  32. package/dist/types.d.ts.map +1 -1
  33. package/package.json +2 -2
@@ -0,0 +1,180 @@
1
+ /**
2
+ * Generic Batch Queue (Cloudflare Workers Implementation)
3
+ *
4
+ * Platform-agnostic, type-generic batching for Cloudflare Workers. Collects
5
+ * items in memory and submits them in batches to one or more destinations,
6
+ * without blocking request handling.
7
+ *
8
+ * This is the shared engine behind both the proof batch queue
9
+ * (`proof-batch-queue.ts`) and the KYA-OS activity events emitter
10
+ * (`kya-os-events.service.ts`) so the batching, retry, and flush semantics
11
+ * live in exactly one place.
12
+ *
13
+ * Performance:
14
+ * - Batch size: 10 items (configurable)
15
+ * - Fire-and-forget submission (does not block the caller)
16
+ *
17
+ * Retry Strategy:
18
+ * - Exponential backoff: 1s, 2s, 4s, 8s, 16s
19
+ * - Max retries: 5 (configurable)
20
+ * - Failed items logged and dropped after max retries
21
+ *
22
+ * Note: In Cloudflare Workers, timers do not persist across requests, so
23
+ * automatic flush timers are disabled. Flush is driven by two triggers:
24
+ * within a request when the batch size is reached, and across requests via
25
+ * a scheduled (cron) `flush()` call.
26
+ */
27
+ /**
28
+ * Generic Batch Queue.
29
+ *
30
+ * Collects items and submits them in batches to multiple destinations.
31
+ *
32
+ * Note: In Cloudflare Workers, timers don't persist across requests, so
33
+ * automatic flush timers are disabled. Use manual `flush()` calls via cron.
34
+ */
35
+ export class BatchQueue {
36
+ queue = [];
37
+ pendingBatches = [];
38
+ config;
39
+ closed = false;
40
+ // Stats
41
+ stats = {
42
+ queued: 0,
43
+ submitted: 0,
44
+ failed: 0,
45
+ batchesSubmitted: 0,
46
+ };
47
+ constructor(config) {
48
+ this.config = {
49
+ destinations: config.destinations,
50
+ maxBatchSize: config.maxBatchSize || 10,
51
+ flushIntervalMs: config.flushIntervalMs || 5000,
52
+ maxRetries: config.maxRetries || 5,
53
+ debug: config.debug || false,
54
+ logPrefix: config.logPrefix || "BatchQueue",
55
+ noun: config.noun || "item",
56
+ };
57
+ // Note: Timers are disabled in Cloudflare Workers.
58
+ // Flush must be called manually via cron jobs.
59
+ }
60
+ /** The log prefix, e.g. "[ProofBatchQueue]". */
61
+ get tag() {
62
+ return `[${this.config.logPrefix}]`;
63
+ }
64
+ /**
65
+ * Add an item to the queue.
66
+ */
67
+ enqueue(item) {
68
+ if (this.closed) {
69
+ console.warn(`${this.tag} Queue is closed, dropping ${this.config.noun}`);
70
+ return;
71
+ }
72
+ this.queue.push(item);
73
+ this.stats.queued++;
74
+ if (this.config.debug) {
75
+ console.error(`${this.tag} Enqueued ${this.config.noun} (queue size: ${this.queue.length})`);
76
+ }
77
+ // Flush immediately if batch size reached (Cloudflare Workers compatible)
78
+ if (this.queue.length >= this.config.maxBatchSize) {
79
+ this.flush();
80
+ }
81
+ }
82
+ /**
83
+ * Flush queue immediately (submit all queued items).
84
+ */
85
+ async flush() {
86
+ if (this.queue.length === 0) {
87
+ return;
88
+ }
89
+ const items = this.queue.splice(0, this.config.maxBatchSize);
90
+ if (this.config.debug) {
91
+ console.error(`${this.tag} Flushing ${items.length} ${this.config.noun}s to ${this.config.destinations.length} destinations`);
92
+ }
93
+ // Submit to all destinations
94
+ for (const destination of this.config.destinations) {
95
+ const batch = {
96
+ items: [...items], // Copy items for each destination
97
+ destination,
98
+ retryCount: 0,
99
+ };
100
+ this.submitBatch(batch); // Fire-and-forget
101
+ }
102
+ }
103
+ /**
104
+ * Submit a batch to a destination (with retries).
105
+ */
106
+ async submitBatch(batch) {
107
+ try {
108
+ await batch.destination.submit(batch.items);
109
+ this.stats.submitted += batch.items.length;
110
+ this.stats.batchesSubmitted++;
111
+ if (this.config.debug) {
112
+ console.error(`${this.tag} Successfully submitted ${batch.items.length} ${this.config.noun}s to ${batch.destination.name}`);
113
+ }
114
+ }
115
+ catch (error) {
116
+ console.error(`${this.tag} Failed to submit to ${batch.destination.name}:`, error);
117
+ // Retry with exponential backoff
118
+ if (batch.retryCount < this.config.maxRetries) {
119
+ batch.retryCount++;
120
+ const backoffMs = Math.min(1000 * Math.pow(2, batch.retryCount - 1), 16000);
121
+ batch.nextRetryAt = Date.now() + backoffMs;
122
+ this.pendingBatches.push(batch);
123
+ if (this.config.debug) {
124
+ console.error(`${this.tag} Scheduling retry ${batch.retryCount}/${this.config.maxRetries} in ${backoffMs}ms`);
125
+ }
126
+ }
127
+ else {
128
+ // Max retries exceeded, drop batch
129
+ this.stats.failed += batch.items.length;
130
+ console.error(`${this.tag} Max retries exceeded for ${batch.destination.name}, dropping ${batch.items.length} ${this.config.noun}s`);
131
+ }
132
+ }
133
+ }
134
+ /**
135
+ * Retry pending batches that are ready.
136
+ * Called by cron job or manually.
137
+ */
138
+ async retryPending() {
139
+ const now = Date.now();
140
+ const retryBatches = this.pendingBatches.filter((batch) => batch.nextRetryAt && batch.nextRetryAt <= now);
141
+ if (retryBatches.length > 0) {
142
+ // Remove from pending
143
+ this.pendingBatches = this.pendingBatches.filter((batch) => !retryBatches.includes(batch));
144
+ // Retry each batch
145
+ for (const batch of retryBatches) {
146
+ this.submitBatch(batch); // Fire-and-forget
147
+ }
148
+ }
149
+ }
150
+ /**
151
+ * Close queue and flush remaining items.
152
+ */
153
+ async close() {
154
+ if (this.closed) {
155
+ return;
156
+ }
157
+ this.closed = true;
158
+ // Flush remaining items
159
+ if (this.queue.length > 0) {
160
+ await this.flush();
161
+ }
162
+ // Wait for pending batches (with timeout)
163
+ const timeout = 5000; // 5 seconds
164
+ const startTime = Date.now();
165
+ while (this.pendingBatches.length > 0 && Date.now() - startTime < timeout) {
166
+ await this.retryPending();
167
+ await new Promise((resolve) => setTimeout(resolve, 100));
168
+ }
169
+ if (this.pendingBatches.length > 0) {
170
+ console.warn(`${this.tag} Closing with ${this.pendingBatches.length} pending batches (timed out)`);
171
+ }
172
+ }
173
+ /**
174
+ * Get queue statistics.
175
+ */
176
+ getStats() {
177
+ return { ...this.stats };
178
+ }
179
+ }
180
+ //# sourceMappingURL=batch-queue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"batch-queue.js","sourceRoot":"","sources":["../../src/services/batch-queue.ts"],"names":[],"mappings":"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"}
@@ -384,6 +384,13 @@ export declare class ConsentService {
384
384
  * @returns Parsed body object
385
385
  */
386
386
  private parseRequestBody;
387
+ /**
388
+ * Interpret the `CONSENT_REQUIRE_IDENTITY` env override that gates the
389
+ * identity-required refusal in `handleApproval`. Defaults to enabled - only
390
+ * an explicit `"false"`/`"0"` disables it, mirroring the escape-hatch
391
+ * convention used for `MCPI_HTTP_CHALLENGE` in config.ts.
392
+ */
393
+ private isIdentityRequired;
387
394
  /**
388
395
  * Handle consent approval
389
396
  *
@@ -1 +1 @@
1
- {"version":3,"file":"consent.service.d.ts","sourceRoot":"","sources":["../../src/services/consent.service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"consent.service.d.ts","sourceRoot":"","sources":["../../src/services/consent.service.ts"],"names":[],"mappings":"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"}
@@ -12,6 +12,7 @@ import { DEFAULT_AGENTSHIELD_URL, DEFAULT_SESSION_CACHE_TTL, KEY_PAIR_TTL_SECOND
12
12
  import { STORAGE_KEYS } from "../constants/storage-keys";
13
13
  import { loadDay0Config, getDelegationFieldName } from "../utils/day0-config";
14
14
  import { buildProviderAuthorizeUrl } from "../runtime/oidc/authorize-url.js";
15
+ import { resolveIdpScopes } from "../runtime/oidc/idp-scopes.js";
15
16
  import { validateConsentApprovalRequest, } from "@kya-os/contracts/consent";
16
17
  import { AGENTSHIELD_ENDPOINTS, createDelegationAPIResponseSchema, createDelegationResponseSchema, } from "@kya-os/contracts/agentshield-api";
17
18
  import { createUnsignedVCJWT, completeVCJWT, parseVCJWT, generateDidKeyFromBase64, createDelegationVerifier, createDidKeyResolver, logger, base64urlEncodeFromBytes, base64urlDecodeToBytes, bytesToBase64, wrapDelegationAsVC, } from "@kya-os/mcp";
@@ -1154,13 +1155,19 @@ export class ConsentService {
1154
1155
  !providerConfig.proxyMode) {
1155
1156
  // Use providerConfig.clientId from AgentShield dashboard config
1156
1157
  const oauthClientId = providerConfig.clientId || projectId;
1158
+ // The `scopes` argument holds MCP-I delegation scopes (e.g. "greet:execute"),
1159
+ // which the identity provider has never heard of. Only the provider's own
1160
+ // scopes belong in its authorization URL; delegation scopes already travel
1161
+ // separately in `stateData.scopes` above, for the callback to mint the
1162
+ // delegation.
1163
+ const idpScopes = resolveIdpScopes(providerConfig);
1157
1164
  logger.debug("[ConsentService] Using direct OAuth mode (PKCE)", {
1158
1165
  provider: provider || "unknown",
1159
1166
  authorizationUrl: providerConfig.authorizationUrl,
1160
1167
  supportsPKCE: providerConfig.supportsPKCE,
1161
1168
  clientId: oauthClientId.substring(0, 8) + "...",
1162
1169
  });
1163
- return this.buildDirectOAuthUrl(providerConfig, oauthClientId, `${serverUrl}/oauth/callback`, scopes, stateParam, codeChallenge);
1170
+ return this.buildDirectOAuthUrl(providerConfig, oauthClientId, `${serverUrl}/oauth/callback`, idpScopes, stateParam, codeChallenge);
1164
1171
  }
1165
1172
  // Phase 3: Validate custom parameters don't conflict with reserved parameters
1166
1173
  const RESERVED_PARAMS = [
@@ -1195,7 +1202,9 @@ export class ConsentService {
1195
1202
  oauthUrl.searchParams.set("response_type", "code");
1196
1203
  oauthUrl.searchParams.set("client_id", projectId); // Use projectId as client_id
1197
1204
  oauthUrl.searchParams.set("redirect_uri", `${serverUrl}/oauth/callback`);
1198
- oauthUrl.searchParams.set("scope", scopes.join(" "));
1205
+ // Same separation as the direct-PKCE branch above: `scopes` is the MCP-I
1206
+ // delegation scopes, not what belongs in the IdP-facing `scope` param.
1207
+ oauthUrl.searchParams.set("scope", resolveIdpScopes(providerConfig).join(" "));
1199
1208
  oauthUrl.searchParams.set("state", stateParam);
1200
1209
  // ✅ Pass provider to AgentShield bouncer so it selects the correct auth method
1201
1210
  // This is critical when multiple providers are configured for a project
@@ -3219,6 +3228,19 @@ export class ConsentService {
3219
3228
  throw new Error(`Failed to parse request body: ${error instanceof Error ? error.message : "Unknown error"}`);
3220
3229
  }
3221
3230
  }
3231
+ /**
3232
+ * Interpret the `CONSENT_REQUIRE_IDENTITY` env override that gates the
3233
+ * identity-required refusal in `handleApproval`. Defaults to enabled - only
3234
+ * an explicit `"false"`/`"0"` disables it, mirroring the escape-hatch
3235
+ * convention used for `MCPI_HTTP_CHALLENGE` in config.ts.
3236
+ */
3237
+ isIdentityRequired() {
3238
+ const raw = this.env.CONSENT_REQUIRE_IDENTITY;
3239
+ if (raw === undefined || raw === null)
3240
+ return true;
3241
+ const normalized = String(raw).trim().toLowerCase();
3242
+ return normalized !== "false" && normalized !== "0";
3243
+ }
3222
3244
  /**
3223
3245
  * Handle consent approval
3224
3246
  *
@@ -3453,11 +3475,30 @@ export class ConsentService {
3453
3475
  // ✅ Lazy initialization with projectId
3454
3476
  const auditService = await this.getAuditService(projectId);
3455
3477
  // Check if user needs credentials before delegation
3456
- // Skip credential requirement for consent-only mode (provider_type: 'none')
3457
- const isConsentOnlyMode = providerType === CONSENT_PROVIDER_TYPES.NONE;
3458
- const needsCredentials = !isConsentOnlyMode &&
3459
- !approvalRequest.user_did &&
3460
- !approvalRequest.oauth_identity;
3478
+ // Skip credential requirement for consent-only mode (provider_type: 'none').
3479
+ // Read the EFFECTIVE provider_type off bodyObj, not the `providerType`
3480
+ // captured above: the post-OAuth/post-credential clickwrap branches above
3481
+ // rewrite bodyObj.provider_type to 'oauth'/'password' while `providerType`
3482
+ // stays the original raw 'none'. Gating on the stale value would treat
3483
+ // those already-authenticated clickwrap submissions as consent-only and
3484
+ // skip the identity check entirely.
3485
+ const effectiveProviderType = bodyObj.provider_type;
3486
+ const isConsentOnlyMode = effectiveProviderType === CONSENT_PROVIDER_TYPES.NONE;
3487
+ // Resolve identity once, ahead of the gate below, using the same priority
3488
+ // createDelegation used to apply internally (request.user_did first, then
3489
+ // session lookup). The resolved value is threaded into createDelegation so
3490
+ // it is never resolved a second time.
3491
+ let resolvedUserDid = approvalRequest.user_did;
3492
+ if (!resolvedUserDid && approvalRequest.session_id) {
3493
+ try {
3494
+ resolvedUserDid =
3495
+ (await this.getUserDidForSession(approvalRequest.session_id, approvalRequest.oauth_identity || undefined)) ?? undefined;
3496
+ }
3497
+ catch (error) {
3498
+ logger.debug("[ConsentService] Failed to resolve userDid ahead of identity gate:", error);
3499
+ }
3500
+ }
3501
+ const needsCredentials = !isConsentOnlyMode && !resolvedUserDid;
3461
3502
  if (needsCredentials && auditService) {
3462
3503
  await auditService
3463
3504
  .logCredentialRequired({
@@ -3475,12 +3516,25 @@ export class ConsentService {
3475
3516
  error: err instanceof Error ? err.message : String(err),
3476
3517
  });
3477
3518
  });
3478
- // Note: We don't redirect here - the consent flow continues
3479
- // The credential_required event is just for audit tracking
3519
+ }
3520
+ // Fail closed: an authenticated-provider approval with no resolvable user
3521
+ // identity must not mint a delegation. Consent-only mode is exempt - it
3522
+ // legitimately has no user identity. Gated on CONSENT_REQUIRE_IDENTITY so
3523
+ // a bad interaction can be switched off in production without a redeploy;
3524
+ // defaults to enabled.
3525
+ if (needsCredentials && this.isIdentityRequired()) {
3526
+ return new Response(JSON.stringify({
3527
+ success: false,
3528
+ error: "User identity is required to approve this request",
3529
+ error_code: "identity_required",
3530
+ }), {
3531
+ status: 403,
3532
+ headers: { "Content-Type": "application/json" },
3533
+ });
3480
3534
  }
3481
3535
  // Create delegation via AgentShield API
3482
3536
  logger.debug("[ConsentService] Creating delegation...");
3483
- const delegationResult = await this.createDelegation(approvalRequest, resolveExpirationDays(consentConfig.expirationDays));
3537
+ const delegationResult = await this.createDelegation(approvalRequest, resolveExpirationDays(consentConfig.expirationDays), resolvedUserDid ?? null);
3484
3538
  if (!delegationResult.success) {
3485
3539
  logger.error("[ConsentService] Delegation creation failed:", {
3486
3540
  error: delegationResult.error,
@@ -3507,19 +3561,9 @@ export class ConsentService {
3507
3561
  // ✅ After successful delegation creation - log audit events
3508
3562
  if (auditService && delegationResult.success) {
3509
3563
  try {
3510
- // Get userDid (resolved via OAuth identity resolution)
3511
- // getUserDidForSession can work without DELEGATION_STORAGE (uses in-memory UserDidManager)
3512
- let userDid;
3513
- if (approvalRequest.session_id) {
3514
- try {
3515
- userDid =
3516
- (await this.getUserDidForSession(approvalRequest.session_id, approvalRequest.oauth_identity || undefined)) ?? undefined; // Phase 5: Convert null to undefined
3517
- }
3518
- catch (error) {
3519
- logger.warn("[ConsentService] Failed to get userDid for lifecycle recording:", error);
3520
- // Continue without userDid - audit events can still be logged
3521
- }
3522
- }
3564
+ // Reuse the identity resolved ahead of the gate above - do not
3565
+ // read KV a second time for the same session.
3566
+ const userDid = resolvedUserDid;
3523
3567
  await auditService.logConsentApproval({
3524
3568
  sessionId: approvalRequest.session_id,
3525
3569
  userDid,
@@ -3583,7 +3627,7 @@ export class ConsentService {
3583
3627
  * @param request - Approval request
3584
3628
  * @returns Delegation creation result
3585
3629
  */
3586
- async createDelegation(request, expirationDaysOverride) {
3630
+ async createDelegation(request, expirationDaysOverride, resolvedUserDid) {
3587
3631
  const agentShieldUrl = this.env.AGENTSHIELD_API_URL || DEFAULT_AGENTSHIELD_URL;
3588
3632
  const apiKey = this.env.AGENTSHIELD_API_KEY;
3589
3633
  if (!apiKey) {
@@ -3598,46 +3642,59 @@ export class ConsentService {
3598
3642
  // Load Day0 configuration to determine field name and API capabilities
3599
3643
  await loadDay0Config(this.env.DELEGATION_STORAGE);
3600
3644
  const fieldName = await getDelegationFieldName(this.env.DELEGATION_STORAGE);
3601
- // Get userDID - FIRST check if passed in request, THEN fallback to session storage
3602
- // request.user_did takes priority to avoid KV eventual consistency issues
3603
- // This fixes the bug where credential auth resolves userDid but it's not found in storage
3604
- let userDid = request.user_did;
3605
- // Only fetch from storage if not already provided in request
3606
- if (!userDid && request.session_id) {
3607
- try {
3608
- logger.debug("[ConsentService] Getting User DID for session:", {
3609
- sessionId: request.session_id.substring(0, 20) + "...",
3610
- hasOAuthIdentity: !!request.oauth_identity,
3611
- oauthProvider: request.oauth_identity?.provider,
3612
- hasStorage: !!this.env.DELEGATION_STORAGE,
3613
- });
3614
- // Pass OAuth identity if available in approval request (can be null/undefined)
3615
- // getUserDidForSession can work without DELEGATION_STORAGE (uses in-memory UserDidManager)
3616
- // Phase 5: Returns null if no identity found (session stays anonymous)
3617
- userDid =
3618
- (await this.getUserDidForSession(request.session_id, request.oauth_identity || undefined // Explicitly handle null as undefined
3619
- )) ?? undefined;
3620
- logger.debug("[ConsentService] User DID retrieved from storage:", {
3621
- userDid: userDid?.substring(0, 20) + "...",
3622
- hasUserDid: !!userDid,
3623
- });
3624
- }
3625
- catch (error) {
3626
- logger.debug("[ConsentService] Failed to get/generate userDid:", error);
3627
- // Continue without userDid - delegation will work without user_identifier
3628
- // This is valid for non-OAuth scenarios, but we should log this as a warning
3629
- logger.warn("[ConsentService] Delegation will be created without user_identifier - this may affect user tracking");
3630
- }
3631
- }
3632
- else if (userDid) {
3633
- // userDid was provided in request (e.g., from credential auth flow)
3634
- logger.debug("[ConsentService] Using provided user_did from request:", {
3635
- userDid: userDid.substring(0, 20) + "...",
3636
- source: "request.user_did",
3645
+ // Get userDID. If the caller (handleApproval) already resolved it, use that
3646
+ // directly and skip the lookup below entirely - it was already attempted
3647
+ // with the same priority (request.user_did first, then session storage),
3648
+ // and repeating it would read KV a second time for no benefit.
3649
+ let userDid;
3650
+ if (resolvedUserDid !== undefined) {
3651
+ userDid = resolvedUserDid ?? undefined;
3652
+ logger.debug("[ConsentService] Using pre-resolved userDid:", {
3653
+ hasUserDid: !!userDid,
3637
3654
  });
3638
3655
  }
3639
3656
  else {
3640
- logger.debug("[ConsentService] No session_id provided - skipping User DID generation");
3657
+ // FIRST check if passed in request, THEN fallback to session storage
3658
+ // request.user_did takes priority to avoid KV eventual consistency issues
3659
+ // This fixes the bug where credential auth resolves userDid but it's not found in storage
3660
+ userDid = request.user_did;
3661
+ // Only fetch from storage if not already provided in request
3662
+ if (!userDid && request.session_id) {
3663
+ try {
3664
+ logger.debug("[ConsentService] Getting User DID for session:", {
3665
+ sessionId: request.session_id.substring(0, 20) + "...",
3666
+ hasOAuthIdentity: !!request.oauth_identity,
3667
+ oauthProvider: request.oauth_identity?.provider,
3668
+ hasStorage: !!this.env.DELEGATION_STORAGE,
3669
+ });
3670
+ // Pass OAuth identity if available in approval request (can be null/undefined)
3671
+ // getUserDidForSession can work without DELEGATION_STORAGE (uses in-memory UserDidManager)
3672
+ // Phase 5: Returns null if no identity found (session stays anonymous)
3673
+ userDid =
3674
+ (await this.getUserDidForSession(request.session_id, request.oauth_identity || undefined // Explicitly handle null as undefined
3675
+ )) ?? undefined;
3676
+ logger.debug("[ConsentService] User DID retrieved from storage:", {
3677
+ userDid: userDid?.substring(0, 20) + "...",
3678
+ hasUserDid: !!userDid,
3679
+ });
3680
+ }
3681
+ catch (error) {
3682
+ logger.debug("[ConsentService] Failed to get/generate userDid:", error);
3683
+ // Continue without userDid - delegation will work without user_identifier
3684
+ // This is valid for non-OAuth scenarios, but we should log this as a warning
3685
+ logger.warn("[ConsentService] Delegation will be created without user_identifier - this may affect user tracking");
3686
+ }
3687
+ }
3688
+ else if (userDid) {
3689
+ // userDid was provided in request (e.g., from credential auth flow)
3690
+ logger.debug("[ConsentService] Using provided user_did from request:", {
3691
+ userDid: userDid.substring(0, 20) + "...",
3692
+ source: "request.user_did",
3693
+ });
3694
+ }
3695
+ else {
3696
+ logger.debug("[ConsentService] No session_id provided - skipping User DID generation");
3697
+ }
3641
3698
  }
3642
3699
  const expiresInDays = expirationDaysOverride ?? DEFAULT_EXPIRATION_DAYS;
3643
3700
  // Phase 2 VC-Only: Issue Delegation VC if we have a session and userDid