@microsoft/agents-hosting 1.5.0-beta.6.ga236d9a19c → 1.5.1

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 (157) hide show
  1. package/dist/package.json +10 -9
  2. package/dist/src/activityHandler.js +2 -2
  3. package/dist/src/activityHandler.js.map +1 -1
  4. package/dist/src/agent-client/agentClient.js +49 -40
  5. package/dist/src/agent-client/agentClient.js.map +1 -1
  6. package/dist/src/agent-client/agentResponseHandler.js +2 -2
  7. package/dist/src/agent-client/agentResponseHandler.js.map +1 -1
  8. package/dist/src/app/agentApplication.d.ts +36 -10
  9. package/dist/src/app/agentApplication.js +169 -99
  10. package/dist/src/app/agentApplication.js.map +1 -1
  11. package/dist/src/app/agentApplicationBuilder.d.ts +15 -0
  12. package/dist/src/app/agentApplicationBuilder.js +22 -4
  13. package/dist/src/app/agentApplicationBuilder.js.map +1 -1
  14. package/dist/src/app/agentApplicationOptions.d.ts +38 -0
  15. package/dist/src/app/attachmentDownloader.js +2 -2
  16. package/dist/src/app/attachmentDownloader.js.map +1 -1
  17. package/dist/src/app/auth/authorization.js +12 -9
  18. package/dist/src/app/auth/authorization.js.map +1 -1
  19. package/dist/src/app/auth/authorizationManager.d.ts +18 -5
  20. package/dist/src/app/auth/authorizationManager.js +258 -45
  21. package/dist/src/app/auth/authorizationManager.js.map +1 -1
  22. package/dist/src/app/auth/handlerStorage.js +3 -1
  23. package/dist/src/app/auth/handlerStorage.js.map +1 -1
  24. package/dist/src/app/auth/handlers/agenticAuthorization.d.ts +19 -16
  25. package/dist/src/app/auth/handlers/agenticAuthorization.js +46 -52
  26. package/dist/src/app/auth/handlers/agenticAuthorization.js.map +1 -1
  27. package/dist/src/app/auth/handlers/azureBotAuthorization.d.ts +51 -75
  28. package/dist/src/app/auth/handlers/azureBotAuthorization.js +217 -192
  29. package/dist/src/app/auth/handlers/azureBotAuthorization.js.map +1 -1
  30. package/dist/src/app/auth/types.d.ts +100 -1
  31. package/dist/src/app/auth/utils.d.ts +10 -0
  32. package/dist/src/app/auth/utils.js +21 -0
  33. package/dist/src/app/auth/utils.js.map +1 -0
  34. package/dist/src/app/index.d.ts +1 -0
  35. package/dist/src/app/index.js +1 -0
  36. package/dist/src/app/index.js.map +1 -1
  37. package/dist/src/app/proactive/conversation.d.ts +43 -0
  38. package/dist/src/app/proactive/conversation.js +67 -0
  39. package/dist/src/app/proactive/conversation.js.map +1 -0
  40. package/dist/src/app/proactive/conversationBuilder.d.ts +54 -0
  41. package/dist/src/app/proactive/conversationBuilder.js +110 -0
  42. package/dist/src/app/proactive/conversationBuilder.js.map +1 -0
  43. package/dist/src/app/proactive/conversationReferenceBuilder.d.ts +68 -0
  44. package/dist/src/app/proactive/conversationReferenceBuilder.js +125 -0
  45. package/dist/src/app/proactive/conversationReferenceBuilder.js.map +1 -0
  46. package/dist/src/app/proactive/createConversationOptions.d.ts +30 -0
  47. package/dist/src/app/proactive/createConversationOptions.js +10 -0
  48. package/dist/src/app/proactive/createConversationOptions.js.map +1 -0
  49. package/dist/src/app/proactive/createConversationOptionsBuilder.d.ts +69 -0
  50. package/dist/src/app/proactive/createConversationOptionsBuilder.js +141 -0
  51. package/dist/src/app/proactive/createConversationOptionsBuilder.js.map +1 -0
  52. package/dist/src/app/proactive/index.d.ts +7 -0
  53. package/dist/src/app/proactive/index.js +26 -0
  54. package/dist/src/app/proactive/index.js.map +1 -0
  55. package/dist/src/app/proactive/proactive.d.ts +248 -0
  56. package/dist/src/app/proactive/proactive.js +310 -0
  57. package/dist/src/app/proactive/proactive.js.map +1 -0
  58. package/dist/src/app/proactive/proactiveOptions.d.ts +19 -0
  59. package/dist/src/app/proactive/proactiveOptions.js +5 -0
  60. package/dist/src/app/proactive/proactiveOptions.js.map +1 -0
  61. package/dist/src/app/streaming/streamingResponse.js +2 -2
  62. package/dist/src/app/streaming/streamingResponse.js.map +1 -1
  63. package/dist/src/app/teamsAttachmentDownloader.js +2 -2
  64. package/dist/src/app/teamsAttachmentDownloader.js.map +1 -1
  65. package/dist/src/app/turnState.js +2 -2
  66. package/dist/src/app/turnState.js.map +1 -1
  67. package/dist/src/auth/authConfiguration.d.ts +61 -0
  68. package/dist/src/auth/authConfiguration.js +52 -3
  69. package/dist/src/auth/authConfiguration.js.map +1 -1
  70. package/dist/src/auth/jwt-middleware.js +2 -2
  71. package/dist/src/auth/jwt-middleware.js.map +1 -1
  72. package/dist/src/auth/msalConnectionManager.js +20 -0
  73. package/dist/src/auth/msalConnectionManager.js.map +1 -1
  74. package/dist/src/auth/msalTokenCredential.js +3 -0
  75. package/dist/src/auth/msalTokenCredential.js.map +1 -1
  76. package/dist/src/auth/msalTokenProvider.js +136 -110
  77. package/dist/src/auth/msalTokenProvider.js.map +1 -1
  78. package/dist/src/baseAdapter.js +2 -2
  79. package/dist/src/baseAdapter.js.map +1 -1
  80. package/dist/src/cloudAdapter.js +201 -154
  81. package/dist/src/cloudAdapter.js.map +1 -1
  82. package/dist/src/connector-client/connectorClient.js +176 -127
  83. package/dist/src/connector-client/connectorClient.js.map +1 -1
  84. package/dist/src/errorHelper.js +108 -0
  85. package/dist/src/errorHelper.js.map +1 -1
  86. package/dist/src/middlewareSet.js +2 -2
  87. package/dist/src/middlewareSet.js.map +1 -1
  88. package/dist/src/oauth/userTokenClient.js +78 -48
  89. package/dist/src/oauth/userTokenClient.js.map +1 -1
  90. package/dist/src/observability/index.d.ts +2 -0
  91. package/dist/src/observability/index.js +21 -0
  92. package/dist/src/observability/index.js.map +1 -0
  93. package/dist/src/observability/metrics.d.ts +21 -0
  94. package/dist/src/observability/metrics.js +87 -0
  95. package/dist/src/observability/metrics.js.map +1 -0
  96. package/dist/src/observability/traces.d.ts +234 -0
  97. package/dist/src/observability/traces.js +962 -0
  98. package/dist/src/observability/traces.js.map +1 -0
  99. package/dist/src/state/agentState.js +2 -2
  100. package/dist/src/state/agentState.js.map +1 -1
  101. package/dist/src/storage/fileStorage.js +38 -28
  102. package/dist/src/storage/fileStorage.js.map +1 -1
  103. package/dist/src/storage/memoryStorage.js +41 -30
  104. package/dist/src/storage/memoryStorage.js.map +1 -1
  105. package/dist/src/transcript/fileTranscriptLogger.js +2 -2
  106. package/dist/src/transcript/fileTranscriptLogger.js.map +1 -1
  107. package/dist/src/transcript/transcriptLoggerMiddleware.js +2 -2
  108. package/dist/src/transcript/transcriptLoggerMiddleware.js.map +1 -1
  109. package/dist/src/turnContext.js +48 -42
  110. package/dist/src/turnContext.js.map +1 -1
  111. package/package.json +10 -9
  112. package/src/activityHandler.ts +1 -1
  113. package/src/agent-client/agentClient.ts +53 -42
  114. package/src/agent-client/agentResponseHandler.ts +1 -1
  115. package/src/app/agentApplication.ts +212 -86
  116. package/src/app/agentApplicationBuilder.ts +26 -4
  117. package/src/app/agentApplicationOptions.ts +43 -0
  118. package/src/app/attachmentDownloader.ts +1 -1
  119. package/src/app/auth/authorization.ts +11 -8
  120. package/src/app/auth/authorizationManager.ts +297 -45
  121. package/src/app/auth/handlerStorage.ts +3 -1
  122. package/src/app/auth/handlers/agenticAuthorization.ts +68 -72
  123. package/src/app/auth/handlers/azureBotAuthorization.ts +260 -264
  124. package/src/app/auth/types.ts +102 -1
  125. package/src/app/auth/utils.ts +22 -0
  126. package/src/app/index.ts +1 -0
  127. package/src/app/proactive/conversation.ts +87 -0
  128. package/src/app/proactive/conversationBuilder.ts +139 -0
  129. package/src/app/proactive/conversationReferenceBuilder.ts +161 -0
  130. package/src/app/proactive/createConversationOptions.ts +35 -0
  131. package/src/app/proactive/createConversationOptionsBuilder.ts +181 -0
  132. package/src/app/proactive/index.ts +10 -0
  133. package/src/app/proactive/proactive.ts +524 -0
  134. package/src/app/proactive/proactiveOptions.ts +24 -0
  135. package/src/app/streaming/streamingResponse.ts +1 -1
  136. package/src/app/teamsAttachmentDownloader.ts +1 -1
  137. package/src/app/turnState.ts +1 -1
  138. package/src/auth/authConfiguration.ts +58 -1
  139. package/src/auth/jwt-middleware.ts +1 -1
  140. package/src/auth/msalConnectionManager.ts +22 -0
  141. package/src/auth/msalTokenCredential.ts +4 -0
  142. package/src/auth/msalTokenProvider.ts +138 -107
  143. package/src/baseAdapter.ts +1 -1
  144. package/src/cloudAdapter.ts +239 -184
  145. package/src/connector-client/connectorClient.ts +169 -126
  146. package/src/errorHelper.ts +124 -0
  147. package/src/middlewareSet.ts +1 -1
  148. package/src/oauth/userTokenClient.ts +70 -46
  149. package/src/observability/index.ts +5 -0
  150. package/src/observability/metrics.ts +103 -0
  151. package/src/observability/traces.ts +988 -0
  152. package/src/state/agentState.ts +1 -1
  153. package/src/storage/fileStorage.ts +36 -26
  154. package/src/storage/memoryStorage.ts +40 -29
  155. package/src/transcript/fileTranscriptLogger.ts +1 -1
  156. package/src/transcript/transcriptLoggerMiddleware.ts +1 -1
  157. package/src/turnContext.ts +47 -41
