@microsoft/agents-hosting 1.6.0-beta.9.gce9d8facd2 → 1.7.0-beta.1.g8bcd4f11a7

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 (149) hide show
  1. package/dist/package.json +4 -9
  2. package/dist/src/agent-client/agentClient.js +2 -2
  3. package/dist/src/agent-client/agentClient.js.map +1 -1
  4. package/dist/src/agent-client/agentResponseHandler.js +2 -2
  5. package/dist/src/agent-client/agentResponseHandler.js.map +1 -1
  6. package/dist/src/app/agentApplication.js +28 -2
  7. package/dist/src/app/agentApplication.js.map +1 -1
  8. package/dist/src/app/agentApplicationOptions.d.ts +10 -0
  9. package/dist/src/app/attachmentDownloader.js +5 -10
  10. package/dist/src/app/attachmentDownloader.js.map +1 -1
  11. package/dist/src/app/auth/authorizationManager.d.ts +4 -0
  12. package/dist/src/app/auth/authorizationManager.js +94 -67
  13. package/dist/src/app/auth/authorizationManager.js.map +1 -1
  14. package/dist/src/app/auth/handlers/azureBotAuthorization.js +2 -2
  15. package/dist/src/app/auth/handlers/azureBotAuthorization.js.map +1 -1
  16. package/dist/src/app/proactive/createConversationOptionsBuilder.js +10 -6
  17. package/dist/src/app/proactive/createConversationOptionsBuilder.js.map +1 -1
  18. package/dist/src/app/proactive/proactive.d.ts +1 -0
  19. package/dist/src/app/proactive/proactive.js +30 -15
  20. package/dist/src/app/proactive/proactive.js.map +1 -1
  21. package/dist/src/app/streaming/streamingResponse.d.ts +11 -0
  22. package/dist/src/app/streaming/streamingResponse.js +21 -0
  23. package/dist/src/app/streaming/streamingResponse.js.map +1 -1
  24. package/dist/src/app/teamsAttachmentDownloader.js +6 -14
  25. package/dist/src/app/teamsAttachmentDownloader.js.map +1 -1
  26. package/dist/src/auth/MemoryCache.d.ts +2 -1
  27. package/dist/src/auth/MemoryCache.js +7 -1
  28. package/dist/src/auth/MemoryCache.js.map +1 -1
  29. package/dist/src/auth/authConfiguration.d.ts +2 -143
  30. package/dist/src/auth/authConfiguration.js +336 -257
  31. package/dist/src/auth/authConfiguration.js.map +1 -1
  32. package/dist/src/auth/authConstants.d.ts +7 -7
  33. package/dist/src/auth/authConstants.js.map +1 -1
  34. package/dist/src/auth/connectionManager.d.ts +92 -0
  35. package/dist/src/auth/{msalConnectionManager.js → connectionManager.js} +48 -33
  36. package/dist/src/auth/connectionManager.js.map +1 -0
  37. package/dist/src/auth/index.d.ts +5 -3
  38. package/dist/src/auth/index.js +5 -3
  39. package/dist/src/auth/index.js.map +1 -1
  40. package/dist/src/auth/jwt-middleware.d.ts +6 -0
  41. package/dist/src/auth/jwt-middleware.js +34 -2
  42. package/dist/src/auth/jwt-middleware.js.map +1 -1
  43. package/dist/src/auth/msal/msalConnectionManager.d.ts +17 -0
  44. package/dist/src/auth/msal/msalConnectionManager.js +50 -0
  45. package/dist/src/auth/msal/msalConnectionManager.js.map +1 -0
  46. package/dist/src/auth/msal/msalConnectionSettings.d.ts +68 -0
  47. package/dist/src/auth/msal/msalConnectionSettings.js +7 -0
  48. package/dist/src/auth/msal/msalConnectionSettings.js.map +1 -0
  49. package/dist/src/auth/{msalTokenCredential.d.ts → msal/msalTokenCredential.d.ts} +1 -1
  50. package/dist/src/auth/{msalTokenCredential.js → msal/msalTokenCredential.js} +2 -2
  51. package/dist/src/auth/msal/msalTokenCredential.js.map +1 -0
  52. package/dist/src/auth/{msalTokenProvider.d.ts → msal/msalTokenProvider.d.ts} +30 -3
  53. package/dist/src/auth/msal/msalTokenProvider.js +733 -0
  54. package/dist/src/auth/msal/msalTokenProvider.js.map +1 -0
  55. package/dist/src/auth/settings.d.ts +336 -0
  56. package/dist/src/auth/settings.js +202 -0
  57. package/dist/src/auth/settings.js.map +1 -0
  58. package/dist/src/auth/sidecar/sidecarAuthProvider.d.ts +74 -0
  59. package/dist/src/auth/sidecar/sidecarAuthProvider.js +181 -0
  60. package/dist/src/auth/sidecar/sidecarAuthProvider.js.map +1 -0
  61. package/dist/src/auth/sidecar/sidecarConnectionSettings.d.ts +65 -0
  62. package/dist/src/auth/sidecar/sidecarConnectionSettings.js +7 -0
  63. package/dist/src/auth/sidecar/sidecarConnectionSettings.js.map +1 -0
  64. package/dist/src/auth/sidecar/sidecarHttpClient.d.ts +95 -0
  65. package/dist/src/auth/sidecar/sidecarHttpClient.js +406 -0
  66. package/dist/src/auth/sidecar/sidecarHttpClient.js.map +1 -0
  67. package/dist/src/auth/sidecar/sidecarModels.d.ts +110 -0
  68. package/dist/src/auth/sidecar/sidecarModels.js +48 -0
  69. package/dist/src/auth/sidecar/sidecarModels.js.map +1 -0
  70. package/dist/src/auth/sidecar/sidecarTokenExpiry.d.ts +13 -0
  71. package/dist/src/auth/sidecar/sidecarTokenExpiry.js +39 -0
  72. package/dist/src/auth/sidecar/sidecarTokenExpiry.js.map +1 -0
  73. package/dist/src/cloudAdapter.d.ts +58 -1
  74. package/dist/src/cloudAdapter.js +233 -53
  75. package/dist/src/cloudAdapter.js.map +1 -1
  76. package/dist/src/connector-client/connectorClient.d.ts +12 -8
  77. package/dist/src/connector-client/connectorClient.js +99 -82
  78. package/dist/src/connector-client/connectorClient.js.map +1 -1
  79. package/dist/src/errorHelper.js +181 -7
  80. package/dist/src/errorHelper.js.map +1 -1
  81. package/dist/src/getProductInfo.d.ts +23 -0
  82. package/dist/src/getProductInfo.js +71 -1
  83. package/dist/src/getProductInfo.js.map +1 -1
  84. package/dist/src/headerPropagation.d.ts +17 -2
  85. package/dist/src/headerPropagation.js +46 -24
  86. package/dist/src/headerPropagation.js.map +1 -1
  87. package/dist/src/httpClient.d.ts +60 -0
  88. package/dist/src/httpClient.js +173 -0
  89. package/dist/src/httpClient.js.map +1 -0
  90. package/dist/src/index.d.ts +3 -2
  91. package/dist/src/index.js +8 -2
  92. package/dist/src/index.js.map +1 -1
  93. package/dist/src/oauth/userTokenClient.d.ts +17 -4
  94. package/dist/src/oauth/userTokenClient.js +119 -80
  95. package/dist/src/oauth/userTokenClient.js.map +1 -1
  96. package/dist/src/observability/traces.d.ts +11 -4
  97. package/dist/src/observability/traces.js +39 -7
  98. package/dist/src/observability/traces.js.map +1 -1
  99. package/dist/src/utils/env.d.ts +50 -0
  100. package/dist/src/utils/env.js +113 -0
  101. package/dist/src/utils/env.js.map +1 -0
  102. package/dist/src/utils.d.ts +10 -0
  103. package/dist/src/utils.js +18 -0
  104. package/dist/src/utils.js.map +1 -0
  105. package/package.json +4 -9
  106. package/src/agent-client/agentClient.ts +2 -2
  107. package/src/agent-client/agentResponseHandler.ts +2 -2
  108. package/src/app/agentApplication.ts +30 -3
  109. package/src/app/agentApplicationOptions.ts +11 -0
  110. package/src/app/attachmentDownloader.ts +6 -8
  111. package/src/app/auth/authorizationManager.ts +84 -41
  112. package/src/app/auth/handlers/azureBotAuthorization.ts +2 -2
  113. package/src/app/proactive/createConversationOptionsBuilder.ts +8 -4
  114. package/src/app/proactive/proactive.ts +39 -23
  115. package/src/app/streaming/streamingResponse.ts +24 -1
  116. package/src/app/teamsAttachmentDownloader.ts +7 -11
  117. package/src/auth/MemoryCache.ts +7 -1
  118. package/src/auth/authConfiguration.ts +350 -356
  119. package/src/auth/authConstants.ts +7 -7
  120. package/src/auth/{msalConnectionManager.ts → connectionManager.ts} +65 -44
  121. package/src/auth/index.ts +5 -3
  122. package/src/auth/jwt-middleware.ts +32 -2
  123. package/src/auth/msal/msalConnectionManager.ts +55 -0
  124. package/src/auth/msal/msalConnectionSettings.ts +79 -0
  125. package/src/auth/{msalTokenCredential.ts → msal/msalTokenCredential.ts} +2 -1
  126. package/src/auth/msal/msalTokenProvider.ts +881 -0
  127. package/src/auth/settings.ts +378 -0
  128. package/src/auth/sidecar/sidecarAuthProvider.ts +234 -0
  129. package/src/auth/sidecar/sidecarConnectionSettings.ts +72 -0
  130. package/src/auth/sidecar/sidecarHttpClient.ts +443 -0
  131. package/src/auth/sidecar/sidecarModels.ts +153 -0
  132. package/src/auth/sidecar/sidecarTokenExpiry.ts +35 -0
  133. package/src/cloudAdapter.ts +292 -13
  134. package/src/connector-client/connectorClient.ts +116 -94
  135. package/src/errorHelper.ts +206 -7
  136. package/src/getProductInfo.ts +79 -1
  137. package/src/headerPropagation.ts +55 -23
  138. package/src/httpClient.ts +223 -0
  139. package/src/index.ts +6 -2
  140. package/src/oauth/userTokenClient.ts +137 -84
  141. package/src/observability/traces.ts +39 -8
  142. package/src/utils/env.ts +105 -0
  143. package/src/utils.ts +14 -0
  144. package/dist/src/auth/msalConnectionManager.d.ts +0 -64
  145. package/dist/src/auth/msalConnectionManager.js.map +0 -1
  146. package/dist/src/auth/msalTokenCredential.js.map +0 -1
  147. package/dist/src/auth/msalTokenProvider.js +0 -485
  148. package/dist/src/auth/msalTokenProvider.js.map +0 -1
  149. package/src/auth/msalTokenProvider.ts +0 -562
