@microsoft/agents-hosting 0.5.12-g2d752e9b13 → 0.5.19-gc1e2ea1096

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 (58) hide show
  1. package/dist/src/app/agentApplication.d.ts +186 -20
  2. package/dist/src/app/agentApplication.js +234 -32
  3. package/dist/src/app/agentApplication.js.map +1 -1
  4. package/dist/src/app/agentApplicationBuilder.d.ts +1 -1
  5. package/dist/src/app/agentApplicationOptions.d.ts +1 -1
  6. package/dist/src/app/appRoute.d.ts +5 -0
  7. package/dist/src/app/authorization.d.ts +294 -0
  8. package/dist/src/app/authorization.js +379 -0
  9. package/dist/src/app/authorization.js.map +1 -0
  10. package/dist/src/app/index.d.ts +1 -1
  11. package/dist/src/app/index.js +1 -1
  12. package/dist/src/app/index.js.map +1 -1
  13. package/dist/src/app/streaming/streamingResponse.js +1 -1
  14. package/dist/src/app/streaming/streamingResponse.js.map +1 -1
  15. package/dist/src/auth/authConfiguration.d.ts +2 -2
  16. package/dist/src/auth/authConfiguration.js +36 -17
  17. package/dist/src/auth/authConfiguration.js.map +1 -1
  18. package/dist/src/auth/index.d.ts +1 -0
  19. package/dist/src/auth/index.js +1 -0
  20. package/dist/src/auth/index.js.map +1 -1
  21. package/dist/src/auth/jwt-middleware.js.map +1 -1
  22. package/dist/src/auth/msalTokenCredential.d.ts +10 -0
  23. package/dist/src/auth/msalTokenCredential.js +19 -0
  24. package/dist/src/auth/msalTokenCredential.js.map +1 -0
  25. package/dist/src/auth/msalTokenProvider.d.ts +1 -0
  26. package/dist/src/auth/msalTokenProvider.js +15 -0
  27. package/dist/src/auth/msalTokenProvider.js.map +1 -1
  28. package/dist/src/baseAdapter.d.ts +1 -1
  29. package/dist/src/baseAdapter.js +0 -4
  30. package/dist/src/baseAdapter.js.map +1 -1
  31. package/dist/src/cloudAdapter.d.ts +1 -0
  32. package/dist/src/cloudAdapter.js.map +1 -1
  33. package/dist/src/oauth/oAuthFlow.d.ts +53 -9
  34. package/dist/src/oauth/oAuthFlow.js +164 -35
  35. package/dist/src/oauth/oAuthFlow.js.map +1 -1
  36. package/dist/src/oauth/userTokenClient.js +4 -0
  37. package/dist/src/oauth/userTokenClient.js.map +1 -1
  38. package/package.json +4 -3
  39. package/src/app/agentApplication.ts +247 -32
  40. package/src/app/agentApplicationBuilder.ts +1 -1
  41. package/src/app/agentApplicationOptions.ts +1 -1
  42. package/src/app/appRoute.ts +6 -0
  43. package/src/app/authorization.ts +424 -0
  44. package/src/app/index.ts +1 -1
  45. package/src/app/streaming/streamingResponse.ts +1 -1
  46. package/src/auth/authConfiguration.ts +36 -19
  47. package/src/auth/index.ts +1 -0
  48. package/src/auth/jwt-middleware.ts +1 -1
  49. package/src/auth/msalTokenCredential.ts +14 -0
  50. package/src/auth/msalTokenProvider.ts +17 -1
  51. package/src/baseAdapter.ts +1 -1
  52. package/src/cloudAdapter.ts +2 -2
  53. package/src/oauth/oAuthFlow.ts +197 -35
  54. package/src/oauth/userTokenClient.ts +3 -0
  55. package/dist/src/app/oauth/authorization.d.ts +0 -88
  56. package/dist/src/app/oauth/authorization.js +0 -134
  57. package/dist/src/app/oauth/authorization.js.map +0 -1
  58. package/src/app/oauth/authorization.ts +0 -160
@@ -1,26 +1,44 @@
1
1
  // Copyright (c) Microsoft Corporation. All rights reserved.
2
2
  // Licensed under the MIT License.
3
3
  import { debug } from './../logger'