@@ -3,16 +3,19 @@
3
3
  * Licensed under the MIT License.
4
4
  */
5
5
 
6
- import { debug } from '@microsoft/agents-activity/logger'
7
6
  import { AuthorizationHandlerStatus, AuthorizationHandler, ActiveAuthorizationHandler, AuthorizationHandlerSettings, AuthorizationHandlerTokenOptions } from '../types'
8
7
  import { MessageFactory } from '../../../messageFactory'
9
8
  import { CardFactory } from '../../../cards'
10
9
  import { TurnContext } from '../../../turnContext'
11
10
  import { TokenExchangeRequest, TokenExchangeInvokeResponse, TokenResponse, UserTokenClient } from '../../../oauth'
12
- import jwt, { JwtPayload } from 'jsonwebtoken'
11
+ import jwt from 'jsonwebtoken'
13
12
  import { HandlerStorage } from '../handlerStorage'
14
- import { Activity, ActivityTypes, Channels } from '@microsoft/agents-activity'
15
- import { InvokeResponse, TokenExchangeInvokeRequest } from '../../../invoke'
13
+ import { TokenExchangeInvokeRequest } from '../../../invoke'
14
+ import { sendInvokeResponse } from '../utils'
15
+ import { Channels, ExceptionHelper } from '@microsoft/agents-activity'
16
+ import { trace, debug } from '@microsoft/agents-telemetry'
17
+ import { AuthorizationTraceDefinitions } from '../../../observability'
18
+ import { Errors } from '../../../errorHelper'
16
19
 
17
20
  const logger = debug('agents:authorization:azurebot')
18
21
 
@@ -37,46 +40,19 @@ interface AzureBotActiveHandler extends ActiveAuthorizationHandler {
37
40
  category?: Category
38
41
  }
39
42
 
