@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
@@ -1,562 +0,0 @@
1
- /**
2
- * Copyright (c) Microsoft Corporation. All rights reserved.
3
- * Licensed under the MIT License.
4
- */
5
-
6
- import { ConfidentialClientApplication, LogLevel, ManagedIdentityApplication, NodeSystemOptions } from '@azure/msal-node'
7
- import axios from 'axios'
8
- import { AuthConfiguration, resolveAuthority as resolveAuthorityUtil } from './authConfiguration'
9
- import { AuthProvider } from './authProvider'
10
- import { debug, trace } from '@microsoft/agents-telemetry'
11
- import { v4 } from 'uuid'
12
- import { MemoryCache } from './MemoryCache'
13
- import jwt from 'jsonwebtoken'
14
-
15
- import fs from 'fs'
16
- import crypto from 'crypto'
17
- import { AuthenticationTraceDefinitions } from '../observability'
18
-
19
- const audience = 'api://AzureADTokenExchange'
20
- const logger = debug('agents:msal')
21
-
22
- /**
23
- * Provides tokens using MSAL.
24
- */
25
- export class MsalTokenProvider implements AuthProvider {
26
- private readonly _agenticTokenCache: MemoryCache<string>
27
- public readonly connectionSettings?: AuthConfiguration
28
-
29
- constructor (connectionSettings?: AuthConfiguration) {
30
- this._agenticTokenCache = new MemoryCache<string>()
31
- this.connectionSettings = connectionSettings
32
- }
33
-
34
- /**
35
- * Gets an access token using the auth configuration from the MsalTokenProvider instance and the provided scope.
36
- * @param scope The scope for the token.
37
- * @returns A promise that resolves to the access token.
38
- */
39
- public async getAccessToken (scope: string): Promise<string>
40
- /**
41
- * Gets an access token.
42
- * @param authConfig The authentication configuration.
43
- * @param scope The scope for the token.
44
- * @returns A promise that resolves to the access token.
45
- */
46
- public async getAccessToken (authConfig: AuthConfiguration, scope: string): Promise<string>
47
- public async getAccessToken (authConfigOrScope: AuthConfiguration | string, scope?: string): Promise<string> {
48
- return trace(AuthenticationTraceDefinitions.getAccessToken, async ({ record }) => {
49
- let authConfig: AuthConfiguration
50
- let actualScope: string
51
-
52
- if (typeof authConfigOrScope === 'string') {
53
- // Called as getAccessToken(scope)
54
- if (!this.connectionSettings) {
55
- throw new Error('Connection settings must be provided to constructor when calling getAccessToken(scope)')
56
- }
57
- authConfig = this.connectionSettings
58
- actualScope = authConfigOrScope
59
- } else {
60
- // Called as getAccessToken(authConfig, scope)
61
- authConfig = authConfigOrScope
62
- actualScope = scope as string
63
- }
64
-
65
- record({ scope: actualScope })
66
-
67
- if (!authConfig.clientId && process.env.NODE_ENV !== 'production') {
68
- record({ method: 'unknown' })
69
- return ''
70
- }
71
-
72
- let token
73
- if (authConfig.WIDAssertionFile !== undefined) {
74
- record({ method: 'wid' })
75
- logger.debug('getAccessToken via WID clientId=%s scope=%s', authConfig.clientId, actualScope)
76
- token = await this.acquireAccessTokenViaWID(authConfig, actualScope)
77
- } else if (authConfig.FICClientId !== undefined) {
78
- record({ method: 'fic' })
79
- logger.debug('getAccessToken via FIC clientId=%s scope=%s', authConfig.clientId, actualScope)
80
- token = await this.acquireAccessTokenViaFIC(authConfig, actualScope)
81
- } else if (authConfig.clientSecret !== undefined) {
82
- record({ method: 'secret' })
83
- logger.debug('getAccessToken via secret clientId=%s scope=%s', authConfig.clientId, actualScope)
84
- token = await this.acquireAccessTokenViaSecret(authConfig, actualScope)
85
- } else if (authConfig.certPemFile !== undefined &&
86
- authConfig.certKeyFile !== undefined) {
87
- record({ method: 'certificate' })
88
- logger.debug('getAccessToken via certificate clientId=%s scope=%s', authConfig.clientId, actualScope)
89
- token = await this.acquireTokenWithCertificate(authConfig, actualScope)
90
- } else if (authConfig.clientSecret === undefined &&
91
- authConfig.certPemFile === undefined &&
92
- authConfig.certKeyFile === undefined) {
93
- record({ method: 'managed_identity' })
94
- logger.debug('getAccessToken via managed identity clientId=%s scope=%s', authConfig.clientId, actualScope)
95
- token = await this.acquireTokenWithUserAssignedIdentity(authConfig, actualScope)
96
- } else {
97
- throw new Error('Invalid authConfig. ')
98
- }
99
- if (token === undefined) {
100
- throw new Error('Failed to acquire token')
101
- }
102
-
103
- return token
104
- })
105
- }
106
-
107
- public async acquireTokenOnBehalfOf (scopes: string[], oboAssertion: string): Promise<string>
108
- public async acquireTokenOnBehalfOf (authConfig: AuthConfiguration, scopes: string[], oboAssertion: string): Promise<string>
109
- public async acquireTokenOnBehalfOf (
110
- authConfigOrScopes: AuthConfiguration | string[],
111
- scopesOrOboAssertion?: string[] | string,
112
- oboAssertion?: string
113
- ): Promise<string> {
114
- return trace(AuthenticationTraceDefinitions.acquireTokenOnBehalfOf, async ({ record }) => {
115
- let authConfig: AuthConfiguration
116
- let actualScopes: string[]
117
- let actualOboAssertion: string
118
-
119
- if (Array.isArray(authConfigOrScopes)) {
120
- // Called as acquireTokenOnBehalfOf(scopes, oboAssertion)
121
- if (!this.connectionSettings) {
122
- throw new Error('Connection settings must be provided to constructor when calling acquireTokenOnBehalfOf(scopes, oboAssertion)')
123
- }
124
- authConfig = this.connectionSettings
125
- actualScopes = authConfigOrScopes
126
- actualOboAssertion = scopesOrOboAssertion as string
127
- } else {
128
- // Called as acquireTokenOnBehalfOf(authConfig, scopes, oboAssertion)
129
- authConfig = authConfigOrScopes
130
- actualScopes = scopesOrOboAssertion as string[]
131
- actualOboAssertion = oboAssertion!
132
- }
133
-
134
- record({ scopes: actualScopes })
135
- logger.debug('acquireTokenOnBehalfOf clientId=%s scopes=%o', authConfig.clientId, actualScopes)
136
-
137
- const cca = new ConfidentialClientApplication({
138
- auth: {
139
- clientId: authConfig.clientId as string,
140
- authority: `${authConfig.authority}/${authConfig.tenantId || 'botframework.com'}`,
141
- clientSecret: authConfig.clientSecret
142
- },
143
- system: this.sysOptions
144
- })
145
- const token = await cca.acquireTokenOnBehalfOf({
146
- oboAssertion: actualOboAssertion,
147
- scopes: actualScopes
148
- })
149
- if (!token?.accessToken) {
150
- throw new Error('Failed to acquire token on behalf of user')
151
- }
152
-
153
- return token.accessToken
154
- })
155
- }
156
-
157
- public async getAgenticInstanceToken (tenantId: string, agentAppInstanceId: string): Promise<string> {
158
- return trace(AuthenticationTraceDefinitions.getAgenticInstanceToken, async ({ record }) => {
159
- logger.debug('getAgenticInstanceToken tenantId=%s agentAppInstanceId=%s', tenantId, agentAppInstanceId)
160
- record({ agenticInstanceId: agentAppInstanceId })
161
-
162
- if (!this.connectionSettings) {
163
- throw new Error('Connection settings must be provided when calling getAgenticInstanceToken')
164
- }
165
- const appToken = await this.getAgenticApplicationToken(tenantId, agentAppInstanceId)
166
- const cca = new ConfidentialClientApplication({
167
- auth: {
168
- clientId: agentAppInstanceId,
169
- clientAssertion: appToken,
170
- authority: this.resolveAuthority(tenantId),
171
- },
172
- system: this.sysOptions
173
- })
174
-
175
- const token = await cca.acquireTokenByClientCredential({
176
- scopes: ['api://AzureAdTokenExchange/.default'],
177
- correlationId: v4(),
178
- azureRegion: this.connectionSettings?.azureRegion
179
- })
180
-
181
- if (!token?.accessToken) {
182
- throw new Error(`Failed to acquire instance token for agent instance: ${agentAppInstanceId}`)
183
- }
184
-
185
- return token.accessToken
186
- })
187
- }
188
-
189
- /**
190
- * This method can optionally accept a tenant ID that overrides the tenant ID in the connection settings.
191
- * The passed tenantId is always preferred over the configured tenantId when present.
192
- * @param tenantId
193
- * @returns
194
- */
195
- private resolveAuthority (tenantId?: string) : string {
196
- const { authority: configuredAuth, tenantId: configuredTenantId } = this.connectionSettings ?? {}
197
-
198
- if (!tenantId) {
199
- // No agentic tenant override — delegate to shared utility
200
- return resolveAuthorityUtil(configuredAuth, configuredTenantId)
201
- }
202
-
203
- // Agentic override: build a clean base using the override tenant, then replace any
204
- // /common or GUID placeholder left in the authority (e.g. from a multi-tenant config)
205
- const base = resolveAuthorityUtil(configuredAuth, tenantId)
206
- const guidPattern = /\/[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/
207
-
208
- if (base.endsWith('/common') || guidPattern.test(base)) {
209
- return base.replace(
210
- /\/(?:common|[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})(?=\/|$)/,
211
- `/${tenantId}`
212
- )
213
- }
214
-
215
- return base
216
- }
217
-
218
- /**
219
- * Does a direct HTTP call to acquire a token for agentic scenarios - do not use this directly!
220
- * This method will be removed once MSAL is updated with the necessary features.
221
- * (This is required in order to pass additional parameters into the auth call)
222
- * @param tenantId
223
- * @param clientId
224
- * @param clientAssertion
225
- * @param scopes
226
- * @param tokenBodyParameters
227
- * @returns
228
- */
229
- private async acquireTokenForAgenticScenarios (tenantId: string, clientId: string, clientAssertion: string | undefined, scopes: string[], tokenBodyParameters: { [key: string]: any }): Promise<string | null> {
230
- if (!this.connectionSettings) {
231
- throw new Error('Connection settings must be provided when calling getAgenticInstanceToken')
232
- }
233
-
234
- logger.debug('acquireTokenForAgenticScenarios clientId=%s tenantId=%s scopes=%o grant_type=%s', clientId, tenantId, scopes, tokenBodyParameters.grant_type)
235
- // Check cache first
236
- const cacheKey = `${clientId}/${Object.keys(tokenBodyParameters).map(key => key !== 'user_federated_identity_credential' ? `${key}=${tokenBodyParameters[key]}` : '').join('&')}/${scopes.join(';')}`
237
- if (this._agenticTokenCache.get(cacheKey)) {
238
- return this._agenticTokenCache.get(cacheKey) as string
239
- }
240
-
241
- const url = `${this.resolveAuthority(tenantId)}/oauth2/v2.0/token`
242
-
243
- const data: { [key: string]: any } = {
244
- client_id: clientId,
245
- scope: scopes.join(' '),
246
- ...tokenBodyParameters
247
- }
248
-
249
- if (clientAssertion) {
250
- data.client_assertion_type = 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer'
251
- data.client_assertion = clientAssertion
252
- } else {
253
- data.client_secret = this.connectionSettings.clientSecret
254
- }
255
-
256
- if (data.grant_type !== 'user_fic') {
257
- data.client_info = '2'
258
- }
259
-
260
- const token = await axios.post(
261
- url,
262
- data,
263
- {
264
- headers: {
265
- 'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8'
266
- }
267
- }
268
- ).catch((error) => {
269
- logger.error('Error acquiring token: ', error.toJSON())
270
- throw error
271
- })
272
-
273
- // capture token, expire local cache 5 minutes early
274
- this._agenticTokenCache.set(cacheKey, token.data.access_token, token.data.expires_in - 300)
275
- return token.data.access_token
276
- }
277
-
278
- public async getAgenticUserToken (tenantId: string, agentAppInstanceId: string, agenticUserId: string, scopes: string[]): Promise<string> {
279
- return trace(AuthenticationTraceDefinitions.getAgenticUserToken, async ({ record }) => {
280
- logger.debug('getAgenticUserToken tenantId=%s agentAppInstanceId=%s scopes=%o', tenantId, agentAppInstanceId, scopes)
281
- record({ agenticInstanceId: agentAppInstanceId, agenticUserId, scopes })
282
-
283
- const agentToken = await this.getAgenticApplicationToken(tenantId, agentAppInstanceId)
284
- const instanceToken = await this.getAgenticInstanceToken(tenantId, agentAppInstanceId)
285
-
286
- const token = await this.acquireTokenForAgenticScenarios(tenantId, agentAppInstanceId, agentToken, scopes, {
287
- user_id: agenticUserId,
288
- user_federated_identity_credential: instanceToken,
289
- grant_type: 'user_fic',
290
- })
291
-
292
- if (!token) {
293
- throw new Error(`Failed to acquire instance token for user token: ${agentAppInstanceId}`)
294
- }
295
-
296
- return token
297
- })
298
- }
299
-
300
- public async getAgenticApplicationToken (tenantId: string, agentAppInstanceId: string): Promise<string> {
301
- if (!this.connectionSettings?.clientId) {
302
- throw new Error('Connection settings must be provided when calling getAgenticApplicationToken')
303
- }
304
- logger.debug('getAgenticApplicationToken clientId=%s tenantId=%s agentAppInstanceId=%s', this.connectionSettings.clientId, tenantId, agentAppInstanceId)
305
-
306
- let clientAssertion
307
-
308
- if (this.connectionSettings.WIDAssertionFile !== undefined) {
309
- clientAssertion = fs.readFileSync(this.connectionSettings.WIDAssertionFile as string, 'utf8')
310
- } else if (this.connectionSettings.FICClientId !== undefined) {
311
- clientAssertion = await this.fetchExternalToken(this.connectionSettings.FICClientId as string)
312
- } else if (this.connectionSettings.certPemFile !== undefined &&
313
- this.connectionSettings.certKeyFile !== undefined) {
314
- clientAssertion = this.getAssertionFromCert(this.connectionSettings)
315
- }
316
-
317
- const token = await this.acquireTokenForAgenticScenarios(tenantId, this.connectionSettings.clientId, clientAssertion, ['api://AzureAdTokenExchange/.default'], {
318
- grant_type: 'client_credentials',
319
- fmi_path: agentAppInstanceId,
320
- })
321
-
322
- if (!token) {
323
- throw new Error(`Failed to acquire token for agent instance: ${agentAppInstanceId}`)
324
- }
325
-
326
- return token
327
- }
328
-
329
- private readonly sysOptions: NodeSystemOptions = {
330
- loggerOptions: {
331
- logLevel: LogLevel.Trace,
332
- loggerCallback: (level, message, containsPii) => {
333
- if (containsPii) {
334
- return
335
- }
336
- switch (level) {
337
- case LogLevel.Error:
338
- logger.error(message)
339
- return
340
- case LogLevel.Info:
341
- logger.debug(message)
342
- return
343
- case LogLevel.Warning:
344
- if (!message.includes('Warning - No client info in response')) {
345
- logger.warn(message)
346
- }
347
- return
348
- case LogLevel.Verbose:
349
- logger.debug(message)
350
- }
351
- },
352
- piiLoggingEnabled: false
353
- }
354
- }
355
-
356
- /**
357
- * Generates the client assertion using the provided certificate.
358
- * @param authConfig The authentication configuration.
359
- * @returns The client assertion.
360
- */
361
- private getAssertionFromCert (authConfig: AuthConfiguration): string {
362
- const base64url = (buf: Buffer) =>
363
- buf.toString('base64').replace(/=/g, '').replace(/\+/g, '-').replace(/\//g, '_')
364
-
365
- const privateKeyPem = fs.readFileSync(authConfig.certKeyFile as string)
366
-
367
- const pemFile = fs.readFileSync(authConfig.certPemFile as string)
368
- const pubKeyObject = new crypto.X509Certificate(pemFile)
369
-
370
- const der = pubKeyObject.raw
371
- const x5tS256 = base64url(crypto.createHash('sha256').update(der).digest())
372
-
373
- let x5c
374
- if (authConfig.sendX5C) {
375
- x5c = pemFile.toString()
376
- }
377
-
378
- const now = Math.floor(Date.now() / 1000)
379
- const payload = {
380
- aud: `${this.resolveAuthority(authConfig.tenantId)}/oauth2/v2.0/token`,
381
- iss: authConfig.clientId,
382
- sub: authConfig.clientId,
383
- jti: v4(),
384
- nbf: now,
385
- iat: now,
386
- exp: now + 600, // 10 minutes
387
- }
388
-
389
- return jwt.sign(
390
- payload,
391
- privateKeyPem,
392
- {
393
- algorithm: 'PS256',
394
- header: { alg: 'PS256', typ: 'JWT', 'x5t#S256': x5tS256, x5c }
395
- }
396
- )
397
- }
398
-
399
- /**
400
- * Acquires a token using a user-assigned identity.
401
- * @param authConfig The authentication configuration.
402
- * @param scope The scope for the token.
403
- * @returns A promise that resolves to the access token.
404
- */
405
- private async acquireTokenWithUserAssignedIdentity (authConfig: AuthConfiguration, scope: string) {
406
- const mia = new ManagedIdentityApplication({
407
- managedIdentityIdParams: {
408
- userAssignedClientId: authConfig.clientId || ''
409
- },
410
- system: this.sysOptions
411
- })
412
- const token = await mia.acquireToken({
413
- resource: scope
414
- })
415
- return token?.accessToken
416
- }
417
-
418
- /**
419
- * Acquires a token using a certificate.
420
- * @param authConfig The authentication configuration.
421
- * @param scope The scope for the token.
422
- * @returns A promise that resolves to the access token.
423
- */
424
- private async acquireTokenWithCertificate (authConfig: AuthConfiguration, scope: string) {
425
- const privateKeySource = fs.readFileSync(authConfig.certKeyFile as string)
426
-
427
- const privateKeyObject = crypto.createPrivateKey({
428
- key: privateKeySource,
429
- format: 'pem'
430
- })
431
-
432
- const privateKey = privateKeyObject.export({
433
- format: 'pem',
434
- type: 'pkcs8'
435
- })
436
-
437
- const pemFile = fs.readFileSync(authConfig.certPemFile as string)
438
- const pubKeyObject = new crypto.X509Certificate(pemFile)
439
-
440
- const cca = new ConfidentialClientApplication({
441
- auth: {
442
- clientId: authConfig.clientId || '',
443
- authority: `${authConfig.authority}/${authConfig.tenantId || 'botframework.com'}`,
444
- clientCertificate: {
445
- privateKey: privateKey as string,
446
- thumbprint: pubKeyObject.fingerprint.replaceAll(':', ''),
447
- x5c: pemFile.toString()
448
- }
449
- },
450
- system: this.sysOptions
451
- })
452
- const token = await cca.acquireTokenByClientCredential({
453
- scopes: [`${scope}/.default`],
454
- correlationId: v4(),
455
- azureRegion: authConfig.azureRegion
456
- })
457
- if (!token?.accessToken) {
458
- throw new Error('Failed to acquire token using certificate')
459
- }
460
- return token.accessToken
461
- }
462
-
463
- /**
464
- * Acquires a token using a client secret.
465
- * @param authConfig The authentication configuration.
466
- * @param scope The scope for the token.
467
- * @returns A promise that resolves to the access token.
468
- */
469
- private async acquireAccessTokenViaSecret (authConfig: AuthConfiguration, scope: string) {
470
- const cca = new ConfidentialClientApplication({
471
- auth: {
472
- clientId: authConfig.clientId as string,
473
- authority: `${authConfig.authority}/${authConfig.tenantId || 'botframework.com'}`,
474
- clientSecret: authConfig.clientSecret
475
- },
476
- system: this.sysOptions
477
- })
478
- const token = await cca.acquireTokenByClientCredential({
479
- scopes: [`${scope}/.default`],
480
- correlationId: v4(),
481
- azureRegion: authConfig.azureRegion
482
- })
483
- if (!token?.accessToken) {
484
- throw new Error('Failed to acquire token using client secret')
485
- }
486
- return token.accessToken
487
- }
488
-
489
- /**
490
- * Acquires a token using a FIC client assertion.
491
- * @param authConfig The authentication configuration.
492
- * @param scope The scope for the token.
493
- * @returns A promise that resolves to the access token.
494
- */
495
- private async acquireAccessTokenViaFIC (authConfig: AuthConfiguration, scope: string) : Promise<string> {
496
- const scopes = [`${scope}/.default`]
497
- const clientAssertion = await this.fetchExternalToken(authConfig.FICClientId as string)
498
- const cca = new ConfidentialClientApplication({
499
- auth: {
500
- clientId: authConfig.clientId as string,
501
- authority: `${authConfig.authority}/${authConfig.tenantId}`,
502
- clientAssertion
503
- },
504
- system: this.sysOptions
505
- })
506
- const token = await cca.acquireTokenByClientCredential({ scopes, azureRegion: authConfig.azureRegion })
507
- logger.debug('got token using FIC client assertion')
508
- if (!token?.accessToken) {
509
- throw new Error('Failed to acquire token using FIC client assertion')
510
- }
511
- return token.accessToken
512
- }
513
-
514
- /**
515
- * Acquires a token using a Workload Identity client assertion.
516
- * @param authConfig The authentication configuration.
517
- * @param scope The scope for the token.
518
- * @returns A promise that resolves to the access token.
519
- */
520
- private async acquireAccessTokenViaWID (authConfig: AuthConfiguration, scope: string) : Promise<string> {
521
- const scopes = [`${scope}/.default`]
522
- const clientAssertion = fs.readFileSync(authConfig.WIDAssertionFile as string, 'utf8')
523
- const cca = new ConfidentialClientApplication({
524
- auth: {
525
- clientId: authConfig.clientId as string,
526
- authority: `https://login.microsoftonline.com/${authConfig.tenantId}`,
527
- clientAssertion
528
- },
529
- system: this.sysOptions
530
- })
531
- const token = await cca.acquireTokenByClientCredential({ scopes, azureRegion: authConfig.azureRegion })
532
- logger.debug('got token using WID client assertion')
533
- if (!token?.accessToken) {
534
- throw new Error('Failed to acquire token using WID client assertion')
535
- }
536
- return token.accessToken
537
- }
538
-
539
- /**
540
- * Fetches an external token.
541
- * @param FICClientId The FIC client ID.
542
- * @returns A promise that resolves to the external token.
543
- */
544
- private async fetchExternalToken (FICClientId: string) : Promise<string> {
545
- const managedIdentityClientAssertion = new ManagedIdentityApplication({
546
- managedIdentityIdParams: {
547
- userAssignedClientId: FICClientId
548
- },
549
- system: this.sysOptions
550
- }
551
- )
552
- const response = await managedIdentityClientAssertion.acquireToken({
553
- resource: audience,
554
- forceRefresh: true
555
- })
556
- logger.debug('got token for FIC')
557
- if (!response?.accessToken) {
558
- throw new Error('Failed to acquire external token for FIC client assertion')
559
- }
560
- return response.accessToken
561
- }
562
- }