4
- import { ActivityTypes, Attachment } from '@microsoft/agents-activity'
4
+ import { Activity, ActivityTypes, Attachment } from '@microsoft/agents-activity'
5
5
  import {
6
6
  CardFactory,
7
7
  TurnContext,
8
8
  Storage,
9
- MessageFactory,
9
+ MessageFactory
10
10
  } from '../'
11
11
  import { UserTokenClient } from './userTokenClient'
12
12
  import { TokenExchangeRequest, TokenResponse } from './userTokenClient.types'
13
13
 
14
14
  const logger = debug('agents:oauth-flow')
15
15
 
16
+ /**
17
+ * Represents the state of the OAuth flow.
18
+ * @interface FlowState
19
+ */
16
20
  export interface FlowState {
17
- flowStarted: boolean,
18
- flowExpires: number
21
+ /** Indicates whether the OAuth flow has been started */
22
+ flowStarted: boolean | undefined,
23
+ /** Timestamp when the OAuth flow expires (in milliseconds since epoch) */
24
+ flowExpires: number | undefined,
25
+ /** The absolute OAuth connection name used for the flow, null if not set */
26
+ absOauthConnectionName: string
27
+ /** Optional activity to continue the flow with, used for multi-turn scenarios */
28
+ continuationActivity?: Activity | null
29
+
30
+ eTag?: string // Optional ETag for optimistic concurrency control
19
31
  }
20
32
 
21
33
  interface TokenVerifyState {
22
34
  state: string
23
35
  }
36
+
37
+ interface CachedToken {
38
+ token: TokenResponse
39
+ expiresAt: number
40
+ }
41
+
24
42
  /**
25
43
  * Manages the OAuth flow
26
44
  */