40
- /**
41
- * Messages configuration for the AzureBotAuthorization handler.
42
- */
43
- export interface AzureBotAuthorizationOptionsMessages {
44
- /**
45
- * Message displayed when an invalid code is entered.
46
- * Use `{code}` as a placeholder for the entered code.
47
- * Defaults to: 'The code entered is invalid. Please sign-in again to continue.'
48
- */
49
- invalidCode?: string
50
- /**
51
- * Message displayed when the entered code format is invalid.
52
- * Use `{attemptsLeft}` as a placeholder for the number of attempts left.
53
- * Defaults to: 'Please enter a valid **6-digit** code format (_e.g. 123456_).\r\n**{attemptsLeft} attempt(s) left...**'
54
- */
55
- invalidCodeFormat?: string
56
- /**
57
- * Message displayed when the maximum number of attempts is exceeded.
58
- * Use `{maxAttempts}` as a placeholder for the maximum number of attempts.
59
- * Defaults to: 'You have exceeded the maximum number of sign-in attempts ({maxAttempts}).'
60
- */
61
- maxAttemptsExceeded?: string
62
- }
63
-
64
- /**
65
- * Settings for on-behalf-of token acquisition.
66
- */
67
- export interface AzureBotAuthorizationOptionsOBO {
68
- /**
69
- * Connection name to use for on-behalf-of token acquisition.
70
- */
71
- connection?: string
72
- /**
73
- * Scopes to request for on-behalf-of token acquisition.
74
- */
75
- scopes?: string[]
76
- }
77
-
78
43
  /**
79
44
  * Interface defining an authorization handler configuration.
45
+ * @remarks
46
+ * Properties can be configured via environment variables (case-insensitive).
47
+ * Use the format: `AgentApplication__UserAuthorization__handlers__{handlerId}__settings__{propertyName}`
48
+ * where `{handlerId}` is the handler's unique identifier and `{propertyName}` matches the property name.
49
+ *
50
+ * @example
51
+ * ```env
52
+ * # For a handler with id "myAuth":
53
+ * AgentApplication__UserAuthorization__handlers__myAuth__settings__azureBotOAuthConnectionName=MyConnection
54
+ * AgentApplication__UserAuthorization__handlers__myAuth__settings__oboScopes=api://scope1 api://scope2
55
+ * ```
80
56
  */
