@kya-os/mcp-i-cloudflare 1.7.11 → 1.7.15

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 (35) hide show
  1. package/dist/agent.d.ts +13 -2
  2. package/dist/agent.d.ts.map +1 -1
  3. package/dist/agent.js +83 -153
  4. package/dist/agent.js.map +1 -1
  5. package/dist/runtime/oauth-handler.d.ts +23 -0
  6. package/dist/runtime/oauth-handler.d.ts.map +1 -1
  7. package/dist/runtime/oauth-handler.js +167 -2
  8. package/dist/runtime/oauth-handler.js.map +1 -1
  9. package/dist/services/consent-audit.service.d.ts +55 -0
  10. package/dist/services/consent-audit.service.d.ts.map +1 -1
  11. package/dist/services/consent-audit.service.js +116 -0
  12. package/dist/services/consent-audit.service.js.map +1 -1
  13. package/dist/services/consent-templates/base/base-template.d.ts.map +1 -1
  14. package/dist/services/consent-templates/base/base-template.js +10 -1
  15. package/dist/services/consent-templates/base/base-template.js.map +1 -1
  16. package/dist/services/consent-templates/modes/credentials.template.d.ts.map +1 -1
  17. package/dist/services/consent-templates/modes/credentials.template.js +4 -1
  18. package/dist/services/consent-templates/modes/credentials.template.js.map +1 -1
  19. package/dist/services/consent-templates/registry.d.ts +6 -0
  20. package/dist/services/consent-templates/registry.d.ts.map +1 -1
  21. package/dist/services/consent-templates/registry.js +11 -17
  22. package/dist/services/consent-templates/registry.js.map +1 -1
  23. package/dist/services/consent-templates/template-renderer.d.ts +3 -0
  24. package/dist/services/consent-templates/template-renderer.d.ts.map +1 -1
  25. package/dist/services/consent-templates/template-renderer.js +9 -2
  26. package/dist/services/consent-templates/template-renderer.js.map +1 -1
  27. package/dist/services/consent-templates/types.d.ts +8 -0
  28. package/dist/services/consent-templates/types.d.ts.map +1 -1
  29. package/dist/services/consent.service.d.ts.map +1 -1
  30. package/dist/services/consent.service.js +458 -256
  31. package/dist/services/consent.service.js.map +1 -1
  32. package/dist/services/credential-auth.handler.d.ts.map +1 -1
  33. package/dist/services/credential-auth.handler.js +8 -0
  34. package/dist/services/credential-auth.handler.js.map +1 -1
  35. package/package.json +5 -5
@@ -13,7 +13,7 @@ import { STORAGE_KEYS } from "../constants/storage-keys";
13
13
  import { loadDay0Config, getDelegationFieldName } from "../utils/day0-config";
14
14
  import { validateConsentApprovalRequest, } from "@kya-os/contracts/consent";
15
15
  import { AGENTSHIELD_ENDPOINTS, createDelegationAPIResponseSchema, createDelegationResponseSchema, } from "@kya-os/contracts/agentshield-api";
16
- import { fetchRemoteConfig, createUnsignedVCJWT, completeVCJWT, parseVCJWT, base64urlEncodeFromBytes, base64urlDecodeToBytes, bytesToBase64, generateDidKeyFromBase64, createDelegationVerifier, createDidKeyResolver, } from "@kya-os/mcp-i-core";
16
+ import { fetchRemoteConfig, createUnsignedVCJWT, completeVCJWT, parseVCJWT, base64urlEncodeFromBytes, base64urlDecodeToBytes, bytesToBase64, generateDidKeyFromBase64, createDelegationVerifier, createDidKeyResolver, logger, } from "@kya-os/mcp-i-core";
17
17
  import { wrapDelegationAsVC } from "@kya-os/contracts";
18
18
  import { WebCryptoProvider } from "../providers/crypto";
19
19
  import { ConsentAuditService } from "./consent-audit.service";
@@ -76,7 +76,7 @@ export class ConsentService {
76
76
  await this.auditInitPromise;
77
77
  }
78
78
  catch (error) {
79
- console.warn("[ConsentService] Audit service initialization failed:", error);
79
+ logger.warn("[ConsentService] Audit service initialization failed:", error);
80
80
  // Don't throw - audit failures shouldn't break consent flow
81
81
  }
82
82
  return this.auditService;
@@ -95,7 +95,7 @@ export class ConsentService {
95
95
  // ✅ CRITICAL: Fetch config from remote API
96
96
  const config = await this.getConfigFromRemoteAPI(projectId);
97
97
  if (!config?.proofing?.enabled) {
98
- console.error("[ConsentService] Proofing not enabled in remote config");
98
+ logger.debug("[ConsentService] Proofing not enabled in remote config");
99
99
  return; // Proofing not enabled
100
100
  }
101
101
  // Get identity (async - requires runtime to be initialized)
@@ -105,16 +105,16 @@ export class ConsentService {
105
105
  // Get audit logger
106
106
  const auditLogger = this.runtime.getAuditLogger();
107
107
  if (!auditLogger) {
108
- console.warn("[ConsentService] AuditLogger not available");
108
+ logger.warn("[ConsentService] AuditLogger not available");
109
109
  return;
110
110
  }
111
111
  // Create audit service with fetched config
112
112
  this.auditService = new ConsentAuditService(new ProofService(config, this.runtime), auditLogger, proofGenerator, config, // ✅ Config fetched from remote API
113
113
  this.runtime);
114
- console.error("[ConsentService] Audit service initialized successfully");
114
+ logger.debug("[ConsentService] Audit service initialized successfully");
115
115
  }
116
116
  catch (error) {
117
- console.error("[ConsentService] Failed to initialize audit service:", error);
117
+ logger.debug("[ConsentService] Failed to initialize audit service:", error);
118
118
  // Don't throw - audit failures shouldn't break consent flow
119
119
  }
120
120
  }
@@ -131,7 +131,7 @@ export class ConsentService {
131
131
  */
132
132
  async getConfigFromRemoteAPI(projectId) {
133
133
  if (!this.env.AGENTSHIELD_API_KEY) {
134
- console.warn("[ConsentService] No API key for runtime config fetch");
134
+ logger.warn("[ConsentService] No API key for runtime config fetch");
135
135
  return undefined;
136
136
  }
137
137
  try {
@@ -166,11 +166,11 @@ export class ConsentService {
166
166
  const runtimeIdentity = await this.runtime?.getIdentity();
167
167
  if (runtimeIdentity?.did) {
168
168
  identityConfig.serverDid = runtimeIdentity.did;
169
- console.error("[ConsentService] Populated serverDid from runtime identity");
169
+ logger.debug("[ConsentService] Populated serverDid from runtime identity");
170
170
  }
171
171
  }
172
172
  catch (error) {
173
- console.warn("[ConsentService] Failed to get runtime identity for serverDid:", error);
173
+ logger.warn("[ConsentService] Failed to get runtime identity for serverDid:", error);
174
174
  }
175
175
  }
176
176
  }
@@ -179,7 +179,7 @@ export class ConsentService {
179
179
  return config;
180
180
  }
181
181
  catch (error) {
182
- console.warn("[ConsentService] Error fetching runtime config:", error);
182
+ logger.warn("[ConsentService] Error fetching runtime config:", error);
183
183
  return undefined;
184
184
  }
185
185
  }
@@ -210,7 +210,7 @@ export class ConsentService {
210
210
  const oauthKey = STORAGE_KEYS.oauthIdentity(oauthIdentity.provider, oauthIdentity.subject);
211
211
  const mappedUserDid = await this.env.DELEGATION_STORAGE.get(oauthKey, "text");
212
212
  if (mappedUserDid) {
213
- console.error("[ConsentService] Found persistent User DID from OAuth mapping:", {
213
+ logger.debug("[ConsentService] Found persistent User DID from OAuth mapping:", {
214
214
  provider: oauthIdentity.provider,
215
215
  userDid: mappedUserDid.substring(0, 20) + "...",
216
216
  });
@@ -218,7 +218,7 @@ export class ConsentService {
218
218
  }
219
219
  }
220
220
  catch (error) {
221
- console.warn("[ConsentService] Failed to check OAuth mapping:", error);
221
+ logger.warn("[ConsentService] Failed to check OAuth mapping:", error);
222
222
  }
223
223
  }
224
224
  // Priority 2: Check session storage for existing DID
@@ -231,7 +231,7 @@ export class ConsentService {
231
231
  }
232
232
  }
233
233
  catch (error) {
234
- console.warn("[ConsentService] Failed to read session cache:", error);
234
+ logger.warn("[ConsentService] Failed to read session cache:", error);
235
235
  }
236
236
  }
237
237
  // Phase 5: No ephemeral DID generation - session stays anonymous
