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

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