81
57
  export interface AzureBotAuthorizationOptions {
82
58
  /**
@@ -84,49 +60,50 @@ export interface AzureBotAuthorizationOptions {
84
60
  * This property is optional and should not be set when configuring this handler.
85
61
  * It is included here for completeness and type safety.
86
62
  */
87
- type?: undefined
63
+ type?: 'AzureBotUserAuthorization' | undefined
88
64
  /**
89
65
  * Connection name for the auth provider.
90
- * @remarks
91
- * When using environment variables, this can be set using the `${authHandlerId}_connectionName` variable.
92
66
  */
93
- name?: string,
67
+ azureBotOAuthConnectionName?: string,
94
68
  /**
95
69
  * Title to display on auth cards/UI.
96
- * @remarks
97
- * When using environment variables, this can be set using the `${authHandlerId}_connectionTitle` variable.
98
70
  */
99
71
  title?: string,
100
72
  /**
101
73
  * Text to display on auth cards/UI.
102
- * @remarks
103
- * When using environment variables, this can be set using the `${authHandlerId}_connectionText` variable.
104
74
  */
105
75
  text?: string,
106
76
  /**
107
77
  * Maximum number of attempts for entering the magic code. Defaults to 2.
108
- * @remarks
109
- * When using environment variables, this can be set using the `${authHandlerId}_maxAttempts` variable.
110
78
  */
111
- maxAttempts?: number
79
+ invalidSignInRetryMax?: number
80
+ /**
81
+ * Message displayed when an invalid code is entered.
82
+ * Use `{code}` as a placeholder to display the entered code.
83
+ * Defaults to: 'The code entered is invalid. Please sign-in again to continue.'
84
+ */
85
+ invalidSignInRetryMessage?: string
112
86
  /**
113
- * Messages to display for various authentication scenarios.
114
- * @remarks
115
- * When using environment variables, these can be set using the following variables:
116
- * - `${authHandlerId}_messages_invalidCode`
117
- * - `${authHandlerId}_messages_invalidCodeFormat`
118
- * - `${authHandlerId}_messages_maxAttemptsExceeded`
87
+ * Message displayed when the entered code format is invalid.
88
+ * Use `{attemptsLeft}` as a placeholder to display the number of attempts left.
89
+ * Defaults to: 'Please enter a valid **6-digit** code format (_e.g. 123456_).\r\n**{attemptsLeft} attempt(s) left...**'
119
90
  */
120
- messages?: AzureBotAuthorizationOptionsMessages
91
+ invalidSignInRetryMessageFormat?: string
121
92
  /**
122
- * Settings for on-behalf-of token acquisition.
123
- * @remarks
124
- * When using environment variables, these can be set using the following variables:
125
- * - `${authHandlerId}_obo_connection`
126
- * - `${authHandlerId}_obo_scopes` (comma-separated values, e.g. `scope1,scope2`)
93
+ * Message displayed when the maximum number of attempts is exceeded.
94
+ * Use `{maxAttempts}` as a placeholder to display the maximum number of attempts.
95
+ * Defaults to: 'You have exceeded the maximum number of sign-in attempts ({maxAttempts}).'
127
96
  */
128
- obo?: AzureBotAuthorizationOptionsOBO
129
-
97
+ invalidSignInRetryMaxExceededMessage?: string
98
+ /**
99
+ * Connection name to use for on-behalf-of token acquisition.
100
+ */
101
+ oboConnectionName?: string
102
+ /**
103
+ * Scopes to request for on-behalf-of token acquisition.
104
+ * @remarks When set via environment variable, use comma or space-separated values (e.g. `scope1,scope2` or `scope1 scope2`).
105
+ */
106
+ oboScopes?: string[]
130
107
  /**
131
108
  * Option to enable SSO when authenticating using Azure Active Directory (AAD). Defaults to true.
132
109
  */
@@ -157,61 +134,43 @@ interface SignInFailureValue {
157
134
  * Default implementation of an authorization handler using Azure Bot Service.
158
135
  */
159
136
  export class AzureBotAuthorization implements AuthorizationHandler {
160
- private _options: AzureBotAuthorizationOptions
161
137
  private _onSuccess?: Parameters<AuthorizationHandler['onSuccess']>[0]
162
138
  private _onFailure?: Parameters<AuthorizationHandler['onFailure']>[0]
163
139
 
164
140
  /**
165
141
  * Creates an instance of the AzureBotAuthorization.
166
142
  * @param id The unique identifier for the handler.
167
- * @param options The settings for the handler.
168
- * @param app The agent application instance.
143
+ * @param options The settings for the handler (must be fully resolved).
144
+ * @param settings The authorization handler settings.
169
145
  */
170
- constructor (public readonly id: string, options: AzureBotAuthorizationOptions, private settings: AzureBotAuthorizationSettings) {
146
+ constructor (public readonly id: string, private options: AzureBotAuthorizationOptions, private settings: AzureBotAuthorizationSettings) {
171
147
  if (!this.settings.storage) {
172
- throw new Error(this.prefix('The \'storage\' option is not available in the app options. Ensure that the app is properly configured.'))
148
+ throw ExceptionHelper.generateException(Error, Errors.StorageOptionNotAvailable)
173
149
  }
174
150
 
175
151
  if (!this.settings.connections) {
176
- throw new Error(this.prefix('The \'connections\' option is not available in the app options. Ensure that the app is properly configured.'))
152
+ throw ExceptionHelper.generateException(Error, Errors.ConnectionsOptionNotAvailable)
177
153
  }
178
154
 
179
- this._options = this.loadOptions(options)
180
- }
181
-
182
- /**
183
- * Loads and validates the authorization handler options.
184
- */
185
- private loadOptions (settings: AzureBotAuthorizationOptions) {
186
- const result: AzureBotAuthorizationOptions = {
187
- name: settings.name ?? (process.env[`${this.id}_connectionName`]),
188
- title: settings.title ?? (process.env[`${this.id}_connectionTitle`]) ?? 'Sign-in',
189
- text: settings.text ?? (process.env[`${this.id}_connectionText`]) ?? 'Please sign-in to continue',
190
- maxAttempts: settings.maxAttempts ?? parseInt(process.env[`${this.id}_maxAttempts`]!),
191
- messages: {
192
- invalidCode: settings.messages?.invalidCode ?? process.env[`${this.id}_messages_invalidCode`],
193
- invalidCodeFormat: settings.messages?.invalidCodeFormat ?? process.env[`${this.id}_messages_invalidCodeFormat`],
194
- maxAttemptsExceeded: settings.messages?.maxAttemptsExceeded ?? process.env[`${this.id}_messages_maxAttemptsExceeded`],
195
- },
196
- obo: {
197
- connection: settings.obo?.connection ?? process.env[`${this.id}_obo_connection`],
198
- scopes: settings.obo?.scopes ?? this.loadScopes(process.env[`${this.id}_obo_scopes`]),
199
- },
200
- enableSso: process.env[`${this.id}_enableSso`] !== 'false' // default value is true
155
+ if (!options.azureBotOAuthConnectionName) {
156
+ throw ExceptionHelper.generateException(Error, Errors.AzureBotOAuthConnectionNameRequired)
201
157
  }
158
+ }
202
159
 
203
- if (!result.name) {
204
- throw new Error(this.prefix(`The 'name' property or '${this.id}_connectionName' env variable is required to initialize the handler.`))
205
- }
160
+ readonly type = 'azurebot'
206
161
 
207
- return result
162
+ /**
163
+ * The OBO scopes configured for this handler.
164
+ */
165
+ get scopes (): string[] | undefined {
166
+ return this.options.oboScopes
208
167
  }
209
168
 
210
169
  /**
211
170
  * Maximum number of attempts for magic code entry.
212
171
  */
213
172
  private get maxAttempts (): number {
214
- const attempts = this._options.maxAttempts
173
+ const attempts = this.options.invalidSignInRetryMax
215
174
  const result = typeof attempts === 'number' && Number.isFinite(attempts) ? Math.round(attempts) : NaN
216
175
  return result > 0 ? result : DEFAULT_SIGN_IN_ATTEMPTS
217
176
  }
@@ -239,22 +198,21 @@ export class AzureBotAuthorization implements AuthorizationHandler {
239
198
  * @returns The token response containing the token or undefined if not available.
240
199
  */
241
200
  async token (context: TurnContext, options?: AuthorizationHandlerTokenOptions): Promise<TokenResponse> {
242
- let { token } = this.getContext(context)
243
-
244
- if (!token?.trim()) {
245
- const { activity } = context
201
+ const oboScopes = options?.scopes && options.scopes.length > 0 ? options.scopes : this.options.oboScopes
246
202
 
247
- const userTokenClient = await this.getUserTokenClient(context)
248
- // Using getTokenOrSignInResource instead of getUserToken to avoid HTTP 404 errors.
249
- const { tokenResponse } = await userTokenClient.getTokenOrSignInResource(activity.from?.id!, this._options.name!, activity.channelId!, activity.getConversationReference(), activity.relatesTo!, '')
250
- token = tokenResponse?.token
251
- }
252
-
253
- if (!token?.trim()) {
254
- return { token: undefined }
203
+ // OBO token acquisition
204
+ if (oboScopes && oboScopes.length > 0) {
205
+ const oboConnection = options?.connection ?? this.options.oboConnectionName
206
+ const token = await this.getOBOToken(context, oboConnection, oboScopes)
207
+ return { token }
255
208
  }
256
209
 
257
- return await this.handleOBO(token, options)
210
+ // Regular token acquisition
211
+ return trace(AuthorizationTraceDefinitions.azureBotToken, async ({ record }) => {
212
+ record({ handlerId: this.id, connectionName: this.options.azureBotOAuthConnectionName })
213
+ const token = await this.getBaseToken(context)
214
+ return { token }
215
+ })
258
216
  }
259
217
 
260
218
  /**
@@ -263,18 +221,22 @@ export class AzureBotAuthorization implements AuthorizationHandler {
263
221
  * @returns True if the signout was successful, false otherwise.
264
222
  */
265
223
  async signout (context: TurnContext): Promise<boolean> {
266
- const user = context.activity.from?.id
267
- const channel = context.activity.channelId
268
- const connection = this._options.name!
224
+ return trace(AuthorizationTraceDefinitions.azureBotSignout, async ({ record }) => {
225
+ const user = context.activity.from?.id
226
+ const channel = context.activity.channelId
227
+ const connection = this.options.azureBotOAuthConnectionName!
269
228
 
270
- if (!channel || !user) {
271
- throw new Error(this.prefix('Both \'activity.channelId\' and \'activity.from.id\' are required to perform signout.'))
272
- }
229
+ record({ handlerId: this.id, connectionName: connection, channelId: channel ?? 'unknown' })
273
230
 
274
- logger.debug(this.prefix(`Signing out User '${user}' from => Channel: '${channel}', Connection: '${connection}'`), context.activity)
275
- const userTokenClient = await this.getUserTokenClient(context)
276
- await userTokenClient.signOut(user, connection, channel)
277
- return true
231
+ if (!channel || !user) {
232
+ throw ExceptionHelper.generateException(Error, Errors.ChannelIdAndFromIdRequiredForSignout)
233
+ }
234
+
235
+ logger.debug(this.prefix(`Signing out User '${user}' from => Channel: '${channel}', Connection: '${connection}'`), context.activity)
236
+ const userTokenClient = await this.getUserTokenClient(context)
237
+ await userTokenClient.signOut(user, connection, channel)
238
+ return true
239
+ })
278
240
  }
279
241
 
280
242
  /**
@@ -284,124 +246,180 @@ export class AzureBotAuthorization implements AuthorizationHandler {
284
246
  * @returns The status of the sign-in attempt.
285
247
  */
286
248
  async signin (context: TurnContext, active?: AzureBotActiveHandler): Promise<AuthorizationHandlerStatus> {
287
- const { activity } = context
288
- const [category] = activity.name?.split('/') ?? [Category.UNKNOWN]
249
+ return trace(AuthorizationTraceDefinitions.azureBotSignin, async ({ record, actions }) => {
250
+ const reason = { message: '' }
251
+ let status: AuthorizationHandlerStatus | undefined
252
+ const { activity } = context
253
+ const [category] = activity.name?.split('/') ?? [Category.UNKNOWN]
254
+
255
+ const storage = new HandlerStorage<AzureBotActiveHandler>(this.settings.storage, context)
256
+
257
+ try {
258
+ if (!active) {
259
+ status = await this.setToken(storage, context, undefined, undefined, reason)
260
+ return status
261
+ }
262
+
263
+ logger.debug(this.prefix('Sign-in active session detected'), active.activity)
264
+
265
+ if (active.attemptsLeft <= 0) {
266
+ reason.message = 'Maximum sign-in attempts exceeded'
267
+ logger.warn(this.prefix(reason.message), activity)
268
+ await context.sendActivity(MessageFactory.text(this.messages.maxAttemptsExceeded(this.maxAttempts)))
269
+ status = AuthorizationHandlerStatus.REJECTED
270
+ return status
271
+ }
272
+
273
+ if (category === Category.SIGNIN) {
274
+ await storage.write({ ...active, category })
275
+ status = await this.handleSignInActivities(context, reason)
276
+ if (status !== AuthorizationHandlerStatus.IGNORED) {
277
+ return status
278
+ }
279
+ } else if (active.category === Category.SIGNIN && activity.channelId === Channels.Msteams) {
280
+ // Specific to MS Teams, M365 does not send signin/verifyState when user consent is required.
281
+ // This is only for safety in case of unexpected behaviors during the MS Teams sign-in process,
282
+ // e.g., user interrupts the flow by clicking the Consent Cancel button.
283
+ reason.message = 'The incoming activity will be revalidated due to a change in the sign-in flow'
284
+ logger.warn(this.prefix(reason.message), activity)
285
+ status = AuthorizationHandlerStatus.REVALIDATE
286
+ return status
287
+ }
288
+
289
+ const verification = await this.codeVerification(storage, context, active, reason)
290
+ status = verification.status
291
+ if (status !== AuthorizationHandlerStatus.APPROVED) {
292
+ return status
293
+ }
294
+
295
+ try {
296
+ const result = await this.setToken(storage, context, active, verification.code, reason)
297
+ status = result
298
+ if (result !== AuthorizationHandlerStatus.APPROVED) {
299
+ await sendInvokeResponse(context, { status: 404 })
300
+ return result
301
+ }
302
+
303
+ await sendInvokeResponse(context, { status: 200 })
304
+ await this._onSuccess?.(context)
305
+ return result
306
+ } catch (error) {
307
+ await sendInvokeResponse(context, { status: 500 })
308
+ if (error instanceof Error) {
309
+ error.message = this.prefix(error.message)
310
+ }
311
+ throw error
312
+ }
313
+ } finally {
314
+ await actions.link(storage)
315
+ record({
316
+ handlerId: this.id,
317
+ status: status ?? 'unknown',
318
+ statusReason: reason.message,
319
+ connectionName: this.options.azureBotOAuthConnectionName ?? 'unknown'
320
+ })
321
+ }
322
+ })
323
+ }
289
324
 
290
- const storage = new HandlerStorage<AzureBotActiveHandler>(this.settings.storage, context)
325
+ /**
326
+ * Retrieves the base token from the turn state or the user token client.
327
+ * @param context The turn context.
328
+ * @returns The token string or undefined if not available.
329
+ */
330
+ private async getBaseToken (context: TurnContext) {
331
+ const { token } = this.getContext(context)
291
332
 
292
- if (!active) {
293
- return this.setToken(storage, context)
333
+ if (!token?.trim()) {
334
+ const { activity } = context
335
+ const userTokenClient = await this.getUserTokenClient(context)
336
+ // Using getTokenOrSignInResource instead of getUserToken to avoid HTTP 404 errors.
337
+ const { tokenResponse } = await userTokenClient.getTokenOrSignInResource(activity.from?.id!, this.options.azureBotOAuthConnectionName!, activity.channelId!, activity.getConversationReference(), activity.relatesTo!, '')
338
+ return tokenResponse?.token
294
339
  }
295
340
 
296
- logger.debug(this.prefix('Sign-in active session detected'), active.activity)
297
-
298
- if (active.attemptsLeft <= 0) {
299
- logger.warn(this.prefix('Maximum sign-in attempts exceeded'), activity)
300
- await context.sendActivity(MessageFactory.text(this.messages.maxAttemptsExceeded(this.maxAttempts)))
301
- return AuthorizationHandlerStatus.REJECTED
302
- }
341
+ return token
342
+ }
303
343
 
304
- if (category === Category.SIGNIN) {
305
- await storage.write({ ...active, category })
306
- const status = await this.handleSignInActivities(context)
307
- if (status !== AuthorizationHandlerStatus.IGNORED) {
308
- return status
344
+ /**
345
+ * Acquires an on-behalf-of token for the user based on the provided scopes and connection.
346
+ */
347
+ private async getOBOToken (context: TurnContext, oboConnection: string | undefined, oboScopes: string[]) {
348
+ return trace(AuthorizationTraceDefinitions.azureBotOBOToken, async ({ record }) => {
349
+ record({ handlerId: this.id, connectionName: oboConnection, authScopes: oboScopes })
350
+ const token = await this.getBaseToken(context)
351
+ if (!token) {
352
+ return
309
353
  }
310
- } else if (active.category === Category.SIGNIN && activity.channelId === Channels.Msteams) {
311
- // Specific to MS Teams, M365 does not send signin/verifyState when user consent is required.
312
- // This is only for safety in case of unexpected behaviors during the MS Teams sign-in process,
313
- // e.g., user interrupts the flow by clicking the Consent Cancel button.
314
- logger.warn(this.prefix('The incoming activity will be revalidated due to a change in the sign-in flow'), activity)
315
- return AuthorizationHandlerStatus.REVALIDATE
316
- }
317
354
 
318
- const { status, code } = await this.codeVerification(storage, context, active)
319
- if (status !== AuthorizationHandlerStatus.APPROVED) {
320
- return status
321
- }
322
-
323
- try {
324
- const result = await this.setToken(storage, context, active, code)
325
- if (result !== AuthorizationHandlerStatus.APPROVED) {
326
- await this.sendInvokeResponse(context, { status: 404 })
327
- return result
355
+ if (!this.isExchangeable(token)) {
356
+ throw ExceptionHelper.generateException(Error, Errors.AzureBotConnectionTokenNotExchangeable, undefined, { connectionName: this.options.azureBotOAuthConnectionName! })
328
357
  }
329
358
 
330
- await this.sendInvokeResponse(context, { status: 200 })
331
- await this._onSuccess?.(context)
332
- return result
333
- } catch (error) {
334
- await this.sendInvokeResponse(context, { status: 500 })
335
- if (error instanceof Error) {
336
- error.message = this.prefix(error.message)
359
+ try {
360
+ const provider = oboConnection ? this.settings.connections.getConnection(oboConnection) : this.settings.connections.getDefaultConnection()
361
+ // Record the connection name again in case it changes.
362
+ record({ connectionName: provider?.connectionSettings?.connectionName ?? oboConnection })
363
+ const newToken = await provider.acquireTokenOnBehalfOf(oboScopes, token)
364
+ logger.debug(this.prefix('Successfully acquired on-behalf-of token'), { connection: oboConnection, scopes: oboScopes })
365
+ return newToken
366
+ } catch (error) {
367
+ logger.error(this.prefix('Failed to exchange on-behalf-of token'), { connection: oboConnection, scopes: oboScopes }, error)
368
+ throw error
337
369
  }
338
- throw error
339
- }
370
+ })
340
371
  }
341
372
 
342
373
  /**
343
- * Handles on-behalf-of token acquisition.
374
+ * Checks if a token is exchangeable for an on-behalf-of flow.
344
375
  */
345
- private async handleOBO (token:string, options?: AuthorizationHandlerTokenOptions): Promise<TokenResponse> {
346
- const oboConnection = options?.connection ?? this._options.obo?.connection
347
- const oboScopes = options?.scopes && options.scopes.length > 0 ? options.scopes : this._options.obo?.scopes
348
-
349
- if (!oboScopes || oboScopes.length === 0) {
350
- return { token }
351
- }
352
-
353
- if (!this.isExchangeable(token)) {
354
- throw new Error(this.prefix('The current token is not exchangeable for an on-behalf-of flow. Ensure the token audience starts with \'api://\'.'))
376
+ private isExchangeable (token: string | undefined): boolean {
377
+ if (!token || typeof token !== 'string') {
378
+ return false
355
379
  }
356
380
 
357
- try {
358
- const provider = oboConnection ? this.settings.connections.getConnection(oboConnection) : this.settings.connections.getDefaultConnection()
359
- const newToken = await provider.acquireTokenOnBehalfOf(oboScopes, token)
360
- logger.debug(this.prefix('Successfully acquired on-behalf-of token'), { connection: oboConnection, scopes: oboScopes })
361
- return { token: newToken }
362
- } catch (error) {
363
- logger.error(this.prefix('Failed to exchange on-behalf-of token'), { connection: oboConnection, scopes: oboScopes }, error)
364
- return { token: undefined }
381
+ const payload = jwt.decode(token)
382
+ if (!payload || typeof payload === 'string') {
383
+ return false
365
384
  }
366
- }
367
385
 
368
- /**
369
- * Checks if a token is exchangeable for an on-behalf-of flow.
370
- */
371
- private isExchangeable (token: string | undefined): boolean {
372
- if (!token || typeof token !== 'string') {
386
+ const appid = payload.azp ?? payload.appid
387
+ if (typeof appid !== 'string' || appid.length === 0) {
373
388
  return false
374
389
  }
375
- const payload = jwt.decode(token) as JwtPayload
390
+
376
391
  const audiences = Array.isArray(payload.aud) ? payload.aud : [payload.aud]
377
- return audiences.some(aud => typeof aud === 'string' && aud.startsWith('api://'))
392
+ return audiences.some(aud => typeof aud === 'string' && aud.includes(appid))
378
393
  }
379
394
 
380
395
  /**
381
396
  * Sets the token from the token response or initiates the sign-in flow.
382
397
  */
383
- private async setToken (storage: HandlerStorage<AzureBotActiveHandler>, context: TurnContext, active?: AzureBotActiveHandler, code?: string): Promise<AuthorizationHandlerStatus> {
398
+ private async setToken (storage: HandlerStorage<AzureBotActiveHandler>, context: TurnContext, active?: AzureBotActiveHandler, code?: string, reason: { message: string } = { message: '' }): Promise<AuthorizationHandlerStatus> {
384
399
  const { activity } = context
385
400
 
386
401
  const userTokenClient = await this.getUserTokenClient(context)
387
- const { tokenResponse, signInResource } = await userTokenClient.getTokenOrSignInResource(activity.from?.id!, this._options.name!, activity.channelId!, activity.getConversationReference(), activity.relatesTo!, code ?? '')
402
+ const { tokenResponse, signInResource } = await userTokenClient.getTokenOrSignInResource(activity.from?.id!, this.options.azureBotOAuthConnectionName!, activity.channelId!, activity.getConversationReference(), activity.relatesTo!, code ?? '')
388
403
 
389
- if (!tokenResponse && active) {
390
- logger.warn(this.prefix('Invalid code entered. Restarting sign-in flow'), activity)
391
- await context.sendActivity(MessageFactory.text(this.messages.invalidCode(code ?? '')))
404
+ if (!tokenResponse && active && code) {
405
+ reason.message = 'Invalid code entered. Restarting sign-in flow'
406
+ logger.warn(this.prefix(reason.message), activity)
407
+ await context.sendActivity(MessageFactory.text(this.messages.invalidCode(code)))
392
408
  return AuthorizationHandlerStatus.REJECTED
393
409
  }
394
410
 
395
411
  if (!tokenResponse) {
396
- logger.debug(this.prefix('Cannot find token. Sending sign-in card'), activity)
412
+ reason.message = 'Cannot find token. Sending sign-in card'
413
+ logger.debug(this.prefix(reason.message), activity)
397
414
 
398
- const oCard = CardFactory.oauthCard(this._options.name!, this._options.title!, this._options.text!, signInResource, this._options.enableSso)
415
+ const oCard = CardFactory.oauthCard(this.options.azureBotOAuthConnectionName!, this.options.title!, this.options.text!, signInResource, this.options.enableSso)
399
416
  await context.sendActivity(MessageFactory.attachment(oCard))
400
417
  await storage.write({ activity, id: this.id, ...(active ?? {}), attemptsLeft: this.maxAttempts })
401
418
  return AuthorizationHandlerStatus.PENDING
402
419
  }
403
420
 
404
- logger.debug(this.prefix('Successfully acquired token'), activity)
421
+ reason.message = 'Successfully acquired token'
422
+ logger.debug(this.prefix(reason.message), activity)
405
423
  this.setContext(context, { token: tokenResponse.token })
406
424
  return AuthorizationHandlerStatus.APPROVED
407
425
  }
@@ -409,7 +427,7 @@ export class AzureBotAuthorization implements AuthorizationHandler {
409
427
  /**
410
428
  * Handles sign-in related activities.
411
429
  */
412
- private async handleSignInActivities (context: TurnContext): Promise<AuthorizationHandlerStatus> {
430
+ private async handleSignInActivities (context: TurnContext, reason: { message: string }): Promise<AuthorizationHandlerStatus> {
413
431
  const { activity } = context
414
432
 
415
433
  // Ignore signin/verifyState here (handled in codeVerification).
@@ -424,69 +442,71 @@ export class AzureBotAuthorization implements AuthorizationHandler {
424
442
  const tokenExchangeRequest: TokenExchangeRequest = { token: tokenExchangeInvokeRequest?.token }
425
443
 
426
444
  if (!tokenExchangeRequest?.token) {
427
- const reason = 'The Agent received an InvokeActivity that is missing a TokenExchangeInvokeRequest value. This is required to be sent with the InvokeActivity.'
428
- await this.sendInvokeResponse<TokenExchangeInvokeResponse>(context, {
445
+ reason.message = 'The Agent received an InvokeActivity that is missing a TokenExchangeInvokeRequest value. This is required to be sent with the InvokeActivity.'
446
+ await sendInvokeResponse<TokenExchangeInvokeResponse>(context, {
429
447
  status: 400,
430
- body: { connectionName: this._options.name!, failureDetail: reason }
448
+ body: { connectionName: this.options.azureBotOAuthConnectionName!, failureDetail: reason.message }
431
449
  })
432
- logger.error(this.prefix(reason))
433
- await this._onFailure?.(context, reason)
450
+ logger.error(this.prefix(reason.message))
451
+ await this._onFailure?.(context, reason.message)
434
452
  return AuthorizationHandlerStatus.REJECTED
435
453
  }
436
454
 
437
- if (tokenExchangeInvokeRequest.connectionName !== this._options.name) {
438
- const reason = `The Agent received an InvokeActivity with a TokenExchangeInvokeRequest for a different connection name ('${tokenExchangeInvokeRequest.connectionName}') than expected ('${this._options.name}').`
439
- await this.sendInvokeResponse<TokenExchangeInvokeResponse>(context, {
455
+ if (tokenExchangeInvokeRequest.connectionName !== this.options.azureBotOAuthConnectionName) {
456
+ reason.message = `The Agent received an InvokeActivity with a TokenExchangeInvokeRequest for a different connection name ('${tokenExchangeInvokeRequest.connectionName}') than expected ('${this.options.azureBotOAuthConnectionName}').`
457
+ await sendInvokeResponse<TokenExchangeInvokeResponse>(context, {
440
458
  status: 400,
441
- body: { id: tokenExchangeInvokeRequest.id, connectionName: this._options.name!, failureDetail: reason }
459
+ body: { id: tokenExchangeInvokeRequest.id, connectionName: this.options.azureBotOAuthConnectionName!, failureDetail: reason.message }
442
460
  })
443
- logger.error(this.prefix(reason))
444
- await this._onFailure?.(context, reason)
461
+ logger.error(this.prefix(reason.message))
462
+ await this._onFailure?.(context, reason.message)
445
463
  return AuthorizationHandlerStatus.REJECTED
446
464
  }
447
465
 
448
- const { token } = await userTokenClient.exchangeTokenAsync(activity.from?.id!, this._options.name!, activity.channelId!, tokenExchangeRequest)
466
+ const { token } = await userTokenClient.exchangeTokenAsync(activity.from?.id!, this.options.azureBotOAuthConnectionName!, activity.channelId!, tokenExchangeRequest)
449
467
  if (!token) {
450
- const reason = 'The MS Teams token service didn\'t send back the exchanged token. Waiting for MS Teams to send another signin/tokenExchange request. After multiple failed attempts, the user will be asked to enter the magic code.'
451
- await this.sendInvokeResponse<TokenExchangeInvokeResponse>(context, {
468
+ reason.message = 'The MS Teams token service didn\'t send back the exchanged token. Waiting for MS Teams to send another signin/tokenExchange request. After multiple failed attempts, the user will be asked to enter the magic code.'
469
+ await sendInvokeResponse<TokenExchangeInvokeResponse>(context, {
452
470
  status: 412,
453
- body: { id: tokenExchangeInvokeRequest.id, connectionName: this._options.name!, failureDetail: reason }
471
+ body: { id: tokenExchangeInvokeRequest.id, connectionName: this.options.azureBotOAuthConnectionName, failureDetail: reason.message }
454
472
  })
455
- logger.debug(this.prefix(reason))
473
+ logger.debug(this.prefix(reason.message))
456
474
  return AuthorizationHandlerStatus.PENDING
457
475
  }
458
476
 
459
- await this.sendInvokeResponse<TokenExchangeInvokeResponse>(context, {
477
+ await sendInvokeResponse<TokenExchangeInvokeResponse>(context, {
460
478
  status: 200,
461
- body: { id: tokenExchangeInvokeRequest.id, connectionName: this._options.name! }
479
+ body: { id: tokenExchangeInvokeRequest.id, connectionName: this.options.azureBotOAuthConnectionName! }
462
480
  })
463
- logger.debug(this.prefix('Successfully exchanged token'))
481
+ reason.message = 'Successfully exchanged token'
482
+ logger.debug(this.prefix(reason.message))
464
483
  this.setContext(context, { token })
465
484
  await this._onSuccess?.(context)
466
485
  return AuthorizationHandlerStatus.APPROVED
467
486
  }
468
487
 
469
488
  if (activity.name === 'signin/failure') {
470
- await this.sendInvokeResponse(context, { status: 200 })
471
- const reason = 'Failed to sign-in'
489
+ await sendInvokeResponse(context, { status: 200 })
490
+ reason.message = 'Failed to sign-in'
472
491
  const value = activity.value as SignInFailureValue
473
- logger.error(this.prefix(reason), value, activity)
492
+ logger.error(this.prefix(reason.message), value, activity)
474
493
  if (this._onFailure) {
475
- await this._onFailure(context, value.message || reason)
494
+ await this._onFailure(context, value.message || reason.message)
476
495
  } else {
477
- await context.sendActivity(MessageFactory.text(`${reason}. Please try again.`))
496
+ await context.sendActivity(MessageFactory.text(`${reason.message}. Please try again.`))
478
497
  }
479
498
  return AuthorizationHandlerStatus.REJECTED
480
499
  }
481
500
 
482
- logger.error(this.prefix(`Unknown sign-in activity name: ${activity.name}`), activity)
501
+ reason.message = `Unknown sign-in activity name: ${activity.name}`
502
+ logger.error(this.prefix(reason.message), activity)
483
503
  return AuthorizationHandlerStatus.REJECTED
484
504
  }
485
505
 
486
506
  /**
487
507
  * Verifies the magic code provided by the user.
488
508
  */
489
- private async codeVerification (storage: HandlerStorage<AzureBotActiveHandler>, context: TurnContext, active?: AzureBotActiveHandler): Promise<{ status: AuthorizationHandlerStatus, code?: string }> {
509
+ private async codeVerification (storage: HandlerStorage<AzureBotActiveHandler>, context: TurnContext, active?: AzureBotActiveHandler, reason: { message: string } = { message: '' }): Promise<{ status: AuthorizationHandlerStatus, code?: string }> {
490
510
  if (!active) {
491
511
  logger.debug(this.prefix('No active session found. Skipping code verification.'), context.activity)
492
512
  return { status: AuthorizationHandlerStatus.IGNORED }
@@ -502,20 +522,23 @@ export class AzureBotAuthorization implements AuthorizationHandler {
502
522
  }
503
523
 
504
524
  if (state === 'CancelledByUser') {
505
- await this.sendInvokeResponse(context, { status: 200 })
506
- logger.warn(this.prefix('Sign-in process was cancelled by the user'), activity)
525
+ await sendInvokeResponse(context, { status: 200 })
526
+ reason.message = 'Sign-in process was cancelled by the user'
527
+ logger.warn(this.prefix(reason.message), activity)
507
528
  return { status: AuthorizationHandlerStatus.REJECTED }
508
529
  }
509
530
 
510
531
  if (!state?.match(/^\d{6}$/)) {
511
- logger.warn(this.prefix(`Invalid magic code entered. Attempts left: ${active.attemptsLeft}`), activity)
532
+ reason.message = `Invalid magic code entered. Attempts left: ${active.attemptsLeft}`
533
+ logger.warn(this.prefix(reason.message), activity)
512
534
  await context.sendActivity(MessageFactory.text(this.messages.invalidCodeFormat(active.attemptsLeft)))
513
535
  await storage.write({ ...active, attemptsLeft: active.attemptsLeft - 1 })
514
536
  return { status: AuthorizationHandlerStatus.PENDING }
515
537
  }
516
538
 
517
- await this.sendInvokeResponse(context, { status: 200 })
518
- logger.debug(this.prefix('Code verification successful'), activity)
539
+ await sendInvokeResponse(context, { status: 200 })
540
+ reason.message = 'Code verification successful'
541
+ logger.debug(this.prefix(reason.message), activity)
519
542
  return { status: AuthorizationHandlerStatus.APPROVED, code: state }
520
543
  }
521
544
 
@@ -542,25 +565,11 @@ export class AzureBotAuthorization implements AuthorizationHandler {
542
565
  private async getUserTokenClient (context: TurnContext): Promise<UserTokenClient> {
543
566
  const userTokenClient = context.turnState.get<UserTokenClient>(context.adapter.UserTokenClientKey)
544
567
  if (!userTokenClient) {
545
- throw new Error(this.prefix('The \'userTokenClient\' is not available in the adapter. Ensure that the adapter supports user token operations.'))
568
+ throw ExceptionHelper.generateException(Error, Errors.UserTokenClientNotAvailable)
546
569
  }
547
570
  return userTokenClient
548
571
  }
549
572
 
550
- /**
551
- * Sends an InvokeResponse activity if the channel is Microsoft Teams, including Copilot within MS Teams.
552
- */
553
- private sendInvokeResponse <T>(context: TurnContext, response: InvokeResponse<T>) {
554
- if (context.activity.channelIdChannel !== Channels.Msteams) {
555
- return Promise.resolve()
556
- }
557
-
558
- return context.sendActivity(Activity.fromObject({
559
- type: ActivityTypes.InvokeResponse,
560
- value: response
561
- }))
562
- }
563
-
564
573
  /**
565
574
  * Prefixes a message with the handler ID.
566
575
  */
@@ -573,29 +582,16 @@ export class AzureBotAuthorization implements AuthorizationHandler {
573
582
  */
574
583
  private messages = {
575
584
  invalidCode: (code: string) => {
576
- const message = this._options.messages?.invalidCode ?? 'Invalid **{code}** code entered. Please try again with a new sign-in request.'
585
+ const message = this.options.invalidSignInRetryMessage ?? 'Invalid **{code}** code entered. Please try again with a new sign-in request.'
577
586
  return message.replaceAll('{code}', code)
578
587
  },
579
588
  invalidCodeFormat: (attemptsLeft: number) => {
580
- const message = this._options.messages?.invalidCodeFormat ?? 'Please enter a valid **6-digit** code format (_e.g. 123456_).\r\n**{attemptsLeft} attempt(s) left...**'
589
+ const message = this.options.invalidSignInRetryMessageFormat ?? 'Please enter a valid **6-digit** code format (_e.g. 123456_).\r\n**{attemptsLeft} attempt(s) left...**'
581
590
  return message.replaceAll('{attemptsLeft}', attemptsLeft.toString())
582
591
  },
583
592
  maxAttemptsExceeded: (maxAttempts: number) => {
584
- const message = this._options.messages?.maxAttemptsExceeded ?? 'You have exceeded the maximum number of sign-in attempts ({maxAttempts}). Please try again with a new sign-in request.'
593
+ const message = this.options.invalidSignInRetryMaxExceededMessage ?? 'You have exceeded the maximum number of sign-in attempts ({maxAttempts}). Please try again with a new sign-in request.'
585
594
  return message.replaceAll('{maxAttempts}', maxAttempts.toString())
586
595
  },
587
596
  }
588
-
589
- /**
590
- * Loads the OAuth scopes from the environment variables.
591
- */
592
- private loadScopes (value:string | undefined): string[] {
593
- return value?.split(',').reduce<string[]>((acc, scope) => {
594
- const trimmed = scope.trim()
595
- if (trimmed) {
596
- acc.push(trimmed)
597
- }
598
- return acc
599
- }, []) ?? []
600
- }
601
597
  }