@@ -2,10 +2,10 @@
2
2
  * Copyright (c) Microsoft Corporation. All rights reserved.
3
3
  * Licensed under the MIT License.
4
4
  */
5
- export const ApxLocalScope = 'c16e153d-5d2b-4c21-b7f4-b05ee5d516f1/.default'
6
- export const ApxDevScope = '0d94caae-b412-4943-8a68-83135ad6d35f/.default'
7
- export const ApxProductionScope = '5a807f24-c9de-44ee-a3a7-329e88a00ffc/.default'
8
- export const ApxGCCScope = 'c9475445-9789-4fef-9ec5-cde4a9bcd446/.default'
9
- export const ApxGCCHScope = '6f669b9e-7701-4e2b-b624-82c9207fde26/.default'
10
- export const ApxDoDScope = '0a069c81-8c7c-4712-886b-9c542d673ffb/.default'
11
- export const ApxGallatinScope = 'bd004c8e-5acf-4c48-8570-4e7d46b2f63b/.default'
5
+ export const ApxLocalScope: string = 'c16e153d-5d2b-4c21-b7f4-b05ee5d516f1/.default'
6
+ export const ApxDevScope: string = '0d94caae-b412-4943-8a68-83135ad6d35f/.default'
7
+ export const ApxProductionScope: string = '5a807f24-c9de-44ee-a3a7-329e88a00ffc/.default'
8
+ export const ApxGCCScope: string = 'c9475445-9789-4fef-9ec5-cde4a9bcd446/.default'
9
+ export const ApxGCCHScope: string = '6f669b9e-7701-4e2b-b624-82c9207fde26/.default'
10
+ export const ApxDoDScope: string = '0a069c81-8c7c-4712-886b-9c542d673ffb/.default'
11
+ export const ApxGallatinScope: string = 'bd004c8e-5acf-4c48-8570-4e7d46b2f63b/.default'
@@ -3,28 +3,58 @@
3
3
  * Licensed under the MIT License.