@@ -250,7 +250,7 @@ export class ConsentService {
250
250
  */
251
251
  async updateSessionWithIdentity(sessionId, userDid, oauthIdentity) {
252
252
  if (!this.env.DELEGATION_STORAGE) {
253
- console.warn("[ConsentService] No DELEGATION_STORAGE - cannot persist session identity");
253
+ logger.warn("[ConsentService] No DELEGATION_STORAGE - cannot persist session identity");
254
254
  return;
255
255
  }
256
256
  const sessionKey = STORAGE_KEYS.session(sessionId);
@@ -270,7 +270,7 @@ export class ConsentService {
270
270
  await this.env.DELEGATION_STORAGE.put(userAgentKey, delegationToken, {
271
271
  expirationTtl: delegationTtl,
272
272
  });
273
- console.error("[ConsentService] 🔄 DELEGATION UPGRADE: Migrated consent-only delegation to user+agent scoped:", {
273
+ logger.debug("[ConsentService] 🔄 DELEGATION UPGRADE: Migrated consent-only delegation to user+agent scoped:", {
274
274
  sessionId: sessionId.substring(0, 8) + "...",
275
275
  userDid: userDid.substring(0, 20) + "...",
276
276
  agentDid: agentDid.substring(0, 20) + "...",
@@ -294,7 +294,7 @@ export class ConsentService {
294
294
  }),
295
295
  };
296
296
  await this.env.DELEGATION_STORAGE.put(sessionKey, JSON.stringify(sessionData), { expirationTtl: DEFAULT_SESSION_CACHE_TTL });
297
- console.error("[ConsentService] Session identity updated:", {
297
+ logger.debug("[ConsentService] Session identity updated:", {
298
298
  sessionId: sessionId.substring(0, 8) + "...",
299
299
  userDid: userDid.substring(0, 20) + "...",
300
300
  provider: oauthIdentity?.provider,
@@ -302,7 +302,7 @@ export class ConsentService {
302
302
  });
303
303
  }
304
304
  catch (error) {
305
- console.warn("[ConsentService] Failed to update session with identity:", error);
305
+ logger.warn("[ConsentService] Failed to update session with identity:", error);
306
306
  throw error;
307
307
  }
308
308
  // Create OAuth → DID mapping for future lookups
@@ -312,13 +312,13 @@ export class ConsentService {
312
312
  await this.env.DELEGATION_STORAGE.put(oauthKey, userDid, {
313
313
  expirationTtl: 90 * 24 * 60 * 60, // 90 days for persistent mapping
314
314
  });
315
- console.error("[ConsentService] Created OAuth → DID mapping:", {
315
+ logger.debug("[ConsentService] Created OAuth → DID mapping:", {
316
316
  provider: oauthIdentity.provider,
317
317
  userDid: userDid.substring(0, 20) + "...",
318
318
  });
319
319
  }
320
320
  catch (error) {
321
- console.warn("[ConsentService] Failed to create OAuth mapping:", error);
321
+ logger.warn("[ConsentService] Failed to create OAuth mapping:", error);
322
322
  // Non-fatal - session was updated successfully
323
323
  }
324
324
  }
@@ -343,12 +343,12 @@ export class ConsentService {
343
343
  const key = STORAGE_KEYS.userKeyPair(oauthIdentity.provider, oauthIdentity.subject);
344
344
  const stored = (await this.env.DELEGATION_STORAGE.get(key, "json"));
345
345
  if (stored) {
346
- console.error("[ConsentService] Found key pair in OAuth KV storage");
346
+ logger.debug("[ConsentService] Found key pair in OAuth KV storage");
347
347
  return stored;
348
348
  }
349
349
  }
350
350
  catch (error) {
351
- console.warn("[ConsentService] KV key pair lookup failed:", error);
351
+ logger.warn("[ConsentService] KV key pair lookup failed:", error);
352
352
  }
353
353
  }
354
354
  // Priority 2: Check session storage for ephemeral key pair (consent-only flow)
@@ -358,12 +358,12 @@ export class ConsentService {
358
358
  const sessionKey = STORAGE_KEYS.session(sessionId);
359
359
  const sessionData = (await this.env.DELEGATION_STORAGE.get(sessionKey, "json"));
360
360
  if (sessionData?.keyPair) {
361
- console.error("[ConsentService] Found ephemeral key pair in session storage (consent-only VC signing)");
361
+ logger.debug("[ConsentService] Found ephemeral key pair in session storage (consent-only VC signing)");
362
362
  return sessionData.keyPair;
363
363
  }
364
364
  }
365
365
  catch (error) {
366
- console.warn("[ConsentService] Session key pair lookup failed:", error);
366
+ logger.warn("[ConsentService] Session key pair lookup failed:", error);
367
367
  }
368
368
  }
369
369
  // Priority 3: Try UserDidManager (legacy path, may not be initialized)
@@ -378,7 +378,7 @@ export class ConsentService {
378
378
  }
379
379
  }
380
380
  // No key pair found
381
- console.warn("[ConsentService] No key pair found for session - user cannot sign VCs");
381
+ logger.warn("[ConsentService] No key pair found for session - user cannot sign VCs");
382
382
  return null;
383
383
  }
384
384
  /**
@@ -400,7 +400,7 @@ export class ConsentService {
400
400
  // 1. Try existing lookup first
401
401
  const existingKeyPair = await this.getKeyPairForSession(sessionId, oauthIdentity);
402
402
  if (existingKeyPair) {
403
- console.error("[ConsentService] Found existing key pair for OAuth identity");
403
+ logger.debug("[ConsentService] Found existing key pair for OAuth identity");
404
404
  return existingKeyPair;
405
405
  }
406
406
  // 2. Check KV storage directly by OAuth identity
@@ -411,16 +411,16 @@ export class ConsentService {
411
411
  const key = STORAGE_KEYS.userKeyPair(oauthIdentity.provider, oauthIdentity.subject);
412
412
  const stored = (await this.env.DELEGATION_STORAGE.get(key, "json"));
413
413
  if (stored) {
414
- console.error("[ConsentService] Found key pair in KV storage");
414
+ logger.debug("[ConsentService] Found key pair in KV storage");
415
415
  return stored;
416
416
  }
417
417
  }
418
418
  catch (error) {
419
- console.warn("[ConsentService] KV key pair lookup failed:", error);
419
+ logger.warn("[ConsentService] KV key pair lookup failed:", error);
420
420
  }
421
421
  }
422
422
  // 3. Generate new key pair
423
- console.error("[ConsentService] Generating new key pair for OAuth identity");
423
+ logger.debug("[ConsentService] Generating new key pair for OAuth identity");
424
424
  try {
425
425
  const crypto = new WebCryptoProvider();
426
426
  const rawKeyPair = await crypto.generateKeyPair();
@@ -443,20 +443,20 @@ export class ConsentService {
443
443
  await this.env.DELEGATION_STORAGE.put(key, JSON.stringify(keyPair), {
444
444
  expirationTtl: KEY_PAIR_TTL_SECONDS,
445
445
  });
446
- console.error("[ConsentService] Key pair persisted to KV storage");
446
+ logger.debug("[ConsentService] Key pair persisted to KV storage");
447
447
  }
448
448
  catch (persistError) {
449
- console.warn("[ConsentService] KV key pair persistence failed (non-fatal):", persistError);
449
+ logger.warn("[ConsentService] KV key pair persistence failed (non-fatal):", persistError);
450
450
  }
451
451
  }
452
- console.error("[ConsentService] Key pair generated:", {
452
+ logger.debug("[ConsentService] Key pair generated:", {
453
453
  did: did.substring(0, 30) + "...",
454
454
  keyId,
455
455
  });
456
456
  return keyPair;
457
457
  }
458
458
  catch (error) {
459
- console.error("[ConsentService] Key pair generation failed:", error);
459
+ logger.error("[ConsentService] Key pair generation failed:", error);
460
460
  return null;
461
461
  }
462
462
  }
@@ -489,7 +489,7 @@ export class ConsentService {
489
489
  const sessionKey = STORAGE_KEYS.session(sessionId);
490
490
  const existingSession = (await this.env.DELEGATION_STORAGE.get(sessionKey, "json"));
491
491
  if (existingSession?.userDid) {
492
- console.error("[ConsentService] Session already has userDid, reusing:", {
492
+ logger.debug("[ConsentService] Session already has userDid, reusing:", {
493
493
  sessionId: sessionId.substring(0, 20) + "...",
494
494
  userDid: existingSession.userDid.substring(0, 20) + "...",
495
495
  hasKeyPair: !!existingSession.keyPair,
@@ -498,11 +498,11 @@ export class ConsentService {
498
498
  }
499
499
  }
500
500
  catch (error) {
501
- console.warn("[ConsentService] Failed to check existing session userDid:", error);
501
+ logger.warn("[ConsentService] Failed to check existing session userDid:", error);
502
502
  }
503
503
  }
504
504
  // Generate new ephemeral keypair - THIS TIME WE STORE IT!
505
- console.error("[ConsentService] Generating ephemeral key pair for consent-only VC signing");
505
+ logger.debug("[ConsentService] Generating ephemeral key pair for consent-only VC signing");
506
506
  try {
507
507
  const crypto = new WebCryptoProvider();
508
508
  const rawKeyPair = await crypto.generateKeyPair();
@@ -528,13 +528,13 @@ export class ConsentService {
528
528
  keyPair, // Store the full key pair for VC signing!
529
529
  identityState: "ephemeral",
530
530
  }), { expirationTtl: DEFAULT_SESSION_CACHE_TTL });
531
- console.error("[ConsentService] ✅ Ephemeral key pair stored in session for VC signing");
531
+ logger.debug("[ConsentService] ✅ Ephemeral key pair stored in session for VC signing");
532
532
  }
533
533
  catch (storeError) {
534
- console.warn("[ConsentService] Failed to store ephemeral key pair (VC signing may fail):", storeError);
534
+ logger.warn("[ConsentService] Failed to store ephemeral key pair (VC signing may fail):", storeError);
535
535
  }
536
536
  }
537
- console.error("[ConsentService] ✅ Ephemeral key pair generated:", {
537
+ logger.info("[ConsentService] ✅ Ephemeral key pair generated:", {
538
538
  sessionId: sessionId.substring(0, 20) + "...",
539
539
  userDid: ephemeralUserDid.substring(0, 30) + "...",
540
540
  hasPrivateKey: true,
@@ -543,7 +543,7 @@ export class ConsentService {
543
543
  return ephemeralUserDid;
544
544
  }
545
545
  catch (error) {
546
- console.error("[ConsentService] Failed to generate ephemeral key pair:", error);
546
+ logger.debug("[ConsentService] Failed to generate ephemeral key pair:", error);
547
547
  return null;
548
548
  }
549
549
  }
@@ -567,7 +567,7 @@ export class ConsentService {
567
567
  const keyPair = providedKeyPair ??
568
568
  (await this.getKeyPairForSession(sessionId, oauthIdentity));
569
569
  if (!keyPair) {
570
- console.warn("[ConsentService] Cannot issue VC: no key pair available for session");
570
+ logger.warn("[ConsentService] Cannot issue VC: no key pair available for session");
571
571
  return null;
572
572
  }
573
573
  try {
@@ -592,7 +592,7 @@ export class ConsentService {
592
592
  const signature = base64urlEncodeFromBytes(signatureBytes);
593
593
  // Step 4: Complete the JWT
594
594
  const jwt = completeVCJWT(signingInput, signature);
595
- console.error("[ConsentService] VC issued successfully:", {
595
+ logger.debug("[ConsentService] VC issued successfully:", {
596
596
  issuerDid: keyPair.did.substring(0, 20) + "...",
597
597
  subjectDid: delegation.subjectDid.substring(0, 20) + "...",
598
598
  delegationId: delegation.id,
@@ -601,7 +601,7 @@ export class ConsentService {
601
601
  return jwt;
602
602
  }
603
603
  catch (error) {
604
- console.error("[ConsentService] Failed to issue VC:", error);
604
+ logger.error("[ConsentService] Failed to issue VC:", error);
605
605
  return null;
606
606
  }
607
607
  }
@@ -627,7 +627,7 @@ export class ConsentService {
627
627
  // Step 1: Parse JWT
628
628
  const parsed = parseVCJWT(vcJwt);
629
629
  if (!parsed) {
630
- console.warn("[ConsentService] verifyDelegationVC: Invalid JWT format");
630
+ logger.warn("[ConsentService] verifyDelegationVC: Invalid JWT format");
631
631
  return {
632
632
  valid: false,
633
633
  reason: "Invalid JWT format",
@@ -638,7 +638,7 @@ export class ConsentService {
638
638
  // Step 2: Extract VC from payload
639
639
  const vc = parsed.payload.vc;
640
640
  if (!vc) {
641
- console.warn("[ConsentService] verifyDelegationVC: No VC in JWT payload");
641
+ logger.warn("[ConsentService] verifyDelegationVC: No VC in JWT payload");
642
642
  return {
643
643
  valid: false,
644
644
  reason: "No VC in JWT payload",
@@ -678,7 +678,7 @@ export class ConsentService {
678
678
  const crypto = new WebCryptoProvider();
679
679
  const isValid = await crypto.verify(signingInputBytes, signatureBytes, publicKeyBase64);
680
680
  if (!isValid) {
681
- console.warn("[ConsentService] verifyDelegationVC: JWT signature verification failed");
681
+ logger.warn("[ConsentService] verifyDelegationVC: JWT signature verification failed");
682
682
  return {
683
683
  valid: false,
684
684
  reason: "JWT signature verification failed",
@@ -686,7 +686,7 @@ export class ConsentService {
686
686
  metrics: { totalMs: Date.now() - startTime },
687
687
  };
688
688
  }
689
- console.error("[ConsentService] verifyDelegationVC: JWT signature verified successfully");
689
+ logger.debug("[ConsentService] verifyDelegationVC: JWT signature verified successfully");
690
690
  }
691
691
  // Step 4: Run basic VC validation via DelegationCredentialVerifier
692
692
  // Skip signature verification since we already verified the JWT signature above
@@ -702,13 +702,13 @@ export class ConsentService {
702
702
  result.metrics.totalMs = Date.now() - startTime;
703
703
  }
704
704
  if (result.valid) {
705
- console.error("[ConsentService] verifyDelegationVC: VC verified successfully", {
705
+ logger.debug("[ConsentService] verifyDelegationVC: VC verified successfully", {
706
706
  issuer: vc.issuer,
707
707
  subject: vc.credentialSubject?.id,
708
708
  });
709
709
  }
710
710
  else {
711
- console.warn("[ConsentService] verifyDelegationVC: VC validation failed", {
711
+ logger.warn("[ConsentService] verifyDelegationVC: VC validation failed", {
712
712
  reason: result.reason,
713
713
  stage: result.stage,
714
714
  });
@@ -732,7 +732,7 @@ export class ConsentService {
732
732
  // Priority 0: Check for consent-only mode (authorization.type === 'none')
733
733
  // Consent-only means delegation is required but NO OAuth provider is needed
734
734
  if (toolProtection?.authorization?.type === "none") {
735
- console.error("[ConsentService] Tool is consent-only mode (authorization.type=none), OAuth NOT required", {
735
+ logger.debug("[ConsentService] Tool is consent-only mode (authorization.type=none), OAuth NOT required", {
736
736
  projectId,
737
737
  requiresDelegation: toolProtection.requiresDelegation,
738
738
  });
@@ -755,7 +755,7 @@ export class ConsentService {
755
755
  try {
756
756
  const resolvedProvider = await this.providerResolver.resolveProvider(toolProtection, projectId);
757
757
  if (resolvedProvider) {
758
- console.error("[ConsentService] OAuth required: ProviderResolver resolved provider", {
758
+ logger.debug("[ConsentService] OAuth required: ProviderResolver resolved provider", {
759
759
  projectId,
760
760
  provider: resolvedProvider,
761
761
  toolRequiresDelegation: toolProtection.requiresDelegation,
@@ -767,11 +767,22 @@ export class ConsentService {
767
767
  catch (error) {
768
768
  // Check if this is ConsentOnlyModeError - not a real error
769
769
  if (error instanceof Error && error.name === "ConsentOnlyModeError") {
770
- console.error("[ConsentService] Tool is consent-only mode (ConsentOnlyModeError), OAuth NOT required", { projectId });
770
+ logger.debug("[ConsentService] Tool is consent-only mode (ConsentOnlyModeError), OAuth NOT required", { projectId });
771
+ return false;
772
+ }
773
+ // Check for CredentialAuthModeError - credential auth does NOT require OAuth
774
+ // Use multiple detection methods to handle bundled code where class names may be mangled
775
+ const isCredentialAuthError = error instanceof Error &&
776
+ (error.name === "CredentialAuthModeError" ||
777
+ error.constructor?.name === "CredentialAuthModeError" ||
778
+ ("provider" in error &&
779
+ typeof error.provider === "string"));
780
+ if (isCredentialAuthError) {
781
+ logger.debug("[ConsentService] Tool uses credential auth (CredentialAuthModeError), OAuth NOT required", { projectId });
771
782
  return false;
772
783
  }
773
784
  // ProviderResolver failed - log but continue to fallback check
774
- console.warn("[ConsentService] ProviderResolver failed to resolve provider, falling back to project config check:", {
785
+ logger.warn("[ConsentService] ProviderResolver failed to resolve provider, falling back to project config check:", {
775
786
  projectId,
776
787
  error: error instanceof Error ? error.message : String(error),
777
788
  });
@@ -805,7 +816,7 @@ export class ConsentService {
805
816
  return false;
806
817
  }
807
818
  catch (error) {
808
- console.warn("[ConsentService] Failed to check OAuth requirement:", error);
819
+ logger.warn("[ConsentService] Failed to check OAuth requirement:", error);
809
820
  // On error, default to not requiring OAuth (backward compatibility)
810
821
  return false;
811
822
  }
@@ -846,7 +857,7 @@ export class ConsentService {
846
857
  codeChallenge = pkceChallenge.challenge;
847
858
  }
848
859
  catch (error) {
849
- console.warn("[ConsentService] Failed to generate PKCE challenge:", error);
860
+ logger.warn("[ConsentService] Failed to generate PKCE challenge:", error);
850
861
  }
851
862
  }
852
863
  // Build state data with required fields
@@ -881,7 +892,7 @@ export class ConsentService {
881
892
  // Store state data securely in KV (10 minute TTL for OAuth flow)
882
893
  await oauthSecurityService.storeOAuthState(stateValue, stateData, 600);
883
894
  stateParam = stateValue;
884
- console.error("[ConsentService] 🔒 SECURITY EVENT: OAuth state stored securely:", {
895
+ logger.debug("[ConsentService] 🔒 SECURITY EVENT: OAuth state stored securely:", {
885
896
  projectId,
886
897
  agentDid: agentDid.substring(0, 20) + "...",
887
898
  sessionId: sessionId.substring(0, 20) + "...",
@@ -894,7 +905,7 @@ export class ConsentService {
894
905
  else {
895
906
  // Fallback: Encode state as base64 (less secure, but backward compatible)
896
907
  if (!oauthSecurityService) {
897
- console.warn("[ConsentService] ⚠️ SECURITY WARNING: OAuthSecurityService not provided, using insecure state encoding");
908
+ logger.warn("[ConsentService] ⚠️ SECURITY WARNING: OAuthSecurityService not provided, using insecure state encoding");
898
909
  }
899
910
  stateParam = btoa(JSON.stringify(stateData));
900
911
  }
@@ -904,20 +915,20 @@ export class ConsentService {
904
915
  if (provider && this.providerRegistry) {
905
916
  // Lazy load providers if registry is empty (first request for this project)
906
917
  if (this.providerRegistry.getProviderNames().length === 0) {
907
- console.error("[ConsentService] Loading providers from AgentShield", {
918
+ logger.debug("[ConsentService] Loading providers from AgentShield", {
908
919
  projectId,
909
920
  provider,
910
921
  });
911
922
  try {
912
923
  await this.providerRegistry.loadFromAgentShield(projectId);
913
- console.error("[ConsentService] Providers loaded successfully", {
924
+ logger.debug("[ConsentService] Providers loaded successfully", {
914
925
  projectId,
915
926
  providers: this.providerRegistry.getProviderNames(),
916
927
  configuredProvider: this.providerRegistry.getConfiguredProvider(),
917
928
  });
918
929
  }
919
930
  catch (loadError) {
920
- console.warn("[ConsentService] Failed to load providers from AgentShield", {
931
+ logger.warn("[ConsentService] Failed to load providers from AgentShield", {
921
932
  projectId,
922
933
  error: loadError instanceof Error
923
934
  ? loadError.message
@@ -929,7 +940,7 @@ export class ConsentService {
929
940
  providerConfig = this.providerRegistry.getProvider(provider);
930
941
  }
931
942
  // Diagnostic logging to track race condition and OAuth mode selection
932
- console.error("[ConsentService] OAuth mode decision:", {
943
+ logger.debug("[ConsentService] OAuth mode decision:", {
933
944
  provider: provider || "none",
934
945
  hasProviderRegistry: !!this.providerRegistry,
935
946
  hasProviderConfig: !!providerConfig,
@@ -968,7 +979,7 @@ export class ConsentService {
968
979
  !providerConfig.proxyMode) {
969
980
  // Use providerConfig.clientId from AgentShield dashboard config
970
981
  const oauthClientId = providerConfig.clientId || projectId;
971
- console.error("[ConsentService] Using direct OAuth mode (PKCE)", {
982
+ logger.debug("[ConsentService] Using direct OAuth mode (PKCE)", {
972
983
  provider: provider || "unknown",
973
984
  authorizationUrl: providerConfig.authorizationUrl,
974
985
  supportsPKCE: providerConfig.supportsPKCE,
@@ -1119,7 +1130,7 @@ export class ConsentService {
1119
1130
  try {
1120
1131
  const existingUserDid = await this.env.DELEGATION_STORAGE.get(oauthKey, "text");
1121
1132
  if (existingUserDid) {
1122
- console.error("[ConsentService] OAuth identity already mapped:", {
1133
+ logger.debug("[ConsentService] OAuth identity already mapped:", {
1123
1134
  provider: oauthIdentity.provider,
1124
1135
  subject: oauthIdentity.subject.substring(0, 20) + "...",
1125
1136
  userDid: existingUserDid.substring(0, 20) + "...",
@@ -1128,7 +1139,7 @@ export class ConsentService {
1128
1139
  }
1129
1140
  }
1130
1141
  catch (error) {
1131
- console.warn("[ConsentService] Failed to check OAuth mapping:", error);
1142
+ logger.warn("[ConsentService] Failed to check OAuth mapping:", error);
1132
1143
  // Continue to check session
1133
1144
  }
1134
1145
  // Phase 5: Check for existing user DID in session
@@ -1147,14 +1158,14 @@ export class ConsentService {
1147
1158
  await this.env.DELEGATION_STORAGE.put(oauthIdentityKey, JSON.stringify(oauthIdentity), {
1148
1159
  expirationTtl: 90 * 24 * 60 * 60, // 90 days
1149
1160
  });
1150
- console.error("[ConsentService] OAuth identity linked to User DID:", {
1161
+ logger.debug("[ConsentService] OAuth identity linked to User DID:", {
1151
1162
  provider: oauthIdentity.provider,
1152
1163
  subject: oauthIdentity.subject.substring(0, 20) + "...",
1153
1164
  userDid: userDid.substring(0, 20) + "...",
1154
1165
  });
1155
1166
  }
1156
1167
  catch (error) {
1157
- console.error("[ConsentService] Failed to store OAuth mapping:", error);
1168
+ logger.error("[ConsentService] Failed to store OAuth mapping:", error);
1158
1169
  // Non-fatal - continue with User DID
1159
1170
  }
1160
1171
  return userDid;
@@ -1172,7 +1183,7 @@ export class ConsentService {
1172
1183
  */
1173
1184
  async cacheExternalUserDid(oauthIdentity, userDid) {
1174
1185
  if (!this.env.DELEGATION_STORAGE) {
1175
- console.warn("[ConsentService] No storage available for caching external User DID");
1186
+ logger.warn("[ConsentService] No storage available for caching external User DID");
1176
1187
  return;
1177
1188
  }
1178
1189
  const oauthKey = STORAGE_KEYS.oauthIdentity(oauthIdentity.provider, oauthIdentity.subject);
@@ -1182,7 +1193,7 @@ export class ConsentService {
1182
1193
  if (existingUserDid) {
1183
1194
  // Mapping already exists - verify it matches
1184
1195
  if (existingUserDid !== userDid) {
1185
- console.warn("[ConsentService] OAuth identity already mapped to different User DID:", {
1196
+ logger.warn("[ConsentService] OAuth identity already mapped to different User DID:", {
1186
1197
  provider: oauthIdentity.provider,
1187
1198
  subject: oauthIdentity.subject.substring(0, 20) + "...",
1188
1199
  existingUserDid: existingUserDid.substring(0, 30) + "...",
@@ -1194,7 +1205,7 @@ export class ConsentService {
1194
1205
  }
1195
1206
  }
1196
1207
  catch (error) {
1197
- console.warn("[ConsentService] Failed to check existing OAuth mapping:", error);
1208
+ logger.warn("[ConsentService] Failed to check existing OAuth mapping:", error);
1198
1209
  // Continue to store new mapping
1199
1210
  }
1200
1211
  // Store OAuth identity → userDid mapping (persistent - 90 days)
@@ -1207,7 +1218,7 @@ export class ConsentService {
1207
1218
  await this.env.DELEGATION_STORAGE.put(oauthIdentityKey, JSON.stringify(oauthIdentity), {
1208
1219
  expirationTtl: 90 * 24 * 60 * 60, // 90 days
1209
1220
  });
1210
- console.error("[ConsentService] Cached external User DID from AgentShield:", {
1221
+ logger.debug("[ConsentService] Cached external User DID from AgentShield:", {
1211
1222
  provider: oauthIdentity.provider,
1212
1223
  subject: oauthIdentity.subject.substring(0, 20) + "...",
1213
1224
  userDid: userDid.substring(0, 30) + "...",
@@ -1215,7 +1226,7 @@ export class ConsentService {
1215
1226
  });
1216
1227
  }
1217
1228
  catch (error) {
1218
- console.error("[ConsentService] Failed to cache external User DID:", error);
1229
+ logger.debug("[ConsentService] Failed to cache external User DID:", error);
1219
1230
  // Non-fatal - the persistent user_did will still be used
1220
1231
  }
1221
1232
  }
@@ -1301,6 +1312,21 @@ export class ConsentService {
1301
1312
  // ✅ Extract agent_name from URL query param (passed from buildConsentUrl)
1302
1313
  // Human-readable name for AgentShield dashboard display
1303
1314
  const agentName = params.get("agent_name");
1315
+ // ✅ Extract credential auth params for 3-screen flow (Auth → Clickwrap → Success)
1316
+ // These are set when credential auth completes and redirects to clickwrap page
1317
+ // They ensure the delegation is created with 'password' type instead of 'none'
1318
+ const credentialProviderType = params.get("credential_provider_type");
1319
+ const credentialProvider = params.get("credential_provider");
1320
+ // ✅ Extract mode param for post-credential clickwrap detection
1321
+ // When credential auth completes, user is redirected to /consent?mode=consent-only&credential_provider_type=password
1322
+ const mode = params.get("mode");
1323
+ // ✅ LOOP FIX: Detect post-credential clickwrap state to prevent re-rendering credential form
1324
+ // Both conditions must be true to identify post-credential clickwrap:
1325
+ // 1. mode === "consent-only" (indicates we're past auth phase)
1326
+ // 2. credential_provider_type === "password" (confirms this was a credential auth flow)
1327
+ // IMPORTANT: credential_provider_type is a clickwrap-only signal. It is only set by the
1328
+ // credential-auth redirect to clickwrap; it is NOT used for pure consent-only or oauth flows.
1329
+ const isPostCredentialClickwrap = mode === "consent-only" && credentialProviderType === "password";
1304
1330
  // Validate required parameters
1305
1331
  if (!tool || !agentDid || !sessionId || !projectId) {
1306
1332
  return new Response(JSON.stringify({
@@ -1372,13 +1398,13 @@ export class ConsentService {
1372
1398
  }
1373
1399
  }
1374
1400
  catch (parseError) {
1375
- console.warn("[ConsentService] Invalid OAuth cookie format:", parseError);
1401
+ logger.warn("[ConsentService] Invalid OAuth cookie format:", parseError);
1376
1402
  }
1377
1403
  }
1378
1404
  }
1379
1405
  }
1380
1406
  catch (error) {
1381
- console.warn("[ConsentService] Failed to extract OAuth cookie:", error);
1407
+ logger.warn("[ConsentService] Failed to extract OAuth cookie:", error);
1382
1408
  // Non-fatal - continue without OAuth identity
1383
1409
  }
1384
1410
  // Check if OAuth is required (after extracting OAuth identity)
@@ -1400,7 +1426,7 @@ export class ConsentService {
1400
1426
  // This is the most explicit - passed from buildConsentUrl when tool has oauthProvider configured
1401
1427
  if (urlProvider) {
1402
1428
  provider = urlProvider;
1403
- console.error("[ConsentService] Using provider from URL query param:", {
1429
+ logger.debug("[ConsentService] Using provider from URL query param:", {
1404
1430
  provider,
1405
1431
  projectId,
1406
1432
  tool,
@@ -1417,7 +1443,7 @@ export class ConsentService {
1417
1443
  if (protection) {
1418
1444
  provider = await this.providerResolver.resolveProvider(protection, projectId);
1419
1445
  if (provider) {
1420
- console.error("[ConsentService] Using provider from resolver:", {
1446
+ logger.debug("[ConsentService] Using provider from resolver:", {
1421
1447
  provider,
1422
1448
  projectId,
1423
1449
  tool,
@@ -1428,13 +1454,32 @@ export class ConsentService {
1428
1454
  }
1429
1455
  catch (error) {
1430
1456
  // Check if this is ConsentOnlyModeError - expected behavior, not an error
1431
- if (error instanceof Error && error.name === "ConsentOnlyModeError") {
1432
- console.error("[ConsentService] Tool is consent-only mode, no provider needed for consent page", { projectId, tool });
1457
+ // Use multiple detection methods to handle bundled code where class names may be mangled
1458
+ const isConsentOnlyError = error instanceof Error &&
1459
+ (error.name === "ConsentOnlyModeError" ||
1460
+ error.constructor?.name === "ConsentOnlyModeError");
1461
+ // Check for CredentialAuthModeError - expected behavior for password-based auth
1462
+ // Also check for 'provider' property as fallback detection
1463
+ const isCredentialAuthError = error instanceof Error &&
1464
+ (error.name === "CredentialAuthModeError" ||
1465
+ error.constructor?.name === "CredentialAuthModeError" ||
1466
+ // Fallback: check for provider property (unique to CredentialAuthModeError)
1467
+ ("provider" in error &&
1468
+ typeof error.provider === "string"));
1469
+ if (isConsentOnlyError) {
1470
+ logger.debug("[ConsentService] Tool is consent-only mode, no provider needed for consent page", { projectId, tool });
1433
1471
  // Continue without provider - consent-only mode just needs clickwrap
1434
1472
  }
1473
+ else if (isCredentialAuthError) {
1474
+ // CredentialAuthModeError is expected behavior for password-based auth
1475
+ // Extract provider from the error for credential form rendering
1476
+ const credError = error;
1477
+ provider = credError.provider;
1478
+ logger.debug("[ConsentService] Tool uses credential auth, setting provider for credential form", { projectId, tool, provider });
1479
+ }
1435
1480
  else {
1436
1481
  // Non-fatal - continue without provider info
1437
- console.warn("[ConsentService] Failed to resolve provider for consent page:", error);
1482
+ logger.warn("[ConsentService] Failed to resolve provider for consent page:", error);
1438
1483
  }
1439
1484
  }
1440
1485
  }
@@ -1442,7 +1487,7 @@ export class ConsentService {
1442
1487
  // This is a SEPARATE check (not else-if) to handle when providerResolver exists but returns undefined
1443
1488
  if (!provider && toolOAuthProvider) {
1444
1489
  provider = toolOAuthProvider;
1445
- console.error("[ConsentService] Using provider from tool protection (fallback):", {
1490
+ logger.debug("[ConsentService] Using provider from tool protection (fallback):", {
1446
1491
  provider,
1447
1492
  projectId,
1448
1493
  tool,
@@ -1450,10 +1495,29 @@ export class ConsentService {
1450
1495
  }
1451
1496
  let resolvedOAuthUrl;
1452
1497
  let isOAuthRequired = false;
1453
- // Skip OAuth flow for credentials provider - credentials uses form-based auth, not OAuth
1454
- const isCredentialsProvider = provider?.toLowerCase() === "credentials";
1498
+ // CONFIG-BASED CREDENTIAL DETECTION (replaces string matching)
1499
+ // Fetch credential provider config ONCE and reuse throughout the method
1500
+ // Only fetch when: provider exists AND we're not in post-credential clickwrap state
1501
+ // This avoids unnecessary network calls for pure consent-only tools and post-auth clickwrap
1502
+ let credentialProviderConfig = null;
1503
+ if (provider && projectId && !isPostCredentialClickwrap) {
1504
+ try {
1505
+ credentialProviderConfig = await this.getCredentialProviderConfig(projectId, provider);
1506
+ }
1507
+ catch (err) {
1508
+ // Non-fatal: log and continue - will fall back to OAuth flow
1509
+ logger.warn("[ConsentService] Failed to fetch credential provider config:", err);
1510
+ }
1511
+ }
1512
+ // Determine if this is a credentials provider based on config existence (not string matching)
1513
+ const isCredentialsProvider = !!credentialProviderConfig;
1455
1514
  if (isCredentialsProvider && oauthRequired) {
1456
- console.error("[ConsentService] Credentials provider detected - skipping OAuth flow, will render credential form", { provider, projectId, tool });
1515
+ logger.debug("[ConsentService] Credential provider detected via config - skipping OAuth flow, will render credential form", {
1516
+ provider,
1517
+ projectId,
1518
+ tool,
1519
+ providerType: credentialProviderConfig?.type,
1520
+ });
1457
1521
  }
1458
1522
  if (oauthRequired && !isCredentialsProvider) {
1459
1523
  // OAuth is required - redirect to OAuth provider instead of showing consent page
@@ -1468,7 +1532,7 @@ export class ConsentService {
1468
1532
  oauthSecurityService, agentName || undefined // Human-readable agent name for AgentShield dashboard
1469
1533
  );
1470
1534
  isOAuthRequired = true;
1471
- console.error("[ConsentService] 🔒 SECURITY EVENT: OAuth required, preparing consent page with redirect:", {
1535
+ logger.debug("[ConsentService] 🔒 SECURITY EVENT: OAuth required, preparing consent page with redirect:", {
1472
1536
  projectId,
1473
1537
  agentDid: agentDid.substring(0, 20) + "...",
1474
1538
  oauthUrl: resolvedOAuthUrl.substring(0, 100) + "...",
@@ -1492,7 +1556,7 @@ export class ConsentService {
1492
1556
  })
1493
1557
  .catch((err) => {
1494
1558
  // Structured error logging
1495
- console.error("[ConsentService] Audit logging failed", {
1559
+ logger.debug("[ConsentService] Audit logging failed", {
1496
1560
  eventType: "consent:page_viewed",
1497
1561
  sessionId,
1498
1562
  error: err instanceof Error ? err.message : String(err),
@@ -1515,10 +1579,12 @@ export class ConsentService {
1515
1579
  provider, // Phase 2: Include provider if resolved
1516
1580
  branding: consentConfig.branding,
1517
1581
  // ✅ Ensure terms.required has a default value (contracts requires boolean, not boolean | undefined)
1518
- terms: consentConfig.terms ? {
1519
- ...consentConfig.terms,
1520
- required: consentConfig.terms.required ?? true,
1521
- } : undefined,
1582
+ terms: consentConfig.terms
1583
+ ? {
1584
+ ...consentConfig.terms,
1585
+ required: consentConfig.terms.required ?? true,
1586
+ }
1587
+ : undefined,
1522
1588
  customFields: consentConfig.customFields,
1523
1589
  autoClose: consentConfig.ui?.autoClose ?? false,
1524
1590
  // ✅ FIX: Pass full UI config (title, description, button text, etc.)
@@ -1530,35 +1596,34 @@ export class ConsentService {
1530
1596
  // Pass OAuth details for client-side handling
1531
1597
  oauthRequired: isOAuthRequired,
1532
1598
  oauthUrl: resolvedOAuthUrl,
1599
+ // ✅ Pass credential auth params for 3-screen flow (Auth → Clickwrap → Success)
1600
+ // These are set when user is redirected from credential auth page to clickwrap
1601
+ // They ensure the delegation is created with 'password' type instead of 'none'
1602
+ credentialProviderType: credentialProviderType || undefined,
1603
+ credentialProvider: credentialProvider || undefined,
1533
1604
  };
1534
- // CRED-003: Check if this is a credential provider and render credential form
1535
- if (provider && projectId) {
1536
- try {
1537
- const credentialProviderConfig = await this.getCredentialProviderConfig(projectId, provider);
1538
- if (credentialProviderConfig) {
1539
- console.error("[ConsentService] Credential provider detected, rendering credential page", {
1540
- projectId,
1541
- provider,
1542
- providerType: credentialProviderConfig.type,
1543
- displayName: credentialProviderConfig.displayName,
1544
- });
1545
- // Generate and store CSRF token for form security
1546
- const csrfToken = await this.storeCredentialCsrfToken(sessionId);
1547
- // Render credential login page instead of OAuth consent
1548
- const html = this.renderer.renderCredentialPage(pageConfig, credentialProviderConfig, provider, csrfToken);
1549
- return new Response(html, {
1550
- status: 200,
1551
- headers: {
1552
- "Content-Type": "text/html; charset=utf-8",
1553
- "Cache-Control": "no-cache, no-store, must-revalidate",
1554
- },
1555
- });
1556
- }
1557
- }
1558
- catch (credError) {
1559
- // Non-fatal: If credential provider check fails, fall through to OAuth
1560
- console.warn("[ConsentService] Credential provider check failed, falling back to OAuth:", credError);
1561
- }
1605
+ // CRED-003: Render credential form if this is a credential provider
1606
+ // Guard conditions:
1607
+ // 1. credentialProviderConfig must exist (already fetched above)
1608
+ // 2. Must NOT be in post-credential clickwrap mode (would cause infinite loop)
1609
+ if (credentialProviderConfig && !isPostCredentialClickwrap) {
1610
+ logger.debug("[ConsentService] Credential provider detected, rendering credential page", {
1611
+ projectId,
1612
+ provider,
1613
+ providerType: credentialProviderConfig.type,
1614
+ displayName: credentialProviderConfig.displayName,
1615
+ });
1616
+ // Generate and store CSRF token for form security
1617
+ const csrfToken = await this.storeCredentialCsrfToken(sessionId);
1618
+ // Render credential login page instead of OAuth consent
1619
+ const html = this.renderer.renderCredentialPage(pageConfig, credentialProviderConfig, provider, csrfToken);
1620
+ return new Response(html, {
1621
+ status: 200,
1622
+ headers: {
1623
+ "Content-Type": "text/html; charset=utf-8",
1624
+ "Cache-Control": "no-cache, no-store, must-revalidate",
1625
+ },
1626
+ });
1562
1627
  }
1563
1628
  // Standard OAuth flow: Render page with OAuth identity (if available)
1564
1629
  const html = this.renderer.render(pageConfig, oauthIdentity);
@@ -1571,7 +1636,7 @@ export class ConsentService {
1571
1636
  });
1572
1637
  }
1573
1638
  catch (error) {
1574
- console.error("[ConsentService] Error rendering consent page:", error);
1639
+ logger.error("[ConsentService] Error rendering consent page:", error);
1575
1640
  return new Response(JSON.stringify({
1576
1641
  success: false,
1577
1642
  error: "Failed to render consent page",
@@ -1809,7 +1874,7 @@ export class ConsentService {
1809
1874
  }
1810
1875
  catch (formDataError) {
1811
1876
  // FormData parsing failed, try URL-encoded text parsing
1812
- console.warn("[ConsentService] FormData parsing failed, trying URL-encoded text:", formDataError);
1877
+ logger.warn("[ConsentService] FormData parsing failed, trying URL-encoded text:", formDataError);
1813
1878
  }
1814
1879
  // Try URL-encoded text parsing as fallback
1815
1880
  try {
@@ -1820,7 +1885,7 @@ export class ConsentService {
1820
1885
  }
1821
1886
  catch (urlEncodedError) {
1822
1887
  // Both failed, fall through to JSON parsing
1823
- console.warn("[ConsentService] URL-encoded parsing also failed:", urlEncodedError);
1888
+ logger.warn("[ConsentService] URL-encoded parsing also failed:", urlEncodedError);
1824
1889
  }
1825
1890
  }
1826
1891
  // Parse multipart FormData (multipart/form-data or when FormData object is passed with other Content-Type)
@@ -2148,7 +2213,7 @@ export class ConsentService {
2148
2213
  }
2149
2214
  }
2150
2215
  catch (formDataError) {
2151
- console.warn("[ConsentService] FormData parsing failed:", formDataError);
2216
+ logger.warn("[ConsentService] FormData parsing failed:", formDataError);
2152
2217
  // Fall through to JSON parsing
2153
2218
  }
2154
2219
  }
@@ -2665,58 +2730,115 @@ export class ConsentService {
2665
2730
  * @returns JSON response
2666
2731
  */
2667
2732
  async handleApproval(request) {
2668
- console.error("[ConsentService] Approval request received");
2733
+ logger.debug("[ConsentService] Approval request received");
2669
2734
  try {
2670
2735
  // Parse and validate request body (supports both JSON and FormData)
2671
2736
  const body = await this.parseRequestBody(request);
2672
- console.error("[ConsentService] Request body parsed:", {
2737
+ logger.debug("[ConsentService] Request body parsed:", {
2673
2738
  hasBody: !!body,
2674
2739
  bodyKeys: Object.keys(body || {}),
2675
2740
  hasOAuthIdentity: !!body?.oauth_identity,
2676
2741
  });
2677
2742
  // Handle provider_type routing:
2678
- // - 'credential': User authenticated via credential form (email/password)
2743
+ // - 'credential' or 'password': User authenticated via credential form (email/password)
2679
2744
  // - 'oauth2': User authenticated via OAuth provider (handled below)
2680
2745
  // - 'none': Consent-only mode (clickwrap) - user agrees without authentication
2681
2746
  const bodyObj = body;
2682
2747
  const providerType = bodyObj?.provider_type;
2683
2748
  // CRED-003: Check for credential provider submission
2684
- // Credential submissions include `provider_type: 'credential'` and are handled separately
2685
- if (providerType === CONSENT_PROVIDER_TYPES.CREDENTIAL) {
2686
- console.error("[ConsentService] Credential submission detected");
2749
+ // Credential submissions include `provider_type: 'credential'` or 'password' and are handled separately
2750
+ // IMPORTANT: AgentShield tool protection uses 'password' for credential-based auth validation,
2751
+ // but we also accept 'credential' for backward compatibility
2752
+ if (providerType === CONSENT_PROVIDER_TYPES.CREDENTIAL ||
2753
+ providerType === CONSENT_PROVIDER_TYPES.PASSWORD) {
2754
+ logger.debug("[ConsentService] Credential submission detected", {
2755
+ provider_type: providerType,
2756
+ });
2687
2757
  return this.handleCredentialApproval(bodyObj);
2688
2758
  }
2689
2759
  // ✅ Consent-only mode (provider_type: 'none')
2690
- // User consents without authentication - clickwrap only
2691
- // Generate an ephemeral userDid to enable reliable delegation storage & lookup
2760
+ // This can be:
2761
+ // 1. Pure consent-only: User consents without authentication (clickwrap only)
2762
+ // 2. Post-credential clickwrap: User already authenticated via credentials, this is the clickwrap step
2763
+ // 3. Post-OAuth clickwrap: User already authenticated via OAuth, this is the clickwrap step
2692
2764
  if (providerType === CONSENT_PROVIDER_TYPES.NONE) {
2693
- console.error("[ConsentService] Consent-only mode detected (clickwrap)");
2694
- // Extract session_id for ephemeral userDid generation
2695
- const sessionId = body
2696
- .session_id;
2697
- if (sessionId) {
2698
- // Generate ephemeral userDid for this consent-only session
2699
- // This enables PRIORITY 1 delegation key (user+agent scoped) for reliable lookup
2700
- const ephemeralUserDid = await this.generateEphemeralUserDidForSession(sessionId);
2701
- if (ephemeralUserDid) {
2702
- // Store ephemeral userDid in session cache
2703
- // This ensures storeDelegationToken can find it and use PRIORITY 1 key
2704
- await this.updateSessionWithIdentity(sessionId, ephemeralUserDid, null // No OAuth identity for consent-only
2705
- );
2706
- // Also inject the user_did into the request body so createDelegation receives it
2707
- body.user_did = ephemeralUserDid;
2708
- console.error("[ConsentService] Ephemeral userDid stored in session for consent-only flow:", {
2709
- sessionId: sessionId.substring(0, 20) + "...",
2710
- userDid: ephemeralUserDid.substring(0, 30) + "...",
2711
- note: "Enables reliable delegation lookup via PRIORITY 1 key",
2712
- });
2713
- }
2714
- else {
2715
- console.warn("[ConsentService] ⚠️ Failed to generate ephemeral userDid - delegation will use session-scoped storage only");
2765
+ const bodyObj = body;
2766
+ const sessionId = bodyObj.session_id;
2767
+ // Check for credential auth parameters passed from handleCredentialApproval
2768
+ // These indicate this is the clickwrap step AFTER credential authentication
2769
+ const credentialProviderType = bodyObj.credential_provider_type;
2770
+ const credentialProvider = bodyObj.credential_provider;
2771
+ if (credentialProviderType &&
2772
+ credentialProviderType === CONSENT_PROVIDER_TYPES.PASSWORD) {
2773
+ // This is the clickwrap step after credential auth
2774
+ // The session already has userDid from credential auth
2775
+ logger.debug("[ConsentService] Consent-only mode (post-credential clickwrap)");
2776
+ // Override provider_type to 'password' so delegation is created with correct authorization
2777
+ // This ensures authorization.type matches tool protection expectation
2778
+ bodyObj.provider_type = CONSENT_PROVIDER_TYPES.PASSWORD;
2779
+ if (credentialProvider) {
2780
+ bodyObj.customFields = {
2781
+ ...(bodyObj.customFields || {}),
2782
+ provider: credentialProvider,
2783
+ provider_type: CONSENT_PROVIDER_TYPES.PASSWORD,
2784
+ };
2716
2785
  }
2786
+ logger.debug("[ConsentService] ✅ Using credential auth provider_type for delegation:", {
2787
+ sessionId: sessionId?.substring(0, 20) + "...",
2788
+ providerType: CONSENT_PROVIDER_TYPES.PASSWORD,
2789
+ provider: credentialProvider,
2790
+ note: "Delegation will have authorization.type='password' to match tool protection",
2791
+ });
2792
+ // The userDid should already be in the session from credential auth
2793
+ // We don't need to generate ephemeral one
2717
2794
  }
2718
2795
  else {
2719
- console.warn("[ConsentService] ⚠️ No session_id for consent-only flow - delegation will use session-scoped storage only");
2796
+ // Pure consent-only mode - no prior authentication
2797
+ logger.debug("[ConsentService] Consent-only mode detected (pure clickwrap)");
2798
+ if (sessionId && this.env.DELEGATION_STORAGE) {
2799
+ // Check if session already has userDid (from credential auth or OAuth)
2800
+ let existingUserDid;
2801
+ try {
2802
+ const sessionKey = STORAGE_KEYS.session(sessionId);
2803
+ const existingSession = (await this.env.DELEGATION_STORAGE.get(sessionKey, "json"));
2804
+ existingUserDid = existingSession?.userDid;
2805
+ }
2806
+ catch (error) {
2807
+ logger.warn("[ConsentService] Failed to read session for userDid:", error);
2808
+ }
2809
+ if (existingUserDid) {
2810
+ // Session has userDid from prior auth step - use it
2811
+ logger.debug("[ConsentService] Session already has userDid, reusing:", {
2812
+ sessionId: sessionId.substring(0, 20) + "...",
2813
+ userDid: existingUserDid.substring(0, 30) + "...",
2814
+ });
2815
+ bodyObj.user_did = existingUserDid;
2816
+ }
2817
+ else {
2818
+ // Generate ephemeral userDid for pure consent-only
2819
+ // This enables PRIORITY 1 delegation key (user+agent scoped) for reliable lookup
2820
+ const ephemeralUserDid = await this.generateEphemeralUserDidForSession(sessionId);
2821
+ if (ephemeralUserDid) {
2822
+ // Store ephemeral userDid in session cache
2823
+ // This ensures storeDelegationToken can find it and use PRIORITY 1 key
2824
+ await this.updateSessionWithIdentity(sessionId, ephemeralUserDid, null // No OAuth identity for consent-only
2825
+ );
2826
+ // Also inject the user_did into the request body so createDelegation receives it
2827
+ bodyObj.user_did = ephemeralUserDid;
2828
+ logger.debug("[ConsentService] ✅ Ephemeral userDid stored in session for consent-only flow:", {
2829
+ sessionId: sessionId.substring(0, 20) + "...",
2830
+ userDid: ephemeralUserDid.substring(0, 30) + "...",
2831
+ note: "Enables reliable delegation lookup via PRIORITY 1 key",
2832
+ });
2833
+ }
2834
+ else {
2835
+ logger.warn("[ConsentService] ⚠️ Failed to generate ephemeral userDid - delegation will use session-scoped storage only");
2836
+ }
2837
+ }
2838
+ }
2839
+ else {
2840
+ logger.warn("[ConsentService] ⚠️ No session_id for consent-only flow - delegation will use session-scoped storage only");
2841
+ }
2720
2842
  }
2721
2843
  }
2722
2844
  // Convert null oauth_identity to undefined for proper schema validation
@@ -2733,7 +2855,7 @@ export class ConsentService {
2733
2855
  }
2734
2856
  const validation = validateConsentApprovalRequest(body);
2735
2857
  if (!validation.success) {
2736
- console.error("[ConsentService] Approval request validation failed:", {
2858
+ logger.error("[ConsentService] Approval request validation failed:", {
2737
2859
  errors: validation.error.errors,
2738
2860
  receivedBody: body,
2739
2861
  });
@@ -2748,7 +2870,7 @@ export class ConsentService {
2748
2870
  });
2749
2871
  }
2750
2872
  const approvalRequest = validation.data;
2751
- console.error("[ConsentService] Approval request validated:", {
2873
+ logger.debug("[ConsentService] Approval request validated:", {
2752
2874
  agentDid: approvalRequest.agent_did?.substring(0, 20) + "...",
2753
2875
  sessionId: approvalRequest.session_id?.substring(0, 20) + "...",
2754
2876
  scopes: approvalRequest.scopes,
@@ -2788,7 +2910,7 @@ export class ConsentService {
2788
2910
  oauthProvider: approvalRequest.oauth_identity?.provider,
2789
2911
  })
2790
2912
  .catch((err) => {
2791
- console.error("[ConsentService] Failed to log credential required", {
2913
+ logger.debug("[ConsentService] Failed to log credential required", {
2792
2914
  eventType: "consent:credential_required",
2793
2915
  sessionId: approvalRequest.session_id,
2794
2916
  error: err instanceof Error ? err.message : String(err),
@@ -2798,10 +2920,10 @@ export class ConsentService {
2798
2920
  // The credential_required event is just for audit tracking
2799
2921
  }
2800
2922
  // Create delegation via AgentShield API
2801
- console.error("[ConsentService] Creating delegation...");
2923
+ logger.debug("[ConsentService] Creating delegation...");
2802
2924
  const delegationResult = await this.createDelegation(approvalRequest);
2803
2925
  if (!delegationResult.success) {
2804
- console.error("[ConsentService] Delegation creation failed:", {
2926
+ logger.error("[ConsentService] Delegation creation failed:", {
2805
2927
  error: delegationResult.error,
2806
2928
  error_code: delegationResult.error_code,
2807
2929
  });
@@ -2814,7 +2936,7 @@ export class ConsentService {
2814
2936
  headers: { "Content-Type": "application/json" },
2815
2937
  });
2816
2938
  }
2817
- console.error("[ConsentService] ✅ Delegation created successfully:", {
2939
+ logger.info("[ConsentService] ✅ Delegation created successfully:", {
2818
2940
  delegationId: delegationResult.delegation_id?.substring(0, 20) + "...",
2819
2941
  });
2820
2942
  // Store delegation token in KV
@@ -2831,7 +2953,7 @@ export class ConsentService {
2831
2953
  (await this.getUserDidForSession(approvalRequest.session_id, approvalRequest.oauth_identity || undefined)) ?? undefined; // Phase 5: Convert null to undefined
2832
2954
  }
2833
2955
  catch (error) {
2834
- console.warn("[ConsentService] Failed to get userDid for audit logging:", error);
2956
+ logger.warn("[ConsentService] Failed to get userDid for audit logging:", error);
2835
2957
  // Continue without userDid - audit events can still be logged
2836
2958
  }
2837
2959
  }
@@ -2862,7 +2984,7 @@ export class ConsentService {
2862
2984
  });
2863
2985
  }
2864
2986
  catch (error) {
2865
- console.error("[ConsentService] Audit failed but continuing", {
2987
+ logger.debug("[ConsentService] Audit failed but continuing", {
2866
2988
  sessionId: approvalRequest.session_id,
2867
2989
  error: error instanceof Error ? error.message : String(error),
2868
2990
  eventTypes: ["consent:approved", "consent:delegation_created"],
@@ -2881,7 +3003,7 @@ export class ConsentService {
2881
3003
  });
2882
3004
  }
2883
3005
  catch (error) {
2884
- console.error("[ConsentService] Error handling approval:", error);
3006
+ logger.error("[ConsentService] Error handling approval:", error);
2885
3007
  return new Response(JSON.stringify({
2886
3008
  success: false,
2887
3009
  error: "Internal server error",
@@ -2902,7 +3024,7 @@ export class ConsentService {
2902
3024
  const agentShieldUrl = this.env.AGENTSHIELD_API_URL || DEFAULT_AGENTSHIELD_URL;
2903
3025
  const apiKey = this.env.AGENTSHIELD_API_KEY;
2904
3026
  if (!apiKey) {
2905
- console.warn("[ConsentService] No API key configured, cannot create delegation");
3027
+ logger.warn("[ConsentService] No API key configured, cannot create delegation");
2906
3028
  return {
2907
3029
  success: false,
2908
3030
  error: "API key not configured",
@@ -2920,7 +3042,7 @@ export class ConsentService {
2920
3042
  // Only fetch from storage if not already provided in request
2921
3043
  if (!userDid && request.session_id) {
2922
3044
  try {
2923
- console.error("[ConsentService] Getting User DID for session:", {
3045
+ logger.debug("[ConsentService] Getting User DID for session:", {
2924
3046
  sessionId: request.session_id.substring(0, 20) + "...",
2925
3047
  hasOAuthIdentity: !!request.oauth_identity,
2926
3048
  oauthProvider: request.oauth_identity?.provider,
@@ -2932,27 +3054,27 @@ export class ConsentService {
2932
3054
  userDid =
2933
3055
  (await this.getUserDidForSession(request.session_id, request.oauth_identity || undefined // Explicitly handle null as undefined
2934
3056
  )) ?? undefined;
2935
- console.error("[ConsentService] User DID retrieved from storage:", {
3057
+ logger.debug("[ConsentService] User DID retrieved from storage:", {
2936
3058
  userDid: userDid?.substring(0, 20) + "...",
2937
3059
  hasUserDid: !!userDid,
2938
3060
  });
2939
3061
  }
2940
3062
  catch (error) {
2941
- console.error("[ConsentService] Failed to get/generate userDid:", error);
3063
+ logger.debug("[ConsentService] Failed to get/generate userDid:", error);
2942
3064
  // Continue without userDid - delegation will work without user_identifier
2943
3065
  // This is valid for non-OAuth scenarios, but we should log this as a warning
2944
- console.warn("[ConsentService] Delegation will be created without user_identifier - this may affect user tracking");
3066
+ logger.warn("[ConsentService] Delegation will be created without user_identifier - this may affect user tracking");
2945
3067
  }
2946
3068
  }
2947
3069
  else if (userDid) {
2948
3070
  // userDid was provided in request (e.g., from credential auth flow)
2949
- console.error("[ConsentService] Using provided user_did from request:", {
3071
+ logger.debug("[ConsentService] Using provided user_did from request:", {
2950
3072
  userDid: userDid.substring(0, 20) + "...",
2951
3073
  source: "request.user_did",
2952
3074
  });
2953
3075
  }
2954
3076
  else {
2955
- console.error("[ConsentService] No session_id provided - skipping User DID generation");
3077
+ logger.debug("[ConsentService] No session_id provided - skipping User DID generation");
2956
3078
  }
2957
3079
  const expiresInDays = 7; // Default to 7 days
2958
3080
  // Phase 2 VC-Only: Issue Delegation VC if we have a session and userDid
@@ -2983,21 +3105,21 @@ export class ConsentService {
2983
3105
  const vcResult = await this.issueDelegationVC(localDelegation, request.session_id, request.oauth_identity || undefined);
2984
3106
  credentialJwt = vcResult ?? undefined;
2985
3107
  if (credentialJwt) {
2986
- console.error("[ConsentService] VC issued for delegation:", {
3108
+ logger.debug("[ConsentService] VC issued for delegation:", {
2987
3109
  delegationId,
2988
3110
  jwtLength: credentialJwt.length,
2989
3111
  });
2990
3112
  }
2991
3113
  }
2992
3114
  catch (error) {
2993
- console.warn("[ConsentService] Failed to issue VC, continuing without it:", error);
3115
+ logger.warn("[ConsentService] Failed to issue VC, continuing without it:", error);
2994
3116
  // Non-fatal - delegation will work without VC
2995
3117
  }
2996
3118
  }
2997
3119
  // Build delegation request with error-based format detection
2998
3120
  // Try full format first, fallback to simplified format on error
2999
3121
  const delegationRequest = await this.buildDelegationRequest(request, userDid, expiresInDays, fieldName, credentialJwt);
3000
- console.error("[ConsentService] Creating delegation:", {
3122
+ logger.debug("[ConsentService] Creating delegation:", {
3001
3123
  url: `${agentShieldUrl}${AGENTSHIELD_ENDPOINTS.DELEGATIONS_CREATE}`,
3002
3124
  agentDid: request.agent_did.substring(0, 20) + "...",
3003
3125
  scopes: request.scopes,
@@ -3028,7 +3150,7 @@ export class ConsentService {
3028
3150
  // AgentShield now returns delegation_token for stateless verification
3029
3151
  const responseDataObj = wrappedResponse.data;
3030
3152
  const delegationToken = responseDataObj.delegation_token;
3031
- console.error("[ConsentService] ✅ Delegation created successfully:", {
3153
+ logger.info("[ConsentService] ✅ Delegation created successfully:", {
3032
3154
  delegationId,
3033
3155
  agentDid: wrappedResponse.data.agent_did.substring(0, 20) + "...",
3034
3156
  scopes: wrappedResponse.data.scopes,
@@ -3051,7 +3173,7 @@ export class ConsentService {
3051
3173
  // Extract delegation_token (JWT) if present in response
3052
3174
  const unwrappedDataObj = unwrappedResponse;
3053
3175
  const delegationToken = unwrappedDataObj.delegation_token;
3054
- console.error("[ConsentService] ✅ Delegation created successfully:", {
3176
+ logger.info("[ConsentService] ✅ Delegation created successfully:", {
3055
3177
  delegationId,
3056
3178
  agentDid: unwrappedResponse.agent_did.substring(0, 20) + "...",
3057
3179
  scopes: unwrappedResponse.scopes,
@@ -3074,7 +3196,7 @@ export class ConsentService {
3074
3196
  data?.id ||
3075
3197
  delegationObj?.id;
3076
3198
  if (!delegationId) {
3077
- console.error("[ConsentService] Invalid response format - missing delegation_id:", responseData);
3199
+ logger.debug("[ConsentService] Invalid response format - missing delegation_id:", responseData);
3078
3200
  return {
3079
3201
  success: false,
3080
3202
  error: "Invalid API response format - missing delegation_id",
@@ -3084,7 +3206,7 @@ export class ConsentService {
3084
3206
  // Extract delegation_token from fallback parsing
3085
3207
  const delegationToken = data?.delegation_token ||
3086
3208
  delegationObj?.delegation_token;
3087
- console.warn("[ConsentService] ⚠️ Response format not fully validated, using fallback parsing:", {
3209
+ logger.warn("[ConsentService] ⚠️ Response format not fully validated, using fallback parsing:", {
3088
3210
  delegationId,
3089
3211
  hasDelegationToken: !!delegationToken,
3090
3212
  tokenLength: delegationToken?.length,
@@ -3097,7 +3219,7 @@ export class ConsentService {
3097
3219
  };
3098
3220
  }
3099
3221
  catch (error) {
3100
- console.error("[ConsentService] Error creating delegation:", error);
3222
+ logger.error("[ConsentService] Error creating delegation:", error);
3101
3223
  return {
3102
3224
  success: false,
3103
3225
  error: error instanceof Error ? error.message : "Unknown error",
@@ -3118,7 +3240,7 @@ export class ConsentService {
3118
3240
  async storeDelegationToken(sessionId, agentDid, token, delegationId) {
3119
3241
  const delegationStorage = this.env.DELEGATION_STORAGE;
3120
3242
  if (!delegationStorage) {
3121
- console.warn("[ConsentService] No delegation storage configured, token not stored");
3243
+ logger.warn("[ConsentService] No delegation storage configured, token not stored");
3122
3244
  return;
3123
3245
  }
3124
3246
  try {
@@ -3137,7 +3259,7 @@ export class ConsentService {
3137
3259
  await delegationStorage.put(userAgentKey, token, {
3138
3260
  expirationTtl: ttl,
3139
3261
  });
3140
- console.error("[ConsentService] ✅ Token stored with user+agent DID:", {
3262
+ logger.info("[ConsentService] ✅ Token stored with user+agent DID:", {
3141
3263
  key: userAgentKey,
3142
3264
  ttl,
3143
3265
  delegationId,
@@ -3162,7 +3284,7 @@ export class ConsentService {
3162
3284
  await delegationStorage.put(sessionKey, JSON.stringify(sessionDataToStore), {
3163
3285
  expirationTtl: ttl, // Use full TTL - this is the primary storage for session
3164
3286
  });
3165
- console.error("[ConsentService] ✅ Token stored for session:", {
3287
+ logger.info("[ConsentService] ✅ Token stored for session:", {
3166
3288
  key: sessionKey,
3167
3289
  ttl,
3168
3290
  sessionId: sessionId.substring(0, 20) + "...",
@@ -3170,7 +3292,7 @@ export class ConsentService {
3170
3292
  preservedIdentityState: sessionData?.identityState || "none",
3171
3293
  });
3172
3294
  // Metrics: Log delegation key type for monitoring
3173
- console.error("[ConsentService] 📊 Delegation storage metrics:", {
3295
+ logger.debug("[ConsentService] 📊 Delegation storage metrics:", {
3174
3296
  delegationKeyType: userDid ? "user_agent_scoped" : "session_scoped",
3175
3297
  hasUserDid: !!userDid,
3176
3298
  userDidPrefix: userDid
@@ -3186,7 +3308,7 @@ export class ConsentService {
3186
3308
  }
3187
3309
  catch (error) {
3188
3310
  // Storage errors are non-fatal - log but don't fail the request
3189
- console.error("[ConsentService] Storage error (non-fatal):", error);
3311
+ logger.debug("[ConsentService] Storage error (non-fatal):", error);
3190
3312
  }
3191
3313
  }
3192
3314
  /**
@@ -3208,7 +3330,7 @@ export class ConsentService {
3208
3330
  }
3209
3331
  catch (error) {
3210
3332
  // Ignore errors, use default (autoClose = false)
3211
- console.warn("[ConsentService] Failed to fetch config for autoClose:", error);
3333
+ logger.warn("[ConsentService] Failed to fetch config for autoClose:", error);
3212
3334
  }
3213
3335
  }
3214
3336
  const html = this.renderer.renderSuccess({
@@ -3285,9 +3407,24 @@ export class ConsentService {
3285
3407
  * @returns JSON response
3286
3408
  */
3287
3409
  async handleCredentialApproval(body) {
3288
- console.error("[ConsentService] Processing credential approval");
3410
+ logger.debug("[ConsentService] Processing credential approval");
3289
3411
  // Extract standard fields
3290
3412
  const { tool, scopes: rawScopes, agent_did, session_id, project_id, provider, provider_type, csrf_token, ...credentials } = body;
3413
+ // DEBUG: Log credentials to diagnose password encoding issues
3414
+ // SECURITY: Mask password, but show length and first/last char for debugging
3415
+ const pwd = credentials.password || "";
3416
+ logger.debug("[ConsentService] DEBUG: Credential values received", {
3417
+ hasUsername: !!credentials.username,
3418
+ usernameLength: (credentials.username || "").length,
3419
+ usernameValue: credentials.username, // Safe to log email
3420
+ hasPassword: !!credentials.password,
3421
+ passwordLength: pwd.length,
3422
+ passwordFirstChar: pwd.length > 0 ? pwd[0] : "",
3423
+ passwordLastChar: pwd.length > 0 ? pwd[pwd.length - 1] : "",
3424
+ // Check for special chars that might be escaped
3425
+ passwordContainsDollar: pwd.includes("$"),
3426
+ passwordContainsDoubleD: pwd.includes("$$"),
3427
+ });
3291
3428
  // Parse scopes - handles double JSON encoding from form submission
3292
3429
  // The form stores scopes as JSON string, then JS submits it as JSON again
3293
3430
  const scopes = this.parseScopes(rawScopes);
@@ -3308,7 +3445,7 @@ export class ConsentService {
3308
3445
  }
3309
3446
  // Validate CSRF token
3310
3447
  if (!csrf_token || typeof csrf_token !== "string") {
3311
- console.warn("[ConsentService] Missing or invalid CSRF token");
3448
+ logger.warn("[ConsentService] Missing or invalid CSRF token");
3312
3449
  return new Response(JSON.stringify({
3313
3450
  success: false,
3314
3451
  error: "Invalid or missing CSRF token",
@@ -3318,7 +3455,7 @@ export class ConsentService {
3318
3455
  // Validate CSRF token against stored value
3319
3456
  const csrfValid = await this.validateCredentialCsrfToken(csrf_token, session_id);
3320
3457
  if (!csrfValid) {
3321
- console.warn("[ConsentService] CSRF token validation failed", {
3458
+ logger.warn("[ConsentService] CSRF token validation failed", {
3322
3459
  sessionId: session_id.substring(0, 20) + "...",
3323
3460
  });
3324
3461
  return new Response(JSON.stringify({
@@ -3331,7 +3468,7 @@ export class ConsentService {
3331
3468
  // 1. Fetch credential provider config from AgentShield
3332
3469
  const providerConfig = await this.getCredentialProviderConfig(project_id, provider);
3333
3470
  if (!providerConfig) {
3334
- console.error("[ConsentService] Credential provider config not found", {
3471
+ logger.debug("[ConsentService] Credential provider config not found", {
3335
3472
  projectId: project_id,
3336
3473
  provider,
3337
3474
  });
@@ -3347,20 +3484,55 @@ export class ConsentService {
3347
3484
  // See: https://developers.cloudflare.com/workers/observability/errors/#illegal-invocation-errors
3348
3485
  const credentialHandler = createCredentialAuthHandler({
3349
3486
  fetch: (...args) => globalThis.fetch(...args),
3350
- logger: (msg, data) => console.error(msg, data),
3487
+ logger: (msg, data) => logger.debug(msg, data),
3351
3488
  });
3352
3489
  const authResult = await credentialHandler.authenticate(providerConfig, credentials);
3353
3490
  if (!authResult.success) {
3354
- console.error("[ConsentService] Credential authentication failed", {
3491
+ logger.error("[ConsentService] Credential authentication failed", {
3355
3492
  error: authResult.error,
3356
3493
  });
3494
+ // Log credential auth failure for audit trail
3495
+ const auditService = await this.getAuditService(project_id);
3496
+ if (auditService) {
3497
+ await auditService
3498
+ .logCredentialAuthFailed({
3499
+ sessionId: session_id,
3500
+ agentDid: agent_did,
3501
+ targetTools: [tool],
3502
+ scopes: scopes,
3503
+ projectId: project_id,
3504
+ provider: provider,
3505
+ errorMessage: authResult.error,
3506
+ })
3507
+ .catch((err) => {
3508
+ logger.warn("[ConsentService] Failed to log credential auth failure:", err);
3509
+ });
3510
+ }
3357
3511
  return new Response(JSON.stringify({
3358
3512
  success: false,
3359
3513
  error: authResult.error || "Authentication failed",
3360
3514
  error_code: "auth_failed",
3361
3515
  }), { status: 401, headers: { "Content-Type": "application/json" } });
3362
3516
  }
3363
- console.error("[ConsentService] ✅ Credential authentication successful");
3517
+ logger.info("[ConsentService] ✅ Credential authentication successful");
3518
+ // Log credential auth success for audit trail
3519
+ // Note: userDid will be resolved after identity resolution, so we don't include it here
3520
+ const auditService = await this.getAuditService(project_id);
3521
+ if (auditService) {
3522
+ await auditService
3523
+ .logCredentialAuthSuccess({
3524
+ sessionId: session_id,
3525
+ agentDid: agent_did,
3526
+ targetTools: [tool],
3527
+ scopes: scopes,
3528
+ projectId: project_id,
3529
+ provider: provider,
3530
+ // userDid will be available after identity resolution
3531
+ })
3532
+ .catch((err) => {
3533
+ logger.warn("[ConsentService] Failed to log credential auth success:", err);
3534
+ });
3535
+ }
3364
3536
  // 3. Resolve identity via AgentShield
3365
3537
  const identityResult = await this.resolveCredentialIdentity({
3366
3538
  projectId: project_id,
@@ -3376,7 +3548,7 @@ export class ConsentService {
3376
3548
  error_code: "identity_resolution_failed",
3377
3549
  }), { status: 500, headers: { "Content-Type": "application/json" } });
3378
3550
  }
3379
- console.error("[ConsentService] ✅ Identity resolved", {
3551
+ logger.info("[ConsentService] ✅ Identity resolved", {
3380
3552
  userDid: identityResult.userDid.substring(0, 30) + "...",
3381
3553
  });
3382
3554
  // NEW: Update session cache with userDid for proper delegation scoping
@@ -3384,7 +3556,7 @@ export class ConsentService {
3384
3556
  // instead of falling back to legacy agent-only keys
3385
3557
  await this.updateSessionWithIdentity(session_id, identityResult.userDid, null // No OAuth identity for credential auth
3386
3558
  );
3387
- console.error("[ConsentService] ✅ Session updated with identity");
3559
+ logger.info("[ConsentService] ✅ Session updated with identity");
3388
3560
  // 4. Store token in IdpTokenStorage with usage metadata
3389
3561
  // Include userId from authResult for ToolExecutionContext.userId
3390
3562
  await this.storeCredentialToken({
@@ -3396,48 +3568,59 @@ export class ConsentService {
3396
3568
  scopes,
3397
3569
  userId: authResult.userId, // Pass extracted userId from credential provider response
3398
3570
  });
3399
- console.error("[ConsentService] ✅ Token stored");
3400
- // 5. Create delegation using standard flow
3401
- // Include provider_type and provider in customFields for AgentShield dashboard display
3402
- const approvalRequest = {
3403
- tool: tool,
3404
- scopes,
3405
- agent_did: agent_did,
3406
- session_id: session_id,
3407
- project_id: project_id,
3408
- auth_mode: "credentials",
3409
- provider_type: CONSENT_PROVIDER_TYPES.CREDENTIAL,
3410
- termsAccepted: true,
3411
- user_did: identityResult.userDid,
3412
- customFields: {
3413
- provider: provider,
3414
- },
3415
- };
3416
- const delegationResult = await this.createDelegation(approvalRequest);
3417
- if (!delegationResult.success) {
3418
- return new Response(JSON.stringify({
3419
- success: false,
3420
- error: delegationResult.error || "Delegation creation failed",
3421
- error_code: delegationResult.error_code || "delegation_failed",
3422
- }), { status: 500, headers: { "Content-Type": "application/json" } });
3571
+ logger.info("[ConsentService] ✅ Token stored");
3572
+ // ================================================================================
3573
+ // 5. REDIRECT TO CLICKWRAP PAGE (3-screen flow)
3574
+ // ================================================================================
3575
+ // Flow: Credential Auth → Clickwrap (consent-only UI) → Success
3576
+ //
3577
+ // Instead of creating the delegation here, redirect to the clickwrap page
3578
+ // where the user can see their identity and approve the permission request.
3579
+ // The clickwrap approval will then create the delegation with the stored
3580
+ // credential auth info.
3581
+ //
3582
+ // This matches the OAuth flow pattern for consistency.
3583
+ // ================================================================================
3584
+ const serverUrl = this.env.MCP_SERVER_URL || "";
3585
+ // Build clickwrap URL with all necessary parameters
3586
+ const clickwrapUrl = new URL(`${serverUrl}/consent`);
3587
+ // Mode is consent-only since credential auth is complete
3588
+ clickwrapUrl.searchParams.set("mode", "consent-only");
3589
+ // CRITICAL: Pass provider_type so delegation is created with 'password' not 'none'
3590
+ // This ensures authorization.type matches tool protection expectation
3591
+ clickwrapUrl.searchParams.set("credential_provider_type", CONSENT_PROVIDER_TYPES.PASSWORD);
3592
+ clickwrapUrl.searchParams.set("credential_provider", provider);
3593
+ // Preserve important state from credential flow
3594
+ clickwrapUrl.searchParams.set("project_id", project_id);
3595
+ clickwrapUrl.searchParams.set("agent_did", agent_did);
3596
+ clickwrapUrl.searchParams.set("session_id", session_id);
3597
+ // Include tool and scopes for display
3598
+ clickwrapUrl.searchParams.set("tool", tool);
3599
+ if (Array.isArray(scopes) && scopes.length > 0) {
3600
+ clickwrapUrl.searchParams.set("scopes", scopes.join(","));
3423
3601
  }
3424
- console.error("[ConsentService] Credential approval complete", {
3425
- delegationId: delegationResult.delegation_id?.substring(0, 20) + "...",
3602
+ // Include user info for display on clickwrap page
3603
+ if (authResult.userEmail) {
3604
+ clickwrapUrl.searchParams.set("credential_user_email", authResult.userEmail);
3605
+ }
3606
+ if (authResult.userId) {
3607
+ clickwrapUrl.searchParams.set("credential_user_id", authResult.userId);
3608
+ }
3609
+ logger.debug("[ConsentService] ✅ Credential auth complete, redirecting to clickwrap", {
3610
+ sessionId: session_id.substring(0, 20) + "...",
3611
+ userDid: identityResult.userDid.substring(0, 30) + "...",
3612
+ provider: provider,
3613
+ clickwrapUrl: clickwrapUrl.toString().substring(0, 100) + "...",
3426
3614
  });
3427
- // Store delegation token
3428
- await this.storeDelegationToken(session_id, agent_did, delegationResult.delegation_token, delegationResult.delegation_id);
3429
- // Return success with redirect URL
3430
- const serverUrl = this.env.MCP_SERVER_URL || "";
3431
- const redirectUrl = `${serverUrl}/consent/success?delegation_id=${encodeURIComponent(delegationResult.delegation_id)}&project_id=${encodeURIComponent(project_id)}`;
3615
+ // Return success with redirect to clickwrap page
3432
3616
  return new Response(JSON.stringify({
3433
3617
  success: true,
3434
- delegation_id: delegationResult.delegation_id,
3435
- delegation_token: delegationResult.delegation_token,
3436
- redirectUrl,
3618
+ redirectUrl: clickwrapUrl.toString(),
3619
+ // Note: delegation_id is NOT returned here - it will be created on clickwrap approval
3437
3620
  }), { status: 200, headers: { "Content-Type": "application/json" } });
3438
3621
  }
3439
3622
  catch (error) {
3440
- console.error("[ConsentService] Credential approval error:", error);
3623
+ logger.error("[ConsentService] Credential approval error:", error);
3441
3624
  return new Response(JSON.stringify({
3442
3625
  success: false,
3443
3626
  error: error instanceof Error ? error.message : "Internal error",
@@ -3469,7 +3652,7 @@ export class ConsentService {
3469
3652
  }
3470
3653
  }
3471
3654
  catch {
3472
- console.warn("[ConsentService] Failed to parse scopes JSON:", rawScopes);
3655
+ logger.warn("[ConsentService] Failed to parse scopes JSON:", rawScopes);
3473
3656
  }
3474
3657
  }
3475
3658
  // Single string scope - wrap in array
@@ -3491,7 +3674,7 @@ export class ConsentService {
3491
3674
  const agentShieldUrl = this.env.AGENTSHIELD_API_URL || DEFAULT_AGENTSHIELD_URL;
3492
3675
  const apiKey = this.env.AGENTSHIELD_API_KEY;
3493
3676
  if (!apiKey) {
3494
- console.warn("[ConsentService] No AgentShield API key configured");
3677
+ logger.warn("[ConsentService] No AgentShield API key configured");
3495
3678
  return null;
3496
3679
  }
3497
3680
  try {
@@ -3505,7 +3688,7 @@ export class ConsentService {
3505
3688
  },
3506
3689
  });
3507
3690
  if (!response.ok) {
3508
- console.warn("[ConsentService] Providers API returned error:", {
3691
+ logger.warn("[ConsentService] Providers API returned error:", {
3509
3692
  status: response.status,
3510
3693
  statusText: response.statusText,
3511
3694
  });
@@ -3515,7 +3698,7 @@ export class ConsentService {
3515
3698
  // { success: true, data: { providers: { ... }, configuredProvider: "..." } }
3516
3699
  const result = (await response.json());
3517
3700
  if (!result.success || !result.data?.providers) {
3518
- console.warn("[ConsentService] Invalid providers response:", {
3701
+ logger.warn("[ConsentService] Invalid providers response:", {
3519
3702
  hasSuccess: result.success,
3520
3703
  hasData: !!result.data,
3521
3704
  hasProviders: !!result.data?.providers,
@@ -3530,13 +3713,13 @@ export class ConsentService {
3530
3713
  // AgentShield API may return snake_case fields from database
3531
3714
  const provider = this.mapCredentialProviderFields(rawProvider, providerName);
3532
3715
  if (!provider) {
3533
- console.error("[ConsentService] Credential provider validation failed:", {
3716
+ logger.debug("[ConsentService] Credential provider validation failed:", {
3534
3717
  projectId,
3535
3718
  providerName,
3536
3719
  });
3537
3720
  return null;
3538
3721
  }
3539
- console.error("[ConsentService] Found credential provider:", {
3722
+ logger.debug("[ConsentService] Found credential provider:", {
3540
3723
  providerName,
3541
3724
  hasAuthEndpoint: !!provider.authEndpoint,
3542
3725
  hasResponseFields: !!provider.responseFields,
@@ -3547,7 +3730,7 @@ export class ConsentService {
3547
3730
  return null;
3548
3731
  }
3549
3732
  catch (error) {
3550
- console.error("[ConsentService] Failed to fetch provider config:", error);
3733
+ logger.error("[ConsentService] Failed to fetch provider config:", error);
3551
3734
  return null;
3552
3735
  }
3553
3736
  }
@@ -3619,7 +3802,7 @@ export class ConsentService {
3619
3802
  raw.auth_endpoint ??
3620
3803
  "");
3621
3804
  if (!authEndpoint) {
3622
- console.error("[ConsentService] Credential provider missing required authEndpoint", { providerName: providerName ?? "unknown" });
3805
+ logger.debug("[ConsentService] Credential provider missing required authEndpoint", { providerName: providerName ?? "unknown" });
3623
3806
  return null;
3624
3807
  }
3625
3808
  return {
@@ -3646,7 +3829,7 @@ export class ConsentService {
3646
3829
  const agentShieldUrl = this.env.AGENTSHIELD_API_URL || DEFAULT_AGENTSHIELD_URL;
3647
3830
  const apiKey = this.env.AGENTSHIELD_API_KEY;
3648
3831
  if (!apiKey) {
3649
- console.warn("[ConsentService] No AgentShield API key for identity resolution");
3832
+ logger.warn("[ConsentService] No AgentShield API key for identity resolution");
3650
3833
  return { success: false };
3651
3834
  }
3652
3835
  try {
@@ -3676,7 +3859,7 @@ export class ConsentService {
3676
3859
  };
3677
3860
  }
3678
3861
  catch (error) {
3679
- console.error("[ConsentService] Identity resolution failed:", error);
3862
+ logger.error("[ConsentService] Identity resolution failed:", error);
3680
3863
  return { success: false };
3681
3864
  }
3682
3865
  }
@@ -3686,7 +3869,7 @@ export class ConsentService {
3686
3869
  async storeCredentialToken(params) {
3687
3870
  const delegationStorage = this.env.DELEGATION_STORAGE;
3688
3871
  if (!delegationStorage) {
3689
- console.warn("[ConsentService] No DELEGATION_STORAGE for credential tokens");
3872
+ logger.warn("[ConsentService] No DELEGATION_STORAGE for credential tokens");
3690
3873
  return;
3691
3874
  }
3692
3875
  const oauthSecurityService = new OAuthSecurityService(delegationStorage, this.env.OAUTH_ENCRYPTION_SECRET);
@@ -3724,7 +3907,7 @@ export class ConsentService {
3724
3907
  async validateCredentialCsrfToken(token, sessionId) {
3725
3908
  const delegationStorage = this.env.DELEGATION_STORAGE;
3726
3909
  if (!delegationStorage) {
3727
- console.warn("[ConsentService] No DELEGATION_STORAGE for CSRF validation, skipping");
3910
+ logger.warn("[ConsentService] No DELEGATION_STORAGE for CSRF validation, skipping");
3728
3911
  // Return true to allow flow to continue (graceful degradation)
3729
3912
  // This matches OAuth behavior when storage is unavailable
3730
3913
  return true;
@@ -3733,7 +3916,7 @@ export class ConsentService {
3733
3916
  const csrfKey = STORAGE_KEYS.credentialCsrf(sessionId);
3734
3917
  const storedToken = await delegationStorage.get(csrfKey);
3735
3918
  if (!storedToken) {
3736
- console.warn("[ConsentService] No stored CSRF token found");
3919
+ logger.warn("[ConsentService] No stored CSRF token found");
3737
3920
  return false;
3738
3921
  }
3739
3922
  // Constant-time comparison to prevent timing attacks
@@ -3745,7 +3928,7 @@ export class ConsentService {
3745
3928
  return isValid;
3746
3929
  }
3747
3930
  catch (error) {
3748
- console.error("[ConsentService] CSRF validation error:", error);
3931
+ logger.error("[ConsentService] CSRF validation error:", error);
3749
3932
  return false;
3750
3933
  }
3751
3934
  }
@@ -3766,7 +3949,7 @@ export class ConsentService {
3766
3949
  .replace(/\//g, "_")
3767
3950
  .replace(/=/g, "");
3768
3951
  if (!delegationStorage) {
3769
- console.warn("[ConsentService] No DELEGATION_STORAGE for CSRF storage");
3952
+ logger.warn("[ConsentService] No DELEGATION_STORAGE for CSRF storage");
3770
3953
  // Return token anyway - form will submit but validation will skip
3771
3954
  return token;
3772
3955
  }
@@ -3774,10 +3957,10 @@ export class ConsentService {
3774
3957
  const csrfKey = STORAGE_KEYS.credentialCsrf(sessionId);
3775
3958
  // 10 minute TTL matches OAuth state TTL
3776
3959
  await delegationStorage.put(csrfKey, token, { expirationTtl: 600 });
3777
- console.error("[ConsentService] CSRF token stored for credential form");
3960
+ logger.debug("[ConsentService] CSRF token stored for credential form");
3778
3961
  }
3779
3962
  catch (error) {
3780
- console.error("[ConsentService] CSRF token storage error:", error);
3963
+ logger.error("[ConsentService] CSRF token storage error:", error);
3781
3964
  }
3782
3965
  return token;
3783
3966
  }
@@ -3864,26 +4047,40 @@ export class ConsentService {
3864
4047
  // user_identifier can be the same as user_did or a human-readable version
3865
4048
  // If we have a human-readable identifier from OAuth, use it; otherwise use DID
3866
4049
  simplifiedRequest.user_identifier = userDid;
3867
- console.error("[ConsentService] Including user_did in delegation request:", {
4050
+ logger.debug("[ConsentService] Including user_did in delegation request:", {
3868
4051
  user_did: userDid.substring(0, 20) + "...",
3869
4052
  });
3870
4053
  }
3871
4054
  else {
3872
- console.error("[ConsentService] No user_did (session is anonymous) - delegation will proceed without it");
4055
+ logger.debug("[ConsentService] No user_did (session is anonymous) - delegation will proceed without it");
3873
4056
  }
3874
4057
  // Phase 2 VC-Only: Include credential_jwt if available
3875
4058
  if (credentialJwt) {
3876
4059
  simplifiedRequest.credential_jwt = credentialJwt;
3877
- console.error("[ConsentService] Including credential_jwt in delegation request");
4060
+ logger.debug("[ConsentService] Including credential_jwt in delegation request");
3878
4061
  }
3879
4062
  // AgentShield API only accepts "custom_fields", not "metadata"
3880
4063
  // Always use "custom_fields" regardless of Day0 config
3881
4064
  // Include provider_type and provider for dashboard authorization display
4065
+ //
4066
+ // CRITICAL FIX: request.provider_type is at the TOP LEVEL of ConsentApprovalRequest,
4067
+ // NOT inside customFields. We need to read from both locations:
4068
+ // - request.provider_type (set by handleCredentialApproval, handleApproval, etc.)
4069
+ // - customFieldsFromRequest.provider (set in customFields for backward compat)
3882
4070
  const customFieldsFromRequest = request.customFields || {};
3883
- const hasProviderInfo = customFieldsFromRequest.provider_type || customFieldsFromRequest.provider;
4071
+ // FIX: Read provider_type from request root (where handleCredentialApproval sets it)
4072
+ // Fall back to customFields for backward compatibility
4073
+ const providerType = request.provider_type || customFieldsFromRequest.provider_type;
4074
+ const provider = customFieldsFromRequest.provider;
4075
+ const hasProviderInfo = providerType || provider;
3884
4076
  if (userDid || hasProviderInfo) {
3885
4077
  // Include issuer_did and subject_did in custom_fields when we have userDid
3886
4078
  // Also include provider_type and provider for AgentShield dashboard
4079
+ // CRITICAL: AgentShield derives authorization from metadata.provider_type:
4080
+ // - provider_type === 'password' → authorization.type = 'password' (credential auth)
4081
+ // - provider_type === 'none' → authorization.type = 'none' (consent-only)
4082
+ // - oauth_provider present → authorization.type = 'oauth'
4083
+ // NOTE: Tool protection expects 'password' for credential flows, NOT 'credential'
3887
4084
  simplifiedRequest.custom_fields = {
3888
4085
  ...(userDid
3889
4086
  ? {
@@ -3892,13 +4089,18 @@ export class ConsentService {
3892
4089
  }
3893
4090
  : {}),
3894
4091
  format_version: "simplified_v1",
3895
- // Merge with any existing custom_fields from request (includes provider_type, provider)
4092
+ // Include provider_type at the custom_fields level (where AgentShield reads it)
4093
+ ...(providerType ? { provider_type: providerType } : {}),
4094
+ // Merge with any existing custom_fields from request
3896
4095
  ...customFieldsFromRequest,
3897
4096
  };
3898
4097
  if (hasProviderInfo) {
3899
- console.error("[ConsentService] Including provider info in custom_fields:", {
3900
- provider_type: customFieldsFromRequest.provider_type,
3901
- provider: customFieldsFromRequest.provider,
4098
+ logger.debug("[ConsentService] Including provider info in custom_fields:", {
4099
+ provider_type: providerType,
4100
+ provider: provider,
4101
+ source: request.provider_type
4102
+ ? "request.provider_type"
4103
+ : "customFields",
3902
4104
  });
3903
4105
  }
3904
4106
  }
@@ -3929,7 +4131,7 @@ export class ConsentService {
3929
4131
  return fullResponse;
3930
4132
  }
3931
4133
  // Full format failed with validation error, try simplified
3932
- console.error("[ConsentService] Full format failed, trying simplified format...");
4134
+ logger.debug("[ConsentService] Full format failed, trying simplified format...");
3933
4135
  const simplifiedResponse = await this.makeAPICall(agentShieldUrl, apiKey, request.simplifiedFormat);
3934
4136
  if (simplifiedResponse.success) {
3935
4137
  await this.cacheFormatPreference("simplified");
@@ -3951,11 +4153,11 @@ export class ConsentService {
3951
4153
  // This provides defense-in-depth protection
3952
4154
  const sanitizedBody = { ...requestBody };
3953
4155
  if ("session_id" in sanitizedBody) {
3954
- console.warn("[ConsentService] ⚠️ session_id detected in request body - removing (not in schema)");
4156
+ logger.warn("[ConsentService] ⚠️ session_id detected in request body - removing (not in schema)");
3955
4157
  delete sanitizedBody.session_id;
3956
4158
  }
3957
4159
  if ("project_id" in sanitizedBody) {
3958
- console.warn("[ConsentService] ⚠️ project_id detected in request body - removing (not in schema)");
4160
+ logger.warn("[ConsentService] ⚠️ project_id detected in request body - removing (not in schema)");
3959
4161
  delete sanitizedBody.project_id;
3960
4162
  }
3961
4163
  const response = await fetch(`${agentShieldUrl}${AGENTSHIELD_ENDPOINTS.DELEGATIONS_CREATE}`, {
@@ -4009,7 +4211,7 @@ export class ConsentService {
4009
4211
  };
4010
4212
  }
4011
4213
  catch (error) {
4012
- console.error("[ConsentService] API call failed:", error);
4214
+ logger.error("[ConsentService] API call failed:", error);
4013
4215
  return {
4014
4216
  success: false,
4015
4217
  error: error instanceof Error ? error.message : "Network request failed",
@@ -4031,10 +4233,10 @@ export class ConsentService {
4031
4233
  }), {
4032
4234
  expirationTtl: 3600, // 1 hour
4033
4235
  });
4034
- console.error(`[ConsentService] Cached format preference: ${format}`);
4236
+ logger.debug(`[ConsentService] Cached format preference: ${format}`);
4035
4237
  }
4036
4238
  catch (error) {
4037
- console.warn("[ConsentService] Failed to cache format preference:", error);
4239
+ logger.warn("[ConsentService] Failed to cache format preference:", error);
4038
4240
  }
4039
4241
  }
4040
4242
  }