@kya-os/mcp-i-cloudflare 1.7.24 → 1.7.25

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.
@@ -1690,16 +1690,23 @@ export class ConsentService {
1690
1690
  // 1. credentialProviderConfig must exist (already fetched above)
1691
1691
  // 2. Must NOT be in post-credential clickwrap mode (would cause infinite loop)
1692
1692
  if (credentialProviderConfig && !isPostCredentialClickwrap) {
1693
+ // Determine authorization type from tool protection config
1694
+ // Default to 'password' for credential flows (matches AgentShield expectations)
1695
+ // The authorization.type from tool protection tells us what type of auth the tool expects
1696
+ const authorizationType = protection?.authorization?.type ?? "password";
1693
1697
  logger.debug("[ConsentService] Credential provider detected, rendering credential page", {
1694
1698
  projectId,
1695
1699
  provider,
1696
1700
  providerType: credentialProviderConfig.type,
1697
1701
  displayName: credentialProviderConfig.displayName,
1702
+ authorizationType, // Log the authorization type being used
1698
1703
  });
1699
1704
  // Generate and store CSRF token for form security
1700
1705
  const csrfToken = await this.storeCredentialCsrfToken(sessionId);
1701
1706
  // Render credential login page instead of OAuth consent
1702
- const html = this.renderer.renderCredentialPage(pageConfig, credentialProviderConfig, provider, csrfToken);
1707
+ // Pass authorizationType from tool protection config for dynamic provider_type
1708
+ const html = this.renderer.renderCredentialPage(pageConfig, credentialProviderConfig, provider, csrfToken, authorizationType // Dynamic authorization type from tool protection
1709
+ );
1703
1710
  return new Response(html, {
1704
1711
  status: 200,
1705
1712
  headers: {
@@ -2879,23 +2886,33 @@ export class ConsentService {
2879
2886
  // Ensure userDid is in bodyObj for createDelegation and storeDelegationToken
2880
2887
  bodyObj.user_did = userDidFromRedirect;
2881
2888
  }
2882
- // Read credential_user_id from redirect URL params for UX metadata
2883
- // This is the human-readable identifier (email, username) from credential auth
2884
- const credentialUserIdFromRedirect = bodyObj.credential_user_id;
2885
- if (credentialUserIdFromRedirect) {
2886
- logger.debug("[ConsentService] Using credential_user_id from redirect:", {
2889
+ // Read user info from redirect URL params
2890
+ // Field mapping (clear naming):
2891
+ // credential_user_email user_identifier (human-readable for display)
2892
+ // credential_provider_user_id → user_id (provider's internal ID)
2893
+ const credentialUserEmailFromRedirect = bodyObj.credential_user_email;
2894
+ const credentialProviderUserIdFromRedirect = bodyObj.credential_provider_user_id;
2895
+ if (credentialUserEmailFromRedirect ||
2896
+ credentialProviderUserIdFromRedirect) {
2897
+ logger.debug("[ConsentService] ✅ Using credential user info from redirect:", {
2887
2898
  sessionId: sessionId?.substring(0, 20) + "...",
2888
- credential_user_id: credentialUserIdFromRedirect.substring(0, 20) + "...",
2899
+ credential_user_email: credentialUserEmailFromRedirect
2900
+ ? credentialUserEmailFromRedirect.substring(0, 20) + "..."
2901
+ : undefined,
2902
+ credential_provider_user_id: credentialProviderUserIdFromRedirect
2903
+ ? credentialProviderUserIdFromRedirect.substring(0, 20) +
2904
+ "..."
2905
+ : undefined,
2889
2906
  source: "redirect-param",
2890
2907
  });
2891
- // credential_user_id is already in bodyObj from form, no need to reassign
2892
2908
  }
2893
2909
  logger.debug("[ConsentService] ✅ Using credential auth provider_type for delegation:", {
2894
2910
  sessionId: sessionId?.substring(0, 20) + "...",
2895
2911
  providerType: CONSENT_PROVIDER_TYPES.PASSWORD,
2896
2912
  provider: credentialProvider,
2897
2913
  hasUserDid: !!userDidFromRedirect,
2898
- hasCredentialUserId: !!credentialUserIdFromRedirect,
2914
+ hasCredentialUserEmail: !!credentialUserEmailFromRedirect,
2915
+ hasProviderUserId: !!credentialProviderUserIdFromRedirect,
2899
2916
  note: "Delegation will have authorization.type='password' to match tool protection",
2900
2917
  });
2901
2918
  // The userDid is passed via redirect URL - no need to read from KV
@@ -3743,12 +3760,18 @@ export class ConsentService {
3743
3760
  if (Array.isArray(scopes) && scopes.length > 0) {
3744
3761
  clickwrapUrl.searchParams.set("scopes", scopes.join(","));
3745
3762
  }
3746
- // Include user info for display on clickwrap page
3763
+ // Include user info for delegation request
3764
+ // Field mapping (clear naming):
3765
+ // credential_user_email → user_identifier (human-readable for display)
3766
+ // credential_provider_user_id → user_id (provider's internal ID for business reference)
3767
+ // user_did → user_did (cryptographic identity, always present)
3747
3768
  if (authResult.userEmail) {
3769
+ // Email for human-readable display in AgentShield dashboard
3748
3770
  clickwrapUrl.searchParams.set("credential_user_email", authResult.userEmail);
3749
3771
  }
3750
3772
  if (authResult.userId) {
3751
- clickwrapUrl.searchParams.set("credential_user_id", authResult.userId);
3773
+ // Provider's internal ID (e.g., customer ID 696395) for business reference
3774
+ clickwrapUrl.searchParams.set("credential_provider_user_id", authResult.userId);
3752
3775
  }
3753
3776
  // CRITICAL FIX: Pass userDid through redirect to avoid KV eventual consistency issues
3754
3777
  // Without this, the clickwrap approval might read stale session data from KV
@@ -4158,30 +4181,98 @@ export class ConsentService {
4158
4181
  // CRITICAL: user_did is required for proper user identification in dashboard
4159
4182
  // user_identifier is for display purposes (email, username, etc.)
4160
4183
  // user_id is the provider-specific ID from credential auth (for UX metadata)
4184
+ //
4185
+ // Fallback Strategy:
4186
+ // 1. If email available → user_identifier = email (preferred)
4187
+ // 2. If no email → user_identifier = userDid (fallback so AgentShield has something to display)
4188
+ // AgentShield will also check metadata.user_email for extraction
4161
4189
  if (userDid) {
4162
4190
  // user_did is the primary identifier - the actual DID
4163
4191
  result.user_did = userDid;
4164
- // user_identifier: Use credential_user_id if available (human-readable),
4165
- // otherwise fall back to DID
4166
- result.user_identifier = request.credential_user_id || userDid;
4167
- // user_id: Include the credential provider's user ID for UX display in dashboard
4168
- // This is separate from user_did (cryptographic identity) and user_identifier
4169
- if (request.credential_user_id) {
4170
- result.user_id = request.credential_user_id;
4171
- logger.debug("[ConsentService] Full format: Including user_id from credential auth:", {
4172
- user_id: request.credential_user_id.substring(0, 20) + "...",
4192
+ // user_identifier: Human-readable identifier (email/username) for AgentShield dashboard display
4193
+ // user_id: Provider's internal ID (e.g., customer ID 696395) for business reference
4194
+ // user_did: Cryptographic DID for identity verification
4195
+ if (request.credential_user_email) {
4196
+ // Have email - use it as human-readable identifier
4197
+ result.user_identifier = request.credential_user_email;
4198
+ }
4199
+ else {
4200
+ // No email - fall back to DID so dashboard has something to display
4201
+ // AgentShield will detect this is a DID and may display differently
4202
+ result.user_identifier = userDid;
4203
+ }
4204
+ // user_id is the provider's internal ID (separate from email)
4205
+ // Use credential_provider_user_id if available
4206
+ const fullFormatProviderId = request.credential_provider_user_id;
4207
+ if (fullFormatProviderId) {
4208
+ result.user_id = fullFormatProviderId;
4209
+ logger.debug("[ConsentService] Full format: Including provider user_id from credential auth:", {
4210
+ user_id: fullFormatProviderId.substring(0, 20) + "...",
4211
+ user_identifier: request.credential_user_email?.substring(0, 20) + "...",
4173
4212
  });
4174
4213
  }
4175
4214
  logger.debug("[ConsentService] Full format: Including user identity fields:", {
4176
4215
  user_did: userDid.substring(0, 20) + "...",
4177
- user_identifier: result.user_identifier.substring(0, 20),
4178
- has_user_id: !!request.credential_user_id,
4216
+ user_identifier: request.credential_user_email
4217
+ ? request.credential_user_email.substring(0, 20) + "..."
4218
+ : "(fallback to DID)",
4219
+ has_user_id: !!fullFormatProviderId,
4220
+ source: request.credential_user_email ? "email" : "did-fallback",
4179
4221
  });
4180
4222
  }
4181
4223
  // Phase 2 VC-Only: Include credential_jwt if available
4182
4224
  if (credentialJwt) {
4183
4225
  result.credential_jwt = credentialJwt;
4184
4226
  }
4227
+ // MCP-I Compatibility: Include user_email and user_id in custom_fields (becomes metadata)
4228
+ // This matches buildSimplifiedFormatRequest behavior for consistency
4229
+ // AgentShield extracts these from metadata when user_identifier is not provided
4230
+ //
4231
+ // user_email = human-readable email (for display)
4232
+ // user_id = provider's internal ID (for business reference)
4233
+ const fullFormatUserEmail = request.credential_user_email || null;
4234
+ const fullFormatProviderUserId = request
4235
+ .credential_provider_user_id || null;
4236
+ const providerType = request.provider_type || "none";
4237
+ const customFieldsFromRequest = request.customFields || {};
4238
+ if (userDid || fullFormatUserEmail || providerType !== "none") {
4239
+ result.custom_fields = {
4240
+ ...(userDid
4241
+ ? {
4242
+ issuer_did: userDid,
4243
+ subject_did: request.agent_did,
4244
+ }
4245
+ : {}),
4246
+ format_version: "full_v1",
4247
+ ...(providerType ? { provider_type: providerType } : {}),
4248
+ // MCP-I Compatibility: Include user_email and user_id in metadata
4249
+ // AgentShield will extract these if user_identifier is not provided
4250
+ // user_email = human-readable email (for display)
4251
+ // user_id = provider's internal ID (for business reference, e.g., customer ID 696395)
4252
+ ...(fullFormatUserEmail ? { user_email: fullFormatUserEmail } : {}),
4253
+ ...(fullFormatProviderUserId
4254
+ ? { user_id: fullFormatProviderUserId }
4255
+ : {}),
4256
+ // Merge with any existing custom_fields from request
4257
+ ...customFieldsFromRequest,
4258
+ };
4259
+ if (fullFormatUserEmail || fullFormatProviderUserId) {
4260
+ logger.debug("[ConsentService] Full format: Including user info in custom_fields for AgentShield compatibility:", {
4261
+ user_email: fullFormatUserEmail
4262
+ ? fullFormatUserEmail.substring(0, 20) + "..."
4263
+ : undefined,
4264
+ user_id: fullFormatProviderUserId
4265
+ ? fullFormatProviderUserId.substring(0, 20) + "..."
4266
+ : undefined,
4267
+ });
4268
+ }
4269
+ }
4270
+ else if (request.customFields &&
4271
+ Object.keys(request.customFields).length > 0) {
4272
+ // Include custom_fields from request even if no userDid (matches buildSimplifiedFormatRequest)
4273
+ result.custom_fields = request.customFields;
4274
+ }
4275
+ // If no userDid, no customFields, and no provider info, custom_fields is omitted (valid)
4185
4276
  return result;
4186
4277
  }
4187
4278
  /**
@@ -4221,25 +4312,44 @@ export class ConsentService {
4221
4312
  // CRITICAL: user_did is required for proper user identification in dashboard
4222
4313
  // user_identifier is for display purposes (email, username, etc.)
4223
4314
  // user_id is the provider-specific ID from credential auth (for UX metadata)
4315
+ //
4316
+ // Fallback Strategy:
4317
+ // 1. If email available → user_identifier = email (preferred)
4318
+ // 2. If no email → user_identifier = userDid (fallback so AgentShield has something to display)
4319
+ // AgentShield will also check metadata.user_email for extraction
4224
4320
  if (userDid) {
4225
4321
  // user_did is the primary identifier - the actual DID
4226
4322
  simplifiedRequest.user_did = userDid;
4227
- // user_identifier: Use credential_user_id if available (human-readable),
4228
- // otherwise fall back to DID
4229
- simplifiedRequest.user_identifier =
4230
- request.credential_user_id || userDid;
4231
- // user_id: Include the credential provider's user ID for UX display in dashboard
4232
- // This is separate from user_did (cryptographic identity) and user_identifier
4233
- if (request.credential_user_id) {
4234
- simplifiedRequest.user_id = request.credential_user_id;
4235
- logger.debug("[ConsentService] Including user_id from credential auth:", {
4236
- user_id: request.credential_user_id.substring(0, 20) + "...",
4323
+ // user_identifier: Human-readable identifier (email/username) for AgentShield dashboard display
4324
+ // user_id: Provider's internal ID (e.g., customer ID 696395) for business reference
4325
+ // user_did: Cryptographic DID for identity verification
4326
+ if (request.credential_user_email) {
4327
+ // Have email - use it as human-readable identifier
4328
+ simplifiedRequest.user_identifier = request.credential_user_email;
4329
+ }
4330
+ else {
4331
+ // No email - fall back to DID so dashboard has something to display
4332
+ // AgentShield will detect this is a DID and may display differently
4333
+ simplifiedRequest.user_identifier = userDid;
4334
+ }
4335
+ // user_id is the provider's internal ID (separate from email)
4336
+ // Use credential_provider_user_id if available
4337
+ const providerId = request
4338
+ .credential_provider_user_id;
4339
+ if (providerId) {
4340
+ simplifiedRequest.user_id = providerId;
4341
+ logger.debug("[ConsentService] Including provider user_id from credential auth:", {
4342
+ user_id: providerId.substring(0, 20) + "...",
4343
+ user_identifier: request.credential_user_email?.substring(0, 20) + "...",
4237
4344
  });
4238
4345
  }
4239
- logger.debug("[ConsentService] Including user_did in delegation request:", {
4346
+ logger.debug("[ConsentService] Including user info in delegation request:", {
4240
4347
  user_did: userDid.substring(0, 20) + "...",
4241
- user_identifier: simplifiedRequest.user_identifier.substring(0, 20),
4242
- has_user_id: !!request.credential_user_id,
4348
+ user_identifier: request.credential_user_email
4349
+ ? request.credential_user_email.substring(0, 20) + "..."
4350
+ : "(fallback to DID)",
4351
+ has_user_id: !!providerId,
4352
+ source: request.credential_user_email ? "email" : "did-fallback",
4243
4353
  });
4244
4354
  }
4245
4355
  else {
@@ -4264,7 +4374,16 @@ export class ConsentService {
4264
4374
  const providerType = request.provider_type || customFieldsFromRequest.provider_type;
4265
4375
  const provider = customFieldsFromRequest.provider;
4266
4376
  const hasProviderInfo = providerType || provider;
4267
- if (userDid || hasProviderInfo) {
4377
+ // MCP-I Compatibility: Include user_email and user_id in custom_fields (becomes metadata)
4378
+ // AgentShield extracts these from metadata when user_identifier is a DID or not provided
4379
+ // This ensures human-readable identifiers are always available for dashboard display
4380
+ //
4381
+ // user_email = human-readable email (for display)
4382
+ // user_id = provider's internal ID (for business reference)
4383
+ const userEmail = request.credential_user_email || null;
4384
+ const providerUserId = request
4385
+ .credential_provider_user_id || null;
4386
+ if (userDid || hasProviderInfo || userEmail) {
4268
4387
  // Include issuer_did and subject_did in custom_fields when we have userDid
4269
4388
  // Also include provider_type and provider for AgentShield dashboard
4270
4389
  // CRITICAL: AgentShield derives authorization from metadata.provider_type:
@@ -4282,6 +4401,12 @@ export class ConsentService {
4282
4401
  format_version: "simplified_v1",
4283
4402
  // Include provider_type at the custom_fields level (where AgentShield reads it)
4284
4403
  ...(providerType ? { provider_type: providerType } : {}),
4404
+ // MCP-I Compatibility: Include user_email and user_id in metadata
4405
+ // AgentShield will extract these if user_identifier is not provided or is a DID
4406
+ // user_email = human-readable email (for display)
4407
+ // user_id = provider's internal ID (for business reference, e.g., customer ID 696395)
4408
+ ...(userEmail ? { user_email: userEmail } : {}),
4409
+ ...(providerUserId ? { user_id: providerUserId } : {}),
4285
4410
  // Merge with any existing custom_fields from request
4286
4411
  ...customFieldsFromRequest,
4287
4412
  };
@@ -4294,6 +4419,16 @@ export class ConsentService {
4294
4419
  : "customFields",
4295
4420
  });
4296
4421
  }
4422
+ if (userEmail || providerUserId) {
4423
+ logger.debug("[ConsentService] Including user info in custom_fields for AgentShield compatibility:", {
4424
+ user_email: userEmail
4425
+ ? userEmail.substring(0, 20) + "..."
4426
+ : undefined,
4427
+ user_id: providerUserId
4428
+ ? providerUserId.substring(0, 20) + "..."
4429
+ : undefined,
4430
+ });
4431
+ }
4297
4432
  }
4298
4433
  else if (request.customFields &&
4299
4434
  Object.keys(request.customFields).length > 0) {