4
4
  */
5
5
 
6
- import { Activity, RoleTypes } from '@microsoft/agents-activity'
7
- import { debug } from '@microsoft/agents-telemetry'
8
- import { AuthConfiguration, resolveAuthority } from './authConfiguration'
6
+ import { Activity, ExceptionHelper, RoleTypes } from '@microsoft/agents-activity'
7
+ import { debug, redactString } from '@microsoft/agents-telemetry'
8
+ import { AuthConfiguration, AuthType, resolveAuthType } from './authConfiguration'
9
9
  import { Connections } from './connections'
10
- import { MsalTokenProvider } from './msalTokenProvider'
10
+ import { AuthProvider } from './authProvider'
11
+ import { MsalTokenProvider } from './msal/msalTokenProvider'
12
+ import { SidecarAuthProvider } from './sidecar/sidecarAuthProvider'
11
13
  import { JwtPayload } from 'jsonwebtoken'
14
+ import { Errors } from '../errorHelper'
15
+ import type { ConnectionMapItem } from './settings'
12
16
 
13
17
  const logger = debug('agents:authorization:connections')
14
18
 
15
- export interface ConnectionMapItem {
16
- audience?: string
17
- serviceUrl: string
18
- connection: string
19
- }
19
+ /**
20
+ * Factory function that creates an {@link AuthProvider} instance from a connection's
21
+ * {@link AuthConfiguration}.
22
+ */
23
+ export type AuthProviderFactory = (config: AuthConfiguration) => AuthProvider
20
24
 