@@ -40,6 +58,11 @@ export class OAuthFlow {
40
58
  */
41
59
  tokenExchangeId: string | null = null
42
60
 
61
+ /**
62
+ * In-memory cache for tokens with expiration.
63
+ */
64
+ private tokenCache: Map<string, CachedToken> = new Map()
65
+
43
66
  /**
44
67
  * The name of the OAuth connection.
45
68
  */
@@ -57,10 +80,14 @@ export class OAuthFlow {
57
80
 
58
81
  /**
59
82
  * Creates a new instance of OAuthFlow.
60
- * @param userState The user state.
83
+ * @param storage The storage provider for persisting flow state.
84
+ * @param absOauthConnectionName The absolute OAuth connection name.
85
+ * @param tokenClient Optional user token client. If not provided, will be initialized automatically.
86
+ * @param cardTitle Optional title for the OAuth card. Defaults to 'Sign in'.
87
+ * @param cardText Optional text for the OAuth card. Defaults to 'login'.
61
88
  */
62
89
  constructor (private storage: Storage, absOauthConnectionName: string, tokenClient?: UserTokenClient, cardTitle?: string, cardText?: string) {
63
- this.state = { flowExpires: 0, flowStarted: false }
90
+ this.state = { flowStarted: undefined, flowExpires: undefined, absOauthConnectionName }
64
91
  this.absOauthConnectionName = absOauthConnectionName
65
92
  this.userTokenClient = tokenClient ?? null!
66
93
  this.cardTitle = cardTitle ?? this.cardTitle
@@ -68,29 +95,50 @@ export class OAuthFlow {
68
95
  }
69
96
 
70
97
  /**
71
- * Retrieves the user token from the user token service.
98
+ * Retrieves the user token from the user token service with in-memory caching for 10 minutes.
72
99
  * @param context The turn context containing the activity information.
73
100
  * @returns A promise that resolves to the user token response.
74
101
  * @throws Will throw an error if the channelId or from properties are not set in the activity.
75
102
  */
76
103
  public async getUserToken (context: TurnContext): Promise<TokenResponse> {
77
104
  await this.initializeTokenClient(context)
78
- logger.info('Get token from user token service')
79
105
  const activity = context.activity
80
- if (activity.channelId && activity.from && activity.from.id) {
81
- return await this.userTokenClient.getUserToken(this.absOauthConnectionName, activity.channelId, activity.from.id)
82
- } else {
106
+
107
+ if (!activity.channelId || !activity.from || !activity.from.id) {
83
108
  throw new Error('UserTokenService requires channelId and from to be set')
84
109
  }
110
+
111
+ const cacheKey = this.getCacheKey(context)
112
+
113
+ const cachedEntry = this.tokenCache.get(cacheKey)
114
+ if (cachedEntry && Date.now() < cachedEntry.expiresAt) {
115
+ logger.info(`Returning cached token for user with cache key: ${cacheKey}`)
116
+ return cachedEntry.token
117
+ }
118
+
119
+ logger.info('Get token from user token service')
120
+ const tokenResponse = await this.userTokenClient.getUserToken(this.absOauthConnectionName, activity.channelId, activity.from.id)
121
+
122
+ // Cache the token if it's valid (has a token value)
123
+ if (tokenResponse && tokenResponse.token) {
124
+ const cacheExpiry = Date.now() + (10 * 60 * 1000) // 10 minutes from now
125
+ this.tokenCache.set(cacheKey, {
126
+ token: tokenResponse,
127
+ expiresAt: cacheExpiry
128
+ })
129
+ logger.info('Token cached for 10 minutes')
130
+ }
131
+
132
+ return tokenResponse
85
133
  }
86
134
 
87
135
  /**
88
136
  * Begins the OAuth flow.
89
137
  * @param context The turn context.
90
- * @returns A promise that resolves to the user token.
138
+ * @returns A promise that resolves to the user token if available, or undefined if OAuth flow needs to be started.
91
139
  */
92
140
  public async beginFlow (context: TurnContext): Promise<TokenResponse | undefined> {
93
- this.state = await this.getUserState(context)
141
+ this.state = await this.getFlowState(context)
94
142
  if (this.absOauthConnectionName === '') {
95
143
  throw new Error('connectionName is not set')
96
144
  }
@@ -98,40 +146,87 @@ export class OAuthFlow {
98
146
  await this.initializeTokenClient(context)
99
147
 
100
148
  const act = context.activity
149
+
150
+ // Check cache first before starting OAuth flow
151
+ if (act.channelId && act.from && act.from.id) {
152
+ const cacheKey = this.getCacheKey(context)
153
+ const cachedEntry = this.tokenCache.get(cacheKey)
154
+ if (cachedEntry && Date.now() < cachedEntry.expiresAt) {
155
+ logger.info(`Returning cached token for user in beginFlow with cache key: ${cacheKey}`)
156
+ return cachedEntry.token
157
+ }
158
+ }
159
+
101
160
  const output = await this.userTokenClient.getTokenOrSignInResource(act.from?.id!, this.absOauthConnectionName, act.channelId!, act.getConversationReference(), act.relatesTo!, undefined!)
102
161
  if (output && output.tokenResponse) {
103
- this.state.flowStarted = false
104
- this.state.flowExpires = 0
105
- await this.storage.write({ [this.getFlowStateKey(context)]: this.state })
162
+ // Cache the token if it's valid
163
+ if (act.channelId && act.from && act.from.id) {
164
+ const cacheKey = this.getCacheKey(context)
165
+ const cacheExpiry = Date.now() + (10 * 60 * 1000) // 10 minutes from now
166
+ this.tokenCache.set(cacheKey, {
167
+ token: output.tokenResponse,
168
+ expiresAt: cacheExpiry
169
+ })
170
+ logger.info('Token cached for 10 minutes in beginFlow')
171
+ this.state = { flowStarted: false, flowExpires: 0, absOauthConnectionName: this.absOauthConnectionName }
172
+ }
173
+ logger.info('Token retrieved successfully')
106
174
  return output.tokenResponse
107
175
  }
108
176
  const oCard: Attachment = CardFactory.oauthCard(this.absOauthConnectionName, this.cardTitle, this.cardText, output.signInResource)
109
177
  await context.sendActivity(MessageFactory.attachment(oCard))
110
- this.state.flowStarted = true
111
- this.state.flowExpires = Date.now() + 30000
178
+ this.state = { flowStarted: true, flowExpires: Date.now() + 60 * 5 * 1000, absOauthConnectionName: this.absOauthConnectionName }
112
179
  await this.storage.write({ [this.getFlowStateKey(context)]: this.state })
180
+ logger.info('OAuth card sent, flow started')
113
181
  return undefined
114
182
  }
115
183
 
116
184
  /**
117
185
  * Continues the OAuth flow.
118
186
  * @param context The turn context.
119
- * @returns A promise that resolves to the user token.
187
+ * @returns A promise that resolves to the user token response.
120
188
  */
121
189
  public async continueFlow (context: TurnContext): Promise<TokenResponse> {
122
- this.state = await this.getUserState(context)
190
+ this.state = await this.getFlowState(context)
123
191
  await this.initializeTokenClient(context)
124
- if (this.state?.flowExpires !== 0 && Date.now() > this.state!.flowExpires) {
192
+ if (this.state?.flowExpires !== 0 && Date.now() > this.state?.flowExpires!) {
125
193
  logger.warn('Flow expired')
126
- this.state!.flowStarted = false
127
194
  await context.sendActivity(MessageFactory.text('Sign-in session expired. Please try again.'))
195
+ this.state!.flowStarted = false
128
196
  return { token: undefined }
129
197
  }
130
198
  const contFlowActivity = context.activity
131
199
  if (contFlowActivity.type === ActivityTypes.Message) {
132
200
  const magicCode = contFlowActivity.text as string
133
- const result = await this.userTokenClient?.getUserToken(this.absOauthConnectionName, contFlowActivity.channelId!, contFlowActivity.from?.id!, magicCode)!
134
- return result
201
+ if (magicCode.match(/^\d{6}$/)) {
202
+ const result = await this.userTokenClient?.getUserToken(this.absOauthConnectionName, contFlowActivity.channelId!, contFlowActivity.from?.id!, magicCode)!
203
+ if (result && result.token) {
204
+ // Cache the token if it's valid
205
+ if (contFlowActivity.channelId && contFlowActivity.from && contFlowActivity.from.id) {
206
+ const cacheKey = this.getCacheKey(context)
207
+ const cacheExpiry = Date.now() + (10 * 60 * 1000) // 10 minutes from now
208
+ this.tokenCache.set(cacheKey, {
209
+ token: result,
210
+ expiresAt: cacheExpiry
211
+ })
212
+ logger.info('Token cached for 10 minutes in continueFlow (magic code)')
213
+ }
214
+
215
+ await this.storage.delete([this.getFlowStateKey(context)])
216
+ logger.info('Token retrieved successfully')
217
+ return result
218
+ } else {
219
+ // await context.sendActivity(MessageFactory.text('Invalid code. Please try again.'))
220
+ logger.warn('Invalid magic code provided')
221
+ this.state = { flowStarted: true, flowExpires: Date.now() + 30000, absOauthConnectionName: this.absOauthConnectionName }
222
+ await this.storage.write({ [this.getFlowStateKey(context)]: this.state })
223
+ return { token: undefined }
224
+ }
225
+ } else {
226
+ logger.warn('Invalid magic code format')
227
+ await context.sendActivity(MessageFactory.text('Invalid code format. Please enter a 6-digit code.'))
228
+ return { token: undefined }
229
+ }
135
230
  }
136
231
 
137
232
  if (contFlowActivity.type === ActivityTypes.Invoke && contFlowActivity.name === 'signin/verifyState') {
@@ -139,6 +234,16 @@ export class OAuthFlow {
139
234
  const tokenVerifyState = contFlowActivity.value as TokenVerifyState
140
235
  const magicCode = tokenVerifyState.state
141
236
  const result = await this.userTokenClient?.getUserToken(this.absOauthConnectionName, contFlowActivity.channelId!, contFlowActivity.from?.id!, magicCode)!
237
+ // Cache the token if it's valid
238
+ if (result && result.token && contFlowActivity.channelId && contFlowActivity.from && contFlowActivity.from.id) {
239
+ const cacheKey = this.getCacheKey(context)
240
+ const cacheExpiry = Date.now() + (10 * 60 * 1000) // 10 minutes from now
241
+ this.tokenCache.set(cacheKey, {
242
+ token: result,
243
+ expiresAt: cacheExpiry
244
+ })
245
+ logger.info('Token cached for 10 minutes in continueFlow (verifyState)')
246
+ }
142
247
  return result
143
248
  }
144
249
 
@@ -146,11 +251,23 @@ export class OAuthFlow {
146
251
  logger.info('Continuing OAuth flow with tokenExchange')
147
252
  const tokenExchangeRequest = contFlowActivity.value as TokenExchangeRequest
148
253
  if (this.tokenExchangeId === tokenExchangeRequest.id) { // dedupe
254
+ logger.debug('Token exchange request already processed, skipping')
149
255
  return { token: undefined }
150
256
  }
151
257
  this.tokenExchangeId = tokenExchangeRequest.id!
152
258
  const userTokenResp = await this.userTokenClient?.exchangeTokenAsync(contFlowActivity.from?.id!, this.absOauthConnectionName, contFlowActivity.channelId!, tokenExchangeRequest)
153
259
  if (userTokenResp && userTokenResp.token) {
260
+ // Cache the token if it's valid
261
+ if (contFlowActivity.channelId && contFlowActivity.from && contFlowActivity.from.id) {
262
+ const cacheKey = this.getCacheKey(context)
263
+ const cacheExpiry = Date.now() + (10 * 60 * 1000) // 10 minutes from now
264
+ this.tokenCache.set(cacheKey, {
265
+ token: userTokenResp,
266
+ expiresAt: cacheExpiry
267
+ })
268
+ logger.info('Token cached for 10 minutes in continueFlow (tokenExchange)')
269
+ }
270
+
154
271
  logger.info('Token exchanged')
155
272
  this.state!.flowStarted = false
156
273
  await this.storage.write({ [this.getFlowStateKey(context)]: this.state })
@@ -170,34 +287,79 @@ export class OAuthFlow {
170
287
  * @returns A promise that resolves when the sign-out operation is complete.
171
288
  */
172
289
  public async signOut (context: TurnContext): Promise<void> {
173
- this.state = await this.getUserState(context)
174
290
  await this.initializeTokenClient(context)
291
+
292
+ // Clear cached token for this user
293
+ const activity = context.activity
294
+ if (activity.channelId && activity.from && activity.from.id) {
295
+ const cacheKey = this.getCacheKey(context)
296
+ this.tokenCache.delete(cacheKey)
297
+ logger.info('Cached token cleared for user')
298
+ }
299
+
175
300
  await this.userTokenClient?.signOut(context.activity.from?.id as string, this.absOauthConnectionName, context.activity.channelId as string)
176
- this.state!.flowExpires = 0
177
- this.storage.write({ [this.getFlowStateKey(context)]: this.state })
178
- logger.info('User signed out successfully')
301
+ this.state = { flowStarted: false, flowExpires: 0, absOauthConnectionName: this.absOauthConnectionName }
302
+ await this.storage.delete([this.getFlowStateKey(context)])
303
+ logger.info('User signed out successfully from connection:', this.absOauthConnectionName)
179
304
  }
180
305
 
181
306
  /**
182
- * Gets the user state.
307
+ * Gets the user state for the OAuth flow.
183
308
  * @param context The turn context.
184
- * @returns A promise that resolves to the user state.
309
+ * @returns A promise that resolves to the flow state.
185
310
  */
186
- private async getUserState (context: TurnContext) {
311
+ public async getFlowState (context: TurnContext) : Promise<FlowState> {
187
312
  const key = this.getFlowStateKey(context)
188
313
  const data = await this.storage.read([key])
189
- const userProfile: FlowState = data[key] ?? { flowStarted: false, flowExpires: 0 }
190
- return userProfile
314
+ const flowState: FlowState = data[key] // ?? { flowStarted: false, flowExpires: 0 }
315
+ return flowState
191
316
  }
192
317
 
318
+ /**
319
+ * Sets the flow state for the OAuth flow.
320
+ * @param context The turn context.
321
+ * @param flowState The flow state to set.
322
+ * @returns A promise that resolves when the flow state is set.
323
+ */
324
+ public async setFlowState (context: TurnContext, flowState: FlowState) : Promise<void> {
325
+ const key = this.getFlowStateKey(context)
326
+ await this.storage.write({ [key]: flowState })
327
+ this.state = flowState
328
+ logger.info('Flow state set:', flowState)
329
+ }
330
+
331
+ /**
332
+ * Initializes the user token client if not already initialized.
333
+ * @param context The turn context used to get authentication credentials.
334
+ */
193
335
  private async initializeTokenClient (context: TurnContext) {
194
336
  if (this.userTokenClient === undefined || this.userTokenClient === null) {
195
337
  const scope = 'https://api.botframework.com'
196
338
  const accessToken = await context.adapter.authProvider.getAccessToken(context.adapter.authConfig, scope)
197
- this.userTokenClient = new UserTokenClient(accessToken, context.adapter.authConfig.clientId!)
339
+ this.userTokenClient = new UserTokenClient(accessToken, context.adapter.authConfig!.clientId!)
340
+ }
341
+ }
342
+
343
+ /**
344
+ * Generates a cache key for storing user tokens.
345
+ * @param context The turn context containing activity information.
346
+ * @returns The cache key string in format: channelId_userId_connectionName.
347
+ * @throws Will throw an error if required activity properties are missing.
348
+ */
349
+ private getCacheKey (context: TurnContext): string {
350
+ const activity = context.activity
351
+ if (!activity.channelId || !activity.from || !activity.from.id) {
352
+ throw new Error('ChannelId and from.id must be set in the activity for cache key generation')
198
353
  }
354
+ return `${activity.channelId}_${activity.from.id}_${this.absOauthConnectionName}`
199
355
  }
200
356
 
357
+ /**
358
+ * Generates a storage key for persisting OAuth flow state.
359
+ * @param context The turn context containing activity information.
360
+ * @returns The storage key string in format: oauth/channelId/conversationId/userId/flowState.
361
+ * @throws Will throw an error if required activity properties are missing.
362
+ */
201
363
  private getFlowStateKey (context: TurnContext): string {
202
364
  const channelId = context.activity.channelId
203
365
  const conversationId = context.activity.conversation?.id
@@ -205,6 +367,6 @@ export class OAuthFlow {
205
367
  if (!channelId || !conversationId || !userId) {
206
368
  throw new Error('ChannelId, conversationId, and userId must be set in the activity')
207
369
  }
208
- return `oauth/${channelId}/${conversationId}/${userId}/flowState`
370
+ return `oauth/${channelId}/${userId}/${this.absOauthConnectionName}/flowState`
209
371
  }
210
372
  }
@@ -117,6 +117,9 @@ export class UserTokenClient {
117
117
  return response.data as TokenResponse
118
118
  } catch (error: any) {
119
119
  logger.error(error)
120
+ if (error.response?.data) {
121
+ logger.error(error.response.data)
122
+ }
120
123
  return { token: undefined }
121
124
  }
122
125
  }
@@ -1,88 +0,0 @@
1
- /**
2
- * Copyright (c) Microsoft Corporation. All rights reserved.
3
- * Licensed under the MIT License.
4
- */
5
- import { TurnContext } from '../../turnContext';
6
- import { TurnState } from '../turnState';
7
- import { Storage } from '../../storage';
8
- import { OAuthFlow, TokenResponse } from '../../oauth';
9
- /**
10
- * Interface defining an authorization handler for OAuth flows
11
- * @interface AuthHandler
12
- */
13
- export interface AuthHandler {
14
- /** Connection name for the auth provider */
15
- name?: string;
16
- /** Whether authorization should be triggered automatically */
17
- auto?: boolean;
18
- /** The OAuth flow implementation */
19
- flow?: OAuthFlow;
20
- /** Title to display on auth cards/UI */
21
- title?: string;
22
- /** Text to display on auth cards/UI */
23
- text?: string;
24
- }
25
- /**
26
- * Options for configuring user authorization.
27
- * Contains settings to configure OAuth connections.
28
- */
29
- export interface AuthorizationHandlers extends Record<string, AuthHandler> {
30
- }
31
- /**
32
- * Class responsible for managing authorization and OAuth flows
33
- * @class Authorization
34
- */
35
- export declare class Authorization {
36
- private storage;
37
- _authHandlers: AuthorizationHandlers;
38
- /**
39
- * Creates a new instance of UserAuthorization.
40
- * @param {Storage} storage - The storage system to use for state management.
41
- * @param {AuthorizationHandlers} authHandlers - Configuration for OAuth providers
42
- * @throws {Error} If storage is null/undefined or no auth handlers are provided
43
- */
44
- constructor(storage: Storage, authHandlers: AuthorizationHandlers);
45
- /**
46
- * Gets the token for a specific auth handler
47
- * @param {TurnContext} context - The context object for the current turn
48
- * @param {string} [authHandlerId] - Optional ID of the auth handler to use, defaults to first handler
49
- * @returns {Promise<TokenResponse>} The token response from the OAuth provider
50
- */
51
- getToken(context: TurnContext, authHandlerId?: string): Promise<TokenResponse>;
52
- /**
53
- * Begins or continues an OAuth flow
54
- * @param {TurnContext} context - The context object for the current turn
55
- * @param {TurnState} state - The state object for the current turn
56
- * @param {string} [authHandlerId] - Optional ID of the auth handler to use, defaults to first handler
57
- * @returns {Promise<TokenResponse>} The token response from the OAuth provider
58
- */
59
- beginOrContinueFlow(context: TurnContext, state: TurnState, authHandlerId?: string): Promise<TokenResponse>;
60
- /**
61
- * Gets the current state of the OAuth flow
62
- * @param {string} [authHandlerId] - Optional ID of the auth handler to check, defaults to first handler
63
- * @returns {boolean} Whether the flow has started
64
- */
65
- getFlowState(authHandlerId?: string): boolean;
66
- /**
67
- * Resolves the auth handler to use based on the provided ID
68
- * @param {string} [authHandlerId] - Optional ID of the auth handler to resolve, defaults to first handler
69
- * @returns {AuthHandler} The resolved auth handler
70
- */
71
- resolverHandler: (authHandlerId?: string) => AuthHandler;
72
- /**
73
- * Signs out the current user.
74
- * This method clears the user's token and resets the SSO state.
75
- *
76
- * @param {TurnContext} context - The context object for the current turn.
77
- * @param {TurnState} state - The state object for the current turn.
78
- * @param {string} [authHandlerId] - Optional ID of the auth handler to use for sign out
79
- * @returns {Promise<void>}
80
- */
81
- signOut(context: TurnContext, state: TurnState, authHandlerId?: string): Promise<void>;
82
- _signInHandler: ((context: TurnContext, state: TurnState, authHandlerId?: string) => void) | null;
83
- /**
84
- * Sets a handler to be called when sign-in is successfully completed
85
- * @param {Function} handler - The handler function to call on successful sign-in
86
- */
87
- onSignInSuccess(handler: (context: TurnContext, state: TurnState, authHandlerId?: string) => void): void;
88
- }
@@ -1,134 +0,0 @@
1
- "use strict";
2
- /**
3
- * Copyright (c) Microsoft Corporation. All rights reserved.
4
- * Licensed under the MIT License.
5
- */
6
- Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.Authorization = void 0;
8
- const logger_1 = require("../../logger");
9
- const oauth_1 = require("../../oauth");
10
- const logger = (0, logger_1.debug)('agents:authorization');
11
- /**
12
- * Class responsible for managing authorization and OAuth flows
13
- * @class Authorization
14
- */
15
- class Authorization {
16
- /**
17
- * Creates a new instance of UserAuthorization.
18
- * @param {Storage} storage - The storage system to use for state management.
19
- * @param {AuthorizationHandlers} authHandlers - Configuration for OAuth providers
20
- * @throws {Error} If storage is null/undefined or no auth handlers are provided
21
- */
22
- constructor(storage, authHandlers) {
23
- var _a, _b, _c, _d;
24
- this.storage = storage;
25
- /**
26
- * Resolves the auth handler to use based on the provided ID
27
- * @param {string} [authHandlerId] - Optional ID of the auth handler to resolve, defaults to first handler
28
- * @returns {AuthHandler} The resolved auth handler
29
- */
30
- this.resolverHandler = (authHandlerId) => {
31
- if (authHandlerId) {
32
- return this._authHandlers[authHandlerId];
33
- }
34
- return this._authHandlers[Object.keys(this._authHandlers)[0]];
35
- };
36
- this._signInHandler = null;
37
- if (storage === undefined || storage === null) {
38
- throw new Error('Storage is required for UserAuthorization');
39
- }
40
- if (authHandlers === undefined || Object.keys(authHandlers).length === 0) {
41
- throw new Error('The authorization does not have any auth handlers');
42
- }
43
- this._authHandlers = authHandlers;
44
- for (const ah in this._authHandlers) {
45
- if (this._authHandlers[ah].name === undefined && process.env[ah + '_connectionName'] === undefined) {
46
- throw new Error(`AuthHandler name ${ah}_connectionName not set in autorization and not found in env vars.`);
47
- }
48
- const currentAuthHandler = this._authHandlers[ah];
49
- currentAuthHandler.name = (_a = currentAuthHandler.name) !== null && _a !== void 0 ? _a : process.env[ah + '_connectionName'];
50
- currentAuthHandler.title = (_b = currentAuthHandler.title) !== null && _b !== void 0 ? _b : process.env[ah + '_connectionTitle'];
51
- currentAuthHandler.text = (_c = currentAuthHandler.text) !== null && _c !== void 0 ? _c : process.env[ah + '_connectionText'];
52
- currentAuthHandler.auto = (_d = currentAuthHandler.auto) !== null && _d !== void 0 ? _d : process.env[ah + '_connectionAuto'] === 'true';
53
- currentAuthHandler.flow = new oauth_1.OAuthFlow(this.storage, currentAuthHandler.name, null, currentAuthHandler.title, currentAuthHandler.text);
54
- }
55
- logger.info('Authorization handlers configured with', this._authHandlers.length, 'handlers');
56
- }
57
- /**
58
- * Gets the token for a specific auth handler
59
- * @param {TurnContext} context - The context object for the current turn
60
- * @param {string} [authHandlerId] - Optional ID of the auth handler to use, defaults to first handler
61
- * @returns {Promise<TokenResponse>} The token response from the OAuth provider
62
- */
63
- async getToken(context, authHandlerId) {
64
- var _a;
65
- logger.info('getToken from user token service for authHandlerId:', authHandlerId);
66
- const authHandler = this.resolverHandler(authHandlerId);
67
- return await ((_a = authHandler.flow) === null || _a === void 0 ? void 0 : _a.getUserToken(context));
68
- }
69
- /**
70
- * Begins or continues an OAuth flow
71
- * @param {TurnContext} context - The context object for the current turn
72
- * @param {TurnState} state - The state object for the current turn
73
- * @param {string} [authHandlerId] - Optional ID of the auth handler to use, defaults to first handler
74
- * @returns {Promise<TokenResponse>} The token response from the OAuth provider
75
- */
76
- async beginOrContinueFlow(context, state, authHandlerId) {
77
- logger.info('beginOrContinueFlow for authHandlerId:', authHandlerId);
78
- const flow = this.resolverHandler(authHandlerId).flow;
79
- let tokenResponse;
80
- if (flow.state.flowStarted === false) {
81
- tokenResponse = await flow.beginFlow(context);
82
- }
83
- else {
84
- tokenResponse = await flow.continueFlow(context);
85
- if (tokenResponse && tokenResponse.token) {
86
- if (this._signInHandler) {
87
- await this._signInHandler(context, state, authHandlerId);
88
- }
89
- }
90
- }
91
- return tokenResponse;
92
- }
93
- /**
94
- * Gets the current state of the OAuth flow
95
- * @param {string} [authHandlerId] - Optional ID of the auth handler to check, defaults to first handler
96
- * @returns {boolean} Whether the flow has started
97
- */
98
- getFlowState(authHandlerId) {
99
- var _a;
100
- const flow = this.resolverHandler(authHandlerId).flow;
101
- return (_a = flow.state) === null || _a === void 0 ? void 0 : _a.flowStarted;
102
- }
103
- /**
104
- * Signs out the current user.
105
- * This method clears the user's token and resets the SSO state.
106
- *
107
- * @param {TurnContext} context - The context object for the current turn.
108
- * @param {TurnState} state - The state object for the current turn.
109
- * @param {string} [authHandlerId] - Optional ID of the auth handler to use for sign out
110
- * @returns {Promise<void>}
111
- */
112
- async signOut(context, state, authHandlerId) {
113
- var _a;
114
- logger.info('signOut for authHandlerId:', authHandlerId);
115
- if (authHandlerId === undefined) { // aw
116
- for (const ah in this._authHandlers) {
117
- const flow = this._authHandlers[ah].flow;
118
- await (flow === null || flow === void 0 ? void 0 : flow.signOut(context));
119
- }
120
- }
121
- else {
122
- await ((_a = this.resolverHandler(authHandlerId).flow) === null || _a === void 0 ? void 0 : _a.signOut(context));
123
- }
124
- }
125
- /**
126
- * Sets a handler to be called when sign-in is successfully completed
127
- * @param {Function} handler - The handler function to call on successful sign-in
128
- */
129
- onSignInSuccess(handler) {
130
- this._signInHandler = handler;
131
- }
132
- }
133
- exports.Authorization = Authorization;
134
- //# sourceMappingURL=authorization.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"authorization.js","sourceRoot":"","sources":["../../../../src/app/oauth/authorization.ts"],"names":[],"mappings":"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"}