21
- export class MsalConnectionManager implements Connections {
22
- private _connections: Map<string, MsalTokenProvider>
23
- private _connectionsMap: ConnectionMapItem[]
24
- private _serviceConnectionConfiguration: AuthConfiguration
25
- private static readonly DEFAULT_CONNECTION = 'serviceConnection'
25
+ /**
26
+ * Default {@link AuthProviderFactory} that dispatches per-connection by `authType`: connections with
27
+ * `authType` set to `EntraAuthSideCar` use {@link SidecarAuthProvider}; all others use
28
+ * {@link MsalTokenProvider}.
29
+ * @param config The connection authentication configuration.
30
+ * @returns The auth provider for the connection.
31
+ */
32
+ export const defaultAuthProviderFactory: AuthProviderFactory = (config: AuthConfiguration): AuthProvider =>
33
+ config?.authType === AuthType.EntraAuthSideCar
34
+ ? new SidecarAuthProvider(config)
35
+ : new MsalTokenProvider(config)
26
36
 
37
+ /**
38
+ * Generic, provider-agnostic connection manager. Dispatches connections to any {@link AuthProvider}
39
+ * implementation produced by the supplied {@link AuthProviderFactory}, while owning the
40
+ * provider-independent connection routing logic (audience matching, service URL dispatch,
41
+ * `altBlueprintConnectionName` handling, default connection resolution).
42
+ */
43
+ export class ConnectionManager implements Connections {
44
+ protected _connections: Map<string, AuthProvider>
45
+ protected _connectionsMap: ConnectionMapItem[]
46
+ protected _serviceConnectionConfiguration: AuthConfiguration
47
+ protected static readonly DEFAULT_CONNECTION = 'serviceConnection'
48
+
49
+ /**
50
+ * Creates a new {@link ConnectionManager}.
51
+ * @param providerFactory Factory used to instantiate an {@link AuthProvider} for each connection.
52
+ * @param connectionsConfigurations Map of connection names to their authentication configurations.
53
+ * @param connectionsMap Map items used to route activities to connections.
54
+ * @param configuration Fallback authentication configuration (used when the above are empty).
55
+ */
27
56
  constructor (
57
+ providerFactory: AuthProviderFactory = defaultAuthProviderFactory,
28
58
  connectionsConfigurations: Map<string, AuthConfiguration> = new Map(),
29
59
  connectionsMap: ConnectionMapItem[] = [],
30
60
  configuration: AuthConfiguration = {}) {
@@ -35,23 +65,16 @@ export class MsalConnectionManager implements Connections {
35
65
  const providedConnections = connectionsConfigurations.size > 0 ? connectionsConfigurations : (configuration.connections || new Map())
36
66
 
37
67
  for (const [name, config] of providedConnections) {
38
- // Instantiate MsalTokenProvider for each connection
39
- this._connections.set(name, new MsalTokenProvider(config))
40
- if (name === MsalConnectionManager.DEFAULT_CONNECTION) {
68
+ this._connections.set(name, providerFactory(config))
69
+ if (name === ConnectionManager.DEFAULT_CONNECTION) {
41
70
  this._serviceConnectionConfiguration = config
42
71
  }
43
72
  }
44
73
 
45
74
  for (const [name, provider] of this._connections.entries()) {
46
75
  const cfg = provider.connectionSettings
47
- const authType = cfg?.certPemFile
48
- ? 'certificate'
49
- : cfg?.clientSecret
50
- ? 'clientSecret'
51
- : cfg?.WIDAssertionFile || cfg?.FICClientId
52
- ? 'workloadIdentity'
53
- : 'none'
54
- logger.debug('connection "%s" clientId=%s tenantId=%s authType=%s', name, cfg?.clientId ?? '<none>', cfg?.tenantId ?? '<none>', authType)
76
+ const authType = resolveAuthType(cfg)
77
+ logger.debug('connection "%s" clientId=%s tenantId=%s authType=%s', name, redactString(cfg?.clientId, true) ?? '<none>', redactString(cfg?.tenantId, true) ?? '<none>', authType)
55
78
  }
56
79
 
57
80
  for (const item of this._connectionsMap) {
@@ -64,10 +87,10 @@ export class MsalConnectionManager implements Connections {
64
87
  * @param connectionName The name of the connection.
65
88
  * @returns The OAuth connection for the agent.
66
89
  */
67
- getConnection (connectionName: string): MsalTokenProvider {
90
+ getConnection (connectionName: string): AuthProvider {
68
91
  const conn = this._connections.get(connectionName)
69
92
  if (!conn) {
70
- throw new Error(`Connection not found: ${connectionName}`)
93
+ throw ExceptionHelper.generateException(Error, Errors.ConnectionNotFound, undefined, { connectionName })
71
94
  }
72
95
  return this.applyConnectionDefaults(conn)
73
96
  }
@@ -76,9 +99,9 @@ export class MsalConnectionManager implements Connections {
76
99
  * Get the default OAuth connection for the agent.
77
100
  * @returns The default OAuth connection for the agent.
78
101
  */
79
- getDefaultConnection (): MsalTokenProvider {
102
+ getDefaultConnection (): AuthProvider {
80
103
  if (this._connections.size === 0) {
81
- throw new Error('No connections found for this Agent in the Connections Configuration.')
104
+ throw ExceptionHelper.generateException(Error, Errors.NoConnectionsFoundInConfiguration)
82
105
  }
83
106
 
84
107
  // Return the wildcard map item instance.
@@ -88,7 +111,7 @@ export class MsalConnectionManager implements Connections {
88
111
  }
89
112
  }
90
113
 
91
- const conn = this._connections.values().next().value as MsalTokenProvider
114
+ const conn = this._connections.values().next().value as AuthProvider
92
115
 
93
116
  return this.applyConnectionDefaults(conn)
94
117
  }
@@ -111,9 +134,9 @@ export class MsalConnectionManager implements Connections {
111
134
  * ServiceUrl is: A regex to match with, or "*" for any serviceUrl value.
112
135
  * Connection is: A name in the 'Connections' list.
113
136
  */
114
- getTokenProvider (identity: JwtPayload, serviceUrl: string): MsalTokenProvider {
137
+ getTokenProvider (identity: JwtPayload, serviceUrl: string): AuthProvider {
115
138
  if (!identity) {
116
- throw new Error('Identity is required to get the token provider.')
139
+ throw ExceptionHelper.generateException(Error, Errors.IdentityRequiredForTokenProvider)
117
140
  }
118
141
 
119
142
  let audience
@@ -123,7 +146,7 @@ export class MsalConnectionManager implements Connections {
123
146
  audience = identity.aud
124
147
  }
125
148
 
126
- if (!audience || !serviceUrl) throw new Error('Audience and Service URL are required to get the token provider.')
149
+ if (!audience || !serviceUrl) throw ExceptionHelper.generateException(Error, Errors.AudienceAndServiceUrlRequiredForTokenProvider)
127
150
 
128
151
  if (this._connectionsMap.length === 0) {
129
152
  logger.debug('no connectionsMap, using default connection for serviceUrl=%s', serviceUrl)
@@ -151,7 +174,7 @@ export class MsalConnectionManager implements Connections {
151
174
  }
152
175
  }
153
176
  }
154
- throw new Error(`No connection found for audience: ${audience} and serviceUrl: ${serviceUrl}`)
177
+ throw ExceptionHelper.generateException(Error, Errors.NoConnectionForAudienceAndServiceUrl, undefined, { audience: String(audience), serviceUrl })
155
178
  }
156
179
 
157
180
  /**
@@ -160,7 +183,7 @@ export class MsalConnectionManager implements Connections {
160
183
  * @param activity The activity.
161
184
  * @returns The TokenProvider for the connection.
162
185
  */
163
- getTokenProviderFromActivity (identity: JwtPayload, activity: Activity): MsalTokenProvider {
186
+ getTokenProviderFromActivity (identity: JwtPayload, activity: Activity): AuthProvider {
164
187
  let connection = this.getTokenProvider(identity, activity.serviceUrl || '')
165
188
 
166
189
  // This is for the case where the Agentic BlueprintId is not the same as the AppId
@@ -183,15 +206,13 @@ export class MsalConnectionManager implements Connections {
183
206
  return this._serviceConnectionConfiguration
184
207
  }
185
208
 
186
- private applyConnectionDefaults (conn: MsalTokenProvider): MsalTokenProvider {
187
- if (conn.connectionSettings) {
188
- conn.connectionSettings.authority ??= 'https://login.microsoftonline.com'
189
- conn.connectionSettings.issuers ??= [
190
- 'https://api.botframework.com',
191
- `${resolveAuthority('https://sts.windows.net', conn.connectionSettings.tenantId)}/`,
192
- `${resolveAuthority(conn.connectionSettings.authority, conn.connectionSettings.tenantId)}/v2.0`
193
- ]
194
- }
209
+ /**
210
+ * Applies provider-specific defaults to a resolved connection before returning it. The generic
211
+ * base performs no mutation; provider-specific managers may override this.
212
+ * @param conn The resolved auth provider.
213
+ * @returns The auth provider, possibly with defaults applied.
214
+ */
215
+ protected applyConnectionDefaults (conn: AuthProvider): AuthProvider {
195
216
  return conn
196
217
  }
197
218
  }
package/src/auth/index.ts CHANGED
@@ -1,7 +1,9 @@
1
1
  export * from './authConfiguration'
2
2
  export * from './authConstants'
3
3
  export * from './authProvider'
4
- export * from './msalTokenProvider'
4
+ export * from './msal/msalTokenProvider'
5
5
  export * from './request'
6
- export * from './msalTokenCredential'
7
- export * from './msalConnectionManager'
6
+ export * from './msal/msalTokenCredential'
7
+ export * from './connectionManager'
8
+ export * from './msal/msalConnectionManager'
9
+ export * from './sidecar/sidecarAuthProvider'
@@ -11,6 +11,15 @@ import jwt, { JwtHeader, JwtPayload, SignCallback, GetPublicKeyOrSecret } from '
11
11
  import { debug } from '@microsoft/agents-telemetry'
12
12
 
13
13
  const logger = debug('agents:jwt-middleware')
14
+ const jwksClients = new Map<string, JwksClient>()
15
+ const maxJwksClients = 100
16
+
17
+ /**
18
+ * Clears process-wide JWKS clients.
19
+ */
20
+ export function clearJwksClients (): void {
21
+ jwksClients.clear()
22
+ }
14
23
 
15
24
  /**
16
25
  * Builds the JWKS URI for the given token issuer and auth configuration.
@@ -21,7 +30,27 @@ const logger = debug('agents:jwt-middleware')
21
30
  export function buildJwksUri (iss: string, authConfig: AuthConfiguration): string {
22
31
  return iss === 'https://api.botframework.com'
23
32
  ? 'https://login.botframework.com/v1/.well-known/keys'
24
- : `${resolveAuthority(authConfig.authority, authConfig.tenantId)}/discovery/v2.0/keys`
33
+ : `${resolveAuthority(authConfig.authorityEndpoint ?? authConfig.authority, authConfig.tenantId)}/discovery/v2.0/keys`
34
+ }
35
+
36
+ export function getJwksClient (jwksUri: string): JwksClient {
37
+ // Check if a client for this JWKS URI already exists in the cache.
38
+ let client = jwksClients.get(jwksUri)
39
+ if (!client) {
40
+ client = jwksRsa({ jwksUri })
41
+ jwksClients.set(jwksUri, client)
42
+ while (jwksClients.size > maxJwksClients) {
43
+ const oldestKey = jwksClients.keys().next().value
44
+ if (oldestKey === undefined) {
45
+ break
46
+ }
47
+ jwksClients.delete(oldestKey)
48
+ }
49
+ } else {
50
+ jwksClients.delete(jwksUri)
51
+ jwksClients.set(jwksUri, client)
52
+ }
53
+ return client
25
54
  }
26
55
 
27
56
  /**
@@ -55,9 +84,10 @@ const verifyToken = async (raw: string, config: AuthConfiguration): Promise<JwtP
55
84
  const jwksUri = buildJwksUri(payload.iss as string, authConfig)
56
85
 
57
86
  logger.debug(`fetching keys from ${jwksUri}`)
58
- const jwksClient: JwksClient = jwksRsa({ jwksUri })
87
+ const jwksClient = getJwksClient(jwksUri)
59
88
 
60
89
  const getKey: GetPublicKeyOrSecret = (header: JwtHeader, callback: SignCallback) => {
90
+ // Retrieve the public, issuer-wide signing key from the JWKS endpoint using the kid from the token header.
61
91
  jwksClient.getSigningKey(header.kid, (err: Error | null, key: SigningKey | undefined): void => {
62
92
  if (err) {
63
93
  logger.error('jwksClient.getSigningKey ', JSON.stringify(err))
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Copyright (c) Microsoft Corporation. All rights reserved.
3
+ * Licensed under the MIT License.
4
+ */
5
+
6
+ import { AuthConfiguration, resolveAuthority } from '../authConfiguration'
7
+ import type { ConnectionMapItem } from '../settings'
8
+ import { AuthProvider } from '../authProvider'
9
+ import { ConnectionManager, defaultAuthProviderFactory } from '../connectionManager'
10
+
11
+ /**
12
+ * Connection manager backed by MSAL (and, for `EntraAuthSideCar` connections, the Entra sidecar
13
+ * provider). A thin convenience subclass of {@link ConnectionManager} that supplies the default
14
+ * provider factory and applies MSAL-specific connection defaults.
15
+ */
16
+ export class MsalConnectionManager extends ConnectionManager {
17
+ constructor (
18
+ connectionsConfigurations: Map<string, AuthConfiguration> = new Map(),
19
+ connectionsMap: ConnectionMapItem[] = [],
20
+ configuration: AuthConfiguration = {}) {
21
+ super(defaultAuthProviderFactory, connectionsConfigurations, connectionsMap, configuration)
22
+ }
23
+
24
+ protected applyConnectionDefaults (conn: AuthProvider): AuthProvider {
25
+ if (conn.connectionSettings) {
26
+ conn.connectionSettings.authorityEndpoint ??= conn.connectionSettings.authority || 'https://login.microsoftonline.com'
27
+ conn.connectionSettings.authority ??= conn.connectionSettings.authorityEndpoint
28
+ conn.connectionSettings.issuers ??= [
29
+ 'https://api.botframework.com',
30
+ `${resolveAuthority('https://sts.windows.net', conn.connectionSettings.tenantId)}/`,
31
+ `${resolveAuthority(conn.connectionSettings.authorityEndpoint, conn.connectionSettings.tenantId)}/v2.0`
32
+ ]
33
+ // For backward compatibility
34
+ if (conn.connectionSettings.federatedClientId) {
35
+ conn.connectionSettings.FICClientId = conn.connectionSettings.federatedClientId
36
+ }
37
+
38
+ if (conn.connectionSettings.scopes?.length) {
39
+ conn.connectionSettings.scope = conn.connectionSettings.scopes?.[0]
40
+ }
41
+
42
+ if (conn.connectionSettings.authorityEndpoint) {
43
+ conn.connectionSettings.authority = conn.connectionSettings.authorityEndpoint
44
+ }
45
+
46
+ // .NET parity alias: keep altBlueprintConnectionName and alternateBlueprintConnectionName in sync.
47
+ conn.connectionSettings.altBlueprintConnectionName ??= conn.connectionSettings.alternateBlueprintConnectionName
48
+ if (conn.connectionSettings.altBlueprintConnectionName) {
49
+ conn.connectionSettings.alternateBlueprintConnectionName = conn.connectionSettings.altBlueprintConnectionName
50
+ }
51
+ }
52
+
53
+ return conn
54
+ }
55
+ }
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Copyright (c) Microsoft Corporation. All rights reserved.
3
+ * Licensed under the MIT License.
4
+ */
5
+
6
+ import type { ConnectionSettingsBase } from '../settings'
7
+
8
+ /**
9
+ * Connection settings for the MSAL-backed authentication providers (the default providers used for
10
+ * every {@link AuthType} except `EntraAuthSideCar`).
11
+ *
12
+ * @remarks
13
+ * Mirrors the .NET `Microsoft.Agents.Authentication.Msal.Model.ConnectionSettings` class. Node.js uses
14
+ * PEM certificate files (`certPemFile`/`certKeyFile`) rather than the Windows certificate store, so the
15
+ * .NET `CertThumbprint`/`CertSubjectName`/`CertStoreName`/`ValidCertificateOnly` settings have no JS
16
+ * equivalent; all other MSAL properties map one-to-one.
17
+ */
18
+ export interface MsalConnectionSettings extends ConnectionSettingsBase {
19
+ /**
20
+ * The client secret for the authentication configuration.
21
+ */
22
+ clientSecret?: string
23
+
24
+ /**
25
+ * The path to the certificate PEM file.
26
+ */
27
+ certPemFile?: string
28
+
29
+ /**
30
+ * The path to the certificate key file.
31
+ */
32
+ certKeyFile?: string
33
+
34
+ /**
35
+ * Indicates whether to send the X5C param or not (for SNI authentication).
36
+ */
37
+ sendX5C?: boolean
38
+
39
+ /**
40
+ * @deprecated Use federatedClientId instead.
41
+ *
42
+ * The FIC (First-Party Integration Channel) client ID.
43
+ */
44
+ FICClientId?: string
45
+
46
+ /**
47
+ * @deprecated Use `authType` set to `'WorkloadIdentity'` and `federatedTokenFile` instead.
48
+ *
49
+ * The path to K8s provided token.
50
+ */
51
+ WIDAssertionFile?: string
52
+
53
+ /**
54
+ * The Azure region for ESTS-R regional token acquisition (e.g. 'westus', 'eastus').
55
+ * When set, MSAL routes token requests to the specified regional endpoint.
56
+ * See https://learn.microsoft.com/en-us/entra/msal/javascript/node/regional-authorities for details.
57
+ */
58
+ azureRegion?: string
59
+
60
+ /**
61
+ * The path to the federated token file used for Workload Identity authentication.
62
+ */
63
+ federatedTokenFile?: string
64
+
65
+ /**
66
+ * Sets the resource URL for Identity Proxy Manager (IDPM).
67
+ *
68
+ * @remarks
69
+ * Set this to the appropriate resource identifier when the application is running in an environment,
70
+ * such as a Foundry container, that exposes Managed Identity through a container-specific IMDS endpoint.
71
+ * This setting is only meaningful when using Identity Proxy Manager (AuthType.IdentityProxyManager) for authentication.
72
+ */
73
+ idpmResource?: string
74
+
75
+ /**
76
+ * The federated client ID for the authentication configuration, used for workload identity federation scenarios.
77
+ */
78
+ federatedClientId?: string
79
+ }
@@ -1,5 +1,6 @@
1
1
  import { GetTokenOptions, TokenCredential } from '@azure/core-auth'
2
- import { AuthConfiguration, MsalTokenProvider } from './'
2
+ import { AuthConfiguration } from '../authConfiguration'
3
+ import { MsalTokenProvider } from './msalTokenProvider'
3
4
  import { debug } from '@microsoft/agents-telemetry'
4
5
 
5
6
  const logger = debug('agents:msal')