@microsoft/agents-hosting 1.1.0-alpha.8.g2362542eea → 1.1.0-alpha.85

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 (144) hide show
  1. package/dist/package.json +10 -6
  2. package/dist/src/activityWireCompat.d.ts +1 -1
  3. package/dist/src/activityWireCompat.js +11 -3
  4. package/dist/src/activityWireCompat.js.map +1 -1
  5. package/dist/src/agent-client/agentClient.js +7 -3
  6. package/dist/src/agent-client/agentClient.js.map +1 -1
  7. package/dist/src/agent-client/agentResponseHandler.js +6 -2
  8. package/dist/src/agent-client/agentResponseHandler.js.map +1 -1
  9. package/dist/src/app/agentApplication.d.ts +26 -11
  10. package/dist/src/app/agentApplication.js +90 -79
  11. package/dist/src/app/agentApplication.js.map +1 -1
  12. package/dist/src/app/agentApplicationBuilder.d.ts +2 -2
  13. package/dist/src/app/agentApplicationBuilder.js.map +1 -1
  14. package/dist/src/app/agentApplicationOptions.d.ts +9 -2
  15. package/dist/src/app/appRoute.d.ts +7 -0
  16. package/dist/src/app/{authorization.d.ts → auth/authorization.d.ts} +41 -139
  17. package/dist/src/app/auth/authorization.js +188 -0
  18. package/dist/src/app/auth/authorization.js.map +1 -0
  19. package/dist/src/app/auth/authorizationManager.d.ts +71 -0
  20. package/dist/src/app/auth/authorizationManager.js +170 -0
  21. package/dist/src/app/auth/authorizationManager.js.map +1 -0
  22. package/dist/src/app/auth/handlerStorage.d.ts +36 -0
  23. package/dist/src/app/auth/handlerStorage.js +62 -0
  24. package/dist/src/app/auth/handlerStorage.js.map +1 -0
  25. package/dist/src/app/auth/handlers/agenticAuthorization.d.ts +93 -0
  26. package/dist/src/app/auth/handlers/agenticAuthorization.js +134 -0
  27. package/dist/src/app/auth/handlers/agenticAuthorization.js.map +1 -0
  28. package/dist/src/app/auth/handlers/azureBotAuthorization.d.ts +222 -0
  29. package/dist/src/app/auth/handlers/azureBotAuthorization.js +428 -0
  30. package/dist/src/app/auth/handlers/azureBotAuthorization.js.map +1 -0
  31. package/dist/src/app/auth/handlers/index.d.ts +2 -0
  32. package/dist/src/app/auth/handlers/index.js +19 -0
  33. package/dist/src/app/auth/handlers/index.js.map +1 -0
  34. package/dist/src/app/auth/index.d.ts +2 -0
  35. package/dist/src/app/auth/index.js +19 -0
  36. package/dist/src/app/auth/index.js.map +1 -0
  37. package/dist/src/app/auth/types.d.ts +104 -0
  38. package/dist/src/app/auth/types.js +24 -0
  39. package/dist/src/app/auth/types.js.map +1 -0
  40. package/dist/src/app/index.d.ts +3 -3
  41. package/dist/src/app/index.js +2 -3
  42. package/dist/src/app/index.js.map +1 -1
  43. package/dist/src/app/routeList.d.ts +1 -1
  44. package/dist/src/app/routeList.js +22 -5
  45. package/dist/src/app/routeList.js.map +1 -1
  46. package/dist/src/app/streaming/streamingResponse.js +2 -1
  47. package/dist/src/app/streaming/streamingResponse.js.map +1 -1
  48. package/dist/src/auth/MemoryCache.d.ts +16 -0
  49. package/dist/src/auth/MemoryCache.js +58 -0
  50. package/dist/src/auth/MemoryCache.js.map +1 -0
  51. package/dist/src/auth/authConfiguration.d.ts +40 -2
  52. package/dist/src/auth/authConfiguration.js +209 -55
  53. package/dist/src/auth/authConfiguration.js.map +1 -1
  54. package/dist/src/auth/authConstants.d.ts +11 -0
  55. package/dist/src/auth/authConstants.js +15 -0
  56. package/dist/src/auth/authConstants.js.map +1 -0
  57. package/dist/src/auth/authProvider.d.ts +23 -0
  58. package/dist/src/auth/connections.d.ts +41 -0
  59. package/dist/src/auth/connections.js +7 -0
  60. package/dist/src/auth/connections.js.map +1 -0
  61. package/dist/src/auth/index.d.ts +2 -0
  62. package/dist/src/auth/index.js +2 -0
  63. package/dist/src/auth/index.js.map +1 -1
  64. package/dist/src/auth/jwt-middleware.js +31 -18
  65. package/dist/src/auth/jwt-middleware.js.map +1 -1
  66. package/dist/src/auth/msalConnectionManager.d.ts +64 -0
  67. package/dist/src/auth/msalConnectionManager.js +148 -0
  68. package/dist/src/auth/msalConnectionManager.js.map +1 -0
  69. package/dist/src/auth/msalTokenProvider.d.ts +24 -0
  70. package/dist/src/auth/msalTokenProvider.js +143 -16
  71. package/dist/src/auth/msalTokenProvider.js.map +1 -1
  72. package/dist/src/baseAdapter.d.ts +10 -25
  73. package/dist/src/baseAdapter.js +2 -15
  74. package/dist/src/baseAdapter.js.map +1 -1
  75. package/dist/src/cloudAdapter.d.ts +40 -23
  76. package/dist/src/cloudAdapter.js +141 -63
  77. package/dist/src/cloudAdapter.js.map +1 -1
  78. package/dist/src/connector-client/connectorClient.d.ts +15 -0
  79. package/dist/src/connector-client/connectorClient.js +49 -15
  80. package/dist/src/connector-client/connectorClient.js.map +1 -1
  81. package/dist/src/index.d.ts +0 -1
  82. package/dist/src/index.js +0 -1
  83. package/dist/src/index.js.map +1 -1
  84. package/dist/src/oauth/customUserTokenAPI.d.ts +1 -0
  85. package/dist/src/oauth/customUserTokenAPI.js +11 -0
  86. package/dist/src/oauth/customUserTokenAPI.js.map +1 -0
  87. package/dist/src/oauth/index.d.ts +0 -1
  88. package/dist/src/oauth/index.js +0 -1
  89. package/dist/src/oauth/index.js.map +1 -1
  90. package/dist/src/oauth/userTokenClient.d.ts +30 -13
  91. package/dist/src/oauth/userTokenClient.js +62 -26
  92. package/dist/src/oauth/userTokenClient.js.map +1 -1
  93. package/dist/src/oauth/userTokenClient.types.d.ts +19 -6
  94. package/dist/src/turnContext.d.ts +7 -1
  95. package/dist/src/turnContext.js +11 -4
  96. package/dist/src/turnContext.js.map +1 -1
  97. package/package.json +10 -6
  98. package/src/activityWireCompat.ts +12 -4
  99. package/src/agent-client/agentClient.ts +9 -3
  100. package/src/agent-client/agentResponseHandler.ts +5 -2
  101. package/src/app/agentApplication.ts +95 -74
  102. package/src/app/agentApplicationBuilder.ts +2 -2
  103. package/src/app/agentApplicationOptions.ts +10 -2
  104. package/src/app/appRoute.ts +8 -0
  105. package/src/app/auth/authorization.ts +261 -0
  106. package/src/app/auth/authorizationManager.ts +213 -0
  107. package/src/app/auth/handlerStorage.ts +61 -0
  108. package/src/app/auth/handlers/agenticAuthorization.ts +182 -0
  109. package/src/app/auth/handlers/azureBotAuthorization.ts +599 -0
  110. package/src/app/auth/handlers/index.ts +2 -0
  111. package/src/app/auth/index.ts +2 -0
  112. package/src/app/auth/types.ts +111 -0
  113. package/src/app/index.ts +3 -3
  114. package/src/app/routeList.ts +24 -5
  115. package/src/app/streaming/streamingResponse.ts +2 -1
  116. package/src/auth/MemoryCache.ts +59 -0
  117. package/src/auth/authConfiguration.ts +239 -53
  118. package/src/auth/authConstants.ts +11 -0
  119. package/src/auth/authProvider.ts +31 -0
  120. package/src/auth/connections.ts +47 -0
  121. package/src/auth/index.ts +2 -0
  122. package/src/auth/jwt-middleware.ts +38 -21
  123. package/src/auth/msalConnectionManager.ts +175 -0
  124. package/src/auth/msalTokenProvider.ts +185 -9
  125. package/src/baseAdapter.ts +10 -29
  126. package/src/cloudAdapter.ts +205 -71
  127. package/src/connector-client/connectorClient.ts +59 -15
  128. package/src/index.ts +0 -1
  129. package/src/oauth/customUserTokenAPI.ts +5 -0
  130. package/src/oauth/index.ts +0 -1
  131. package/src/oauth/userTokenClient.ts +76 -22
  132. package/src/oauth/userTokenClient.types.ts +20 -8
  133. package/src/turnContext.ts +16 -5
  134. package/dist/src/app/authorization.js +0 -387
  135. package/dist/src/app/authorization.js.map +0 -1
  136. package/dist/src/claimsIdentity.d.ts +0 -35
  137. package/dist/src/claimsIdentity.js +0 -43
  138. package/dist/src/claimsIdentity.js.map +0 -1
  139. package/dist/src/oauth/oAuthFlow.d.ts +0 -119
  140. package/dist/src/oauth/oAuthFlow.js +0 -316
  141. package/dist/src/oauth/oAuthFlow.js.map +0 -1
  142. package/src/app/authorization.ts +0 -432
  143. package/src/claimsIdentity.ts +0 -47
  144. package/src/oauth/oAuthFlow.ts +0 -378
@@ -0,0 +1,111 @@
1
+ /**
2
+ * Copyright (c) Microsoft Corporation. All rights reserved.
3
+ * Licensed under the MIT License.
4
+ */
5
+
6
+ import { Activity } from '@microsoft/agents-activity'
7
+ import { Storage, StoreItem } from '../../storage'
8
+ import { TurnContext } from '../../turnContext'
9
+ import { AgenticAuthorizationOptions, AzureBotAuthorizationOptions } from './handlers'
10
+ import { TokenResponse } from '../../oauth'
11
+ import { Connections } from '../../auth/connections'
12
+
13
+ /**
14
+ * Authorization configuration options.
15
+ */
16
+ export type AuthorizationOptions = Record<string, AzureBotAuthorizationOptions | AgenticAuthorizationOptions>
17
+
18
+ /**
19
+ * Represents the status of a handler registration attempt.
20
+ */
21
+ export enum AuthorizationHandlerStatus {
22
+ /** The handler has approved the request - validation passed */
23
+ APPROVED = 'approved',
24
+ /** The handler registration is pending further action */
25
+ PENDING = 'pending',
26
+ /** The handler has rejected the request - validation failed */
27
+ REJECTED = 'rejected',
28
+ /** The handler has ignored the request - no action taken */
29
+ IGNORED = 'ignored',
30
+ /** The handler requires revalidation */
31
+ REVALIDATE = 'revalidate'
32
+ }
33
+
34
+ /**
35
+ * Active handler manager information.
36
+ */
37
+ export interface ActiveAuthorizationHandler extends StoreItem {
38
+ /**
39
+ * Unique identifier for the handler.
40
+ */
41
+ readonly id: string
42
+ /**
43
+ * The current activity associated with the handler.
44
+ */
45
+ activity: Activity
46
+ }
47
+
48
+ export interface AuthorizationHandler {
49
+ /**
50
+ * Unique identifier for the handler.
51
+ */
52
+ readonly id: string
53
+ /**
54
+ * Initiates the sign-in process for the handler.
55
+ * @param context The turn context.
56
+ * @param active Optional active handler data.
57
+ * @returns The status of the sign-in attempt.
58
+ */
59
+ signin(context: TurnContext, active?: ActiveAuthorizationHandler): Promise<AuthorizationHandlerStatus>
60
+ /**
61
+ * Initiates the sign-out process for the handler.
62
+ * @param context The turn context.
63
+ * @returns A promise that resolves to a boolean indicating the success of the sign-out attempt.
64
+ */
65
+ signout(context: TurnContext): Promise<boolean>;
66
+ /**
67
+ * Retrieves an access token for the specified scopes.
68
+ * @param context The turn context.
69
+ * @param options Optional token request options.
70
+ * @returns The access token response.
71
+ */
72
+ token(context: TurnContext, options?: AuthorizationHandlerTokenOptions): Promise<TokenResponse>;
73
+ /**
74
+ * Registers a callback to be invoked when the sign-in process is successful.
75
+ * @param callback The callback to invoke on success.
76
+ */
77
+ onSuccess(callback: (context: TurnContext) => Promise<void> | void): void;
78
+ /**
79
+ * Registers a callback to be invoked when the sign-in process fails.
80
+ * @param callback The callback to invoke on failure.
81
+ */
82
+ onFailure(callback: (context: TurnContext, reason?: string) => Promise<void> | void): void;
83
+ }
84
+
85
+ /**
86
+ * Common settings required by authorization handlers.
87
+ */
88
+ export interface AuthorizationHandlerSettings {
89
+ /**
90
+ * Storage instance for persisting handler state.
91
+ */
92
+ storage: Storage
93
+ /**
94
+ * Connections instance for managing authentication connections.
95
+ */
96
+ connections: Connections
97
+ }
98
+
99
+ /**
100
+ * Options for token requests in authorization handlers.
101
+ */
102
+ export interface AuthorizationHandlerTokenOptions {
103
+ /**
104
+ * Optional name of the connection to use for the token request. Usually used for OBO flows.
105
+ */
106
+ connection?: string
107
+ /**
108
+ * Optional scopes to request in the token. Usually used for OBO flows.
109
+ */
110
+ scopes?: string[]
111
+ }
package/src/app/index.ts CHANGED
@@ -2,13 +2,13 @@ export * from './agentApplication'
2
2
  export * from './agentApplicationBuilder'
3
3
  export * from './agentApplicationOptions'
4
4
  export * from './appRoute'
5
- export * from './attachmentDownloader'
6
- export * from './authorization'
7
- export * from './conversationUpdateEvents'
5
+ export { Authorization } from './auth/authorization'
8
6
  export * from './routeHandler'
9
7
  export * from './routeList'
10
8
  export * from './routeRank'
11
9
  export * from './routeSelector'
10
+ export * from './attachmentDownloader'
11
+ export * from './conversationUpdateEvents'
12
12
  export * from './turnState'
13
13
  export * from './turnEvents'
14
14
  export * from './turnStateEntry'
@@ -17,17 +17,36 @@ export class RouteList<TState extends TurnState> {
17
17
  handler: RouteHandler<TState>,
18
18
  isInvokeRoute: boolean = false,
19
19
  rank: number = RouteRank.Unspecified,
20
- authHandlers: string[] = []
20
+ authHandlers: string[] = [],
21
+ isAgenticRoute: boolean = false
21
22
  ): this {
22
- this._routes.push({ selector, handler, isInvokeRoute, rank, authHandlers })
23
+ this._routes.push({ selector, handler, isInvokeRoute, rank, authHandlers, isAgenticRoute })
23
24
 
24
- // Invoke selectors are first, then order by rank ascending
25
+ // Ordered by:
26
+ // Agentic + Invoke
27
+ // Invoke
28
+ // Agentic
29
+ // Other
30
+ // Then by Rank
25
31
  this._routes.sort((a, b) => {
26
- if (a.isInvokeRoute !== b.isInvokeRoute) {
27
- return a.isInvokeRoute ? -1 : 1
32
+ const getPriority = (route: AppRoute<TState>) => {
33
+ if (route.isAgenticRoute && route.isInvokeRoute) return 0
34
+ if (route.isInvokeRoute) return 1
35
+ if (route.isAgenticRoute) return 2
36
+ return 3
28
37
  }
38
+
39
+ const priorityA = getPriority(a)
40
+ const priorityB = getPriority(b)
41
+
42
+ if (priorityA !== priorityB) {
43
+ return priorityA - priorityB
44
+ }
45
+
46
+ // If priorities are equal, sort by rank
29
47
  return (a.rank ?? 0) - (b.rank ?? 0)
30
48
  })
49
+
31
50
  return this
32
51
  }
33
52
 
@@ -191,7 +191,8 @@ export class StreamingResponse {
191
191
  appearance: {
192
192
  '@type': 'DigitalDocument',
193
193
  name: citation.title || `Document #${currPos + 1}`,
194
- abstract: CitationUtil.snippet(citation.content, 477)
194
+ abstract: CitationUtil.snippet(citation.content, 477),
195
+ url: citation.url!
195
196
  }
196
197
  }
197
198
  currPos++
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Copyright (c) Microsoft Corporation. All rights reserved.
3
+ * Licensed under the MIT License.
4
+ */
5
+ const CACHE_PURGE_INTERVAL = 60000 // 60 seconds
6
+
7
+ /**
8
+ * Simple in-memory cache with TTL support.
9
+ * This is used to store authentication tokens for Agentic Identity scenarios only!
10
+ */
11
+ export class MemoryCache<T> {
12
+ private cache = new Map<string, { value: T; validUntil: number }>()
13
+ private purgeInterval?: NodeJS.Timeout
14
+
15
+ /**
16
+ * Clears the purge interval to allow the process to exit cleanly
17
+ */
18
+ destroy (): void {
19
+ if (this.purgeInterval) {
20
+ clearInterval(this.purgeInterval)
21
+ this.purgeInterval = undefined
22
+ }
23
+ }
24
+
25
+ set (key: string, value: T, ttlSeconds: number): void {
26
+ const validUntil = Date.now() + (ttlSeconds * 1000)
27
+ this.cache.set(key, { value, validUntil })
28
+ if (!this.purgeInterval) {
29
+ this.purgeInterval = setInterval(() => this.purge(), CACHE_PURGE_INTERVAL)
30
+ }
31
+ }
32
+
33
+ get (key: string): T | undefined {
34
+ const item = this.cache.get(key)
35
+ if (!item) {
36
+ return undefined
37
+ }
38
+
39
+ // Check if item has expired
40
+ if (Date.now() > item.validUntil) {
41
+ this.cache.delete(key)
42
+ return undefined
43
+ }
44
+ return item.value
45
+ }
46
+
47
+ delete (key: string): boolean {
48
+ return this.cache.delete(key)
49
+ }
50
+
51
+ purge (): void {
52
+ const now = Date.now()
53
+ for (const [key, { validUntil }] of this.cache.entries()) {
54
+ if (now > validUntil) {
55
+ this.cache.delete(key)
56
+ }
57
+ }
58
+ }
59
+ }
@@ -3,6 +3,13 @@
3
3
  * Licensed under the MIT License.
4
4
  */
5
5
 
6
+ import { debug } from '@microsoft/agents-activity/logger'
7
+ import { ConnectionMapItem } from './msalConnectionManager'
8
+ import objectPath from 'object-path'
9
+
10
+ const logger = debug('agents:authConfiguration')
11
+ const DEFAULT_CONNECTION = 'serviceConnection'
12
+
6
13
  /**
7
14
  * Represents the authentication configuration.
8
15
  */
@@ -15,7 +22,7 @@ export interface AuthConfiguration {
15
22
  /**
16
23
  * The client ID for the authentication configuration. Required in production.
17
24
  */
18
- clientId: string
25
+ clientId?: string
19
26
 
20
27
  /**
21
28
  * The client secret for the authentication configuration.
@@ -35,7 +42,7 @@ export interface AuthConfiguration {
35
42
  /**
36
43
  * A list of valid issuers for the authentication configuration.
37
44
  */
38
- issuers: string[]
45
+ issuers?: string[]
39
46
 
40
47
  /**
41
48
  * The connection name for the authentication configuration.
@@ -57,6 +64,23 @@ export interface AuthConfiguration {
57
64
  */
58
65
  authority?: string
59
66
 
67
+ scope?: string
68
+
69
+ /**
70
+ * A map of connection names to their respective authentication configurations.
71
+ */
72
+ connections?: Map<string, AuthConfiguration>
73
+
74
+ /**
75
+ * A list of connection map items to map service URLs to connection names.
76
+ */
77
+ connectionsMap?: ConnectionMapItem[],
78
+
79
+ /**
80
+ * An optional alternative blueprint Connection name used when constructing a connector client.
81
+ */
82
+ altBlueprintConnectionName?: string
83
+
60
84
  /**
61
85
  * The path to K8s provided token.
62
86
  */
@@ -88,81 +112,243 @@ export interface AuthConfiguration {
88
112
  * ```
89
113
  *
90
114
  */
91
- export const loadAuthConfigFromEnv: (cnxName?: string) => AuthConfiguration = (cnxName?: string) => {
92
- if (cnxName === undefined) {
93
- const authority = process.env.authorityEndpoint ?? 'https://login.microsoftonline.com'
94
- if (process.env.clientId === undefined && process.env.NODE_ENV === 'production') {
115
+ export const loadAuthConfigFromEnv = (cnxName?: string): AuthConfiguration => {
116
+ const envConnections = loadConnectionsMapFromEnv()
117
+ let authConfig: AuthConfiguration
118
+
119
+ if (envConnections.connectionsMap.length === 0) {
120
+ // No connections provided, we need to populate the connections map with the old config settings
121
+ authConfig = buildLegacyAuthConfig(cnxName)
122
+ envConnections.connections.set(DEFAULT_CONNECTION, authConfig)
123
+ envConnections.connectionsMap.push({
124
+ serviceUrl: '*',
125
+ connection: DEFAULT_CONNECTION,
126
+ })
127
+ } else {
128
+ // There are connections provided, use the default or specified connection
129
+ if (cnxName) {
130
+ const entry = envConnections.connections.get(cnxName)
131
+ if (entry) {
132
+ authConfig = entry
133
+ } else {
134
+ throw new Error(`Connection "${cnxName}" not found in environment.`)
135
+ }
136
+ } else {
137
+ const defaultItem = envConnections.connectionsMap.find((item) => item.serviceUrl === '*')
138
+ const defaultConn = defaultItem ? envConnections.connections.get(defaultItem.connection) : undefined
139
+ if (!defaultConn) {
140
+ throw new Error('No default connection found in environment connections.')
141
+ }
142
+ authConfig = defaultConn
143
+ }
144
+
145
+ authConfig.authority ??= 'https://login.microsoftonline.com'
146
+ authConfig.issuers ??= getDefaultIssuers(authConfig.tenantId ?? '', authConfig.authority)
147
+ }
148
+
149
+ return {
150
+ ...authConfig,
151
+ ...envConnections,
152
+ }
153
+ }
154
+
155
+ /**
156
+ * Loads the agent authentication configuration from previous version environment variables.
157
+ *
158
+ * @returns The agent authentication configuration.
159
+ * @throws Will throw an error if MicrosoftAppId is not provided in production.
160
+ *
161
+ * @example
162
+ * ```
163
+ * MicrosoftAppId=your-client-id
164
+ * MicrosoftAppPassword=your-client-secret
165
+ * MicrosoftAppTenantId=your-tenant-id
166
+ * ```
167
+ *
168
+ */
169
+ export const loadPrevAuthConfigFromEnv: () => AuthConfiguration = () => {
170
+ const envConnections = loadConnectionsMapFromEnv()
171
+ let authConfig: AuthConfiguration = {}
172
+
173
+ if (envConnections.connectionsMap.length === 0) {
174
+ // No connections provided, we need to populate the connection map with the old config settings
175
+ if (process.env.MicrosoftAppId === undefined && process.env.NODE_ENV === 'production') {
95
176
  throw new Error('ClientId required in production')
96
177
  }
97
- return {
98
- tenantId: process.env.tenantId,
99
- clientId: process.env.clientId!,
100
- clientSecret: process.env.clientSecret,
178
+ const authority = process.env.authorityEndpoint ?? 'https://login.microsoftonline.com'
179
+ authConfig = {
180
+ tenantId: process.env.MicrosoftAppTenantId,
181
+ clientId: process.env.MicrosoftAppId,
182
+ clientSecret: process.env.MicrosoftAppPassword,
101
183
  certPemFile: process.env.certPemFile,
102
184
  certKeyFile: process.env.certKeyFile,
103
185
  connectionName: process.env.connectionName,
104
- FICClientId: process.env.FICClientId,
186
+ FICClientId: process.env.MicrosoftAppClientId,
105
187
  authority,
188
+ scope: process.env.scope,
189
+ issuers: getDefaultIssuers(process.env.MicrosoftAppTenantId ?? '', authority),
190
+ altBlueprintConnectionName: process.env.altBlueprintConnectionName,
106
191
  WIDAssertionFile: process.env.WIDAssertionFile,
107
- issuers: [
108
- 'https://api.botframework.com',
109
- `https://sts.windows.net/${process.env.tenantId}/`,
110
- `${authority}/${process.env.tenantId}/v2.0`
111
- ],
112
192
  }
193
+ envConnections.connections.set(DEFAULT_CONNECTION, authConfig)
194
+ envConnections.connectionsMap.push({
195
+ serviceUrl: '*',
196
+ connection: DEFAULT_CONNECTION,
197
+ })
113
198
  } else {
114
- const authority = process.env[`${cnxName}_authorityEndpoint`] ?? 'https://login.microsoftonline.com'
115
- return {
116
- tenantId: process.env[`${cnxName}_tenantId`],
117
- clientId: process.env[`${cnxName}_clientId`] ?? (() => { throw new Error(`ClientId not found for connection: ${cnxName}`) })(),
118
- clientSecret: process.env[`${cnxName}_clientSecret`],
119
- certPemFile: process.env[`${cnxName}_certPemFile`],
120
- certKeyFile: process.env[`${cnxName}_certKeyFile`],
121
- connectionName: process.env[`${cnxName}_connectionName`],
122
- FICClientId: process.env[`${cnxName}_FICClientId`],
123
- authority,
124
- issuers: [
125
- 'https://api.botframework.com',
126
- `https://sts.windows.net/${process.env[`${cnxName}_tenantId`]}/`,
127
- `${authority}/${process.env[`${cnxName}_tenantId`]}/v2.0`
128
- ]
199
+ // There are connections provided, use the default one.
200
+ const defaultItem = envConnections.connectionsMap.find((item) => item.serviceUrl === '*')
201
+ const defaultConn = defaultItem ? envConnections.connections.get(defaultItem.connection) : undefined
202
+ if (!defaultConn) {
203
+ throw new Error('No default connection found in environment connections.')
204
+ }
205
+ authConfig = defaultConn
206
+ }
207
+
208
+ authConfig.authority ??= 'https://login.microsoftonline.com'
209
+ authConfig.issuers ??= getDefaultIssuers(authConfig.tenantId ?? '', authConfig.authority)
210
+
211
+ return { ...authConfig, ...envConnections }
212
+ }
213
+
214
+ function loadConnectionsMapFromEnv () {
215
+ const envVars = process.env
216
+ const connectionsObj: Record<string, any> = {}
217
+ const connectionsMap: ConnectionMapItem[] = []
218
+ const CONNECTIONS_PREFIX = 'connections__'
219
+ const CONNECTIONS_MAP_PREFIX = 'connectionsMap__'
220
+
221
+ for (const [key, value] of Object.entries(envVars)) {
222
+ if (key.startsWith(CONNECTIONS_PREFIX)) {
223
+ // Convert to dot notation
224
+ let path = key.substring(CONNECTIONS_PREFIX.length).replace(/__/g, '.')
225
+ // Remove ".settings." from the path
226
+ path = path.replace('.settings.', '.')
227
+ objectPath.set(connectionsObj, path, value)
228
+ } else if (key.startsWith(CONNECTIONS_MAP_PREFIX)) {
229
+ const path = key.substring(CONNECTIONS_MAP_PREFIX.length).replace(/__/g, '.')
230
+ objectPath.set(connectionsMap, path, value)
129
231
  }
130
232
  }
233
+
234
+ // Convert connectionsObj to Map<string, AuthConfiguration>
235
+ const connections: Map<string, AuthConfiguration> = new Map(Object.entries(connectionsObj))
236
+
237
+ if (connections.size === 0) {
238
+ logger.warn('No connections found in configuration.')
239
+ }
240
+
241
+ if (connectionsMap.length === 0) {
242
+ logger.warn('No connections map found in configuration.')
243
+ if (connections.size > 0) {
244
+ const firstEntry = connections.entries().next().value
245
+
246
+ if (firstEntry) {
247
+ const [firstKey] = firstEntry
248
+ // Provide a default connection map if none is specified
249
+ connectionsMap.push({
250
+ serviceUrl: '*',
251
+ connection: firstKey,
252
+ })
253
+ }
254
+ }
255
+ }
256
+ return {
257
+ connections,
258
+ connectionsMap,
259
+ }
131
260
  }
132
261
 
133
262
  /**
134
- * Loads the agent authentication configuration from previous version environment variables.
263
+ * Loads the authentication configuration from the provided config or from the environment variables
264
+ * providing default values for authority and issuers.
135
265
  *
136
- * @returns The agent authentication configuration.
137
- * @throws Will throw an error if MicrosoftAppId is not provided in production.
266
+ * @returns The authentication configuration.
267
+ * @throws Will throw an error if clientId is not provided in production.
138
268
  *
139
269
  * @example
140
270
  * ```
141
- * MicrosoftAppId=your-client-id
142
- * MicrosoftAppPassword=your-client-secret
143
- * MicrosoftAppTenantId=your-tenant-id
271
+ * tenantId=your-tenant-id
272
+ * clientId=your-client-id
273
+ * clientSecret=your-client-secret
274
+ *
275
+ * certPemFile=your-cert-pem-file
276
+ * certKeyFile=your-cert-key-file
277
+ *
278
+ * FICClientId=your-FIC-client-id
279
+ *
280
+ * connectionName=your-connection-name
281
+ * authority=your-authority-endpoint
144
282
  * ```
145
283
  *
146
284
  */
147
- export const loadPrevAuthConfigFromEnv: () => AuthConfiguration = () => {
148
- if (process.env.MicrosoftAppId === undefined && process.env.NODE_ENV === 'production') {
285
+ export function getAuthConfigWithDefaults (config?: AuthConfiguration): AuthConfiguration {
286
+ if (!config) return loadAuthConfigFromEnv()
287
+
288
+ const providedConnections = config.connections && config.connectionsMap
289
+ ? { connections: config.connections, connectionsMap: config.connectionsMap }
290
+ : undefined
291
+
292
+ const connections = providedConnections ?? loadConnectionsMapFromEnv()
293
+
294
+ let mergedConfig: AuthConfiguration
295
+
296
+ if (connections && connections.connectionsMap?.length === 0) {
297
+ // No connections provided, we need to populate the connections map with the old config settings
298
+ mergedConfig = buildLegacyAuthConfig(undefined, config)
299
+ connections.connections?.set(DEFAULT_CONNECTION, mergedConfig)
300
+ connections.connectionsMap.push({ serviceUrl: '*', connection: DEFAULT_CONNECTION })
301
+ } else {
302
+ // There are connections provided, use the default connection
303
+ const defaultItem = connections.connectionsMap?.find((item) => item.serviceUrl === '*')
304
+ const defaultConn = defaultItem ? connections.connections?.get(defaultItem.connection) : undefined
305
+ if (!defaultConn) {
306
+ throw new Error('No default connection found in environment connections.')
307
+ }
308
+ mergedConfig = buildLegacyAuthConfig(undefined, defaultConn)
309
+ }
310
+
311
+ return {
312
+ ...mergedConfig,
313
+ ...connections,
314
+ }
315
+ }
316
+
317
+ function buildLegacyAuthConfig (envPrefix: string = '', customConfig?: AuthConfiguration): AuthConfiguration {
318
+ const prefix = envPrefix ? `${envPrefix}_` : ''
319
+ const authority = customConfig?.authority ?? process.env[`${prefix}authorityEndpoint`] ?? 'https://login.microsoftonline.com'
320
+
321
+ const clientId = customConfig?.clientId ?? process.env[`${prefix}clientId`]
322
+
323
+ if (!clientId && !envPrefix && process.env.NODE_ENV === 'production') {
149
324
  throw new Error('ClientId required in production')
150
325
  }
151
- const authority = process.env.authorityEndpoint ?? 'https://login.microsoftonline.com'
326
+ if (!clientId && envPrefix) {
327
+ throw new Error(`ClientId not found for connection: ${envPrefix}`)
328
+ }
329
+
330
+ const tenantId = customConfig?.tenantId ?? process.env[`${prefix}tenantId`]
331
+
152
332
  return {
153
- tenantId: process.env.MicrosoftAppTenantId,
154
- clientId: process.env.MicrosoftAppId!,
155
- clientSecret: process.env.MicrosoftAppPassword,
156
- certPemFile: process.env.certPemFile,
157
- certKeyFile: process.env.certKeyFile,
158
- connectionName: process.env.connectionName,
159
- FICClientId: process.env.MicrosoftAppClientId,
333
+ tenantId,
334
+ clientId: clientId!,
335
+ clientSecret: customConfig?.clientSecret ?? process.env[`${prefix}clientSecret`],
336
+ certPemFile: customConfig?.certPemFile ?? process.env[`${prefix}certPemFile`],
337
+ certKeyFile: customConfig?.certKeyFile ?? process.env[`${prefix}certKeyFile`],
338
+ connectionName: customConfig?.connectionName ?? process.env[`${prefix}connectionName`],
339
+ FICClientId: customConfig?.FICClientId ?? process.env[`${prefix}FICClientId`],
160
340
  authority,
161
- WIDAssertionFile: process.env.WIDAssertionFile,
162
- issuers: [
163
- 'https://api.botframework.com',
164
- `https://sts.windows.net/${process.env.MicrosoftAppTenantId}/`,
165
- `${authority}/${process.env.MicrosoftAppTenantId}/v2.0`
166
- ]
341
+ scope: customConfig?.scope ?? process.env[`${prefix}scope`],
342
+ issuers: customConfig?.issuers ?? getDefaultIssuers(tenantId as string, authority),
343
+ altBlueprintConnectionName: customConfig?.altBlueprintConnectionName ?? process.env[`${prefix}altBlueprintConnectionName`],
344
+ WIDAssertionFile: customConfig?.WIDAssertionFile ?? process.env[`${prefix}WIDAssertionFile`]
167
345
  }
168
346
  }
347
+
348
+ function getDefaultIssuers (tenantId: string, authority: string) : string[] {
349
+ return [
350
+ 'https://api.botframework.com',
351
+ `https://sts.windows.net/${tenantId}/`,
352
+ `${authority}/${tenantId}/v2.0`
353
+ ]
354
+ }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Copyright (c) Microsoft Corporation. All rights reserved.
3
+ * Licensed under the MIT License.
4
+ */
5
+ export const ApxLocalScope = 'c16e153d-5d2b-4c21-b7f4-b05ee5d516f1/.default'
6
+ export const ApxDevScope = '0d94caae-b412-4943-8a68-83135ad6d35f/.default'
7
+ export const ApxProductionScope = '5a807f24-c9de-44ee-a3a7-329e88a00ffc/.default'
8
+ export const ApxGCCScope = 'c9475445-9789-4fef-9ec5-cde4a9bcd446/.default'
9
+ export const ApxGCCHScope = '6f669b9e-7701-4e2b-b624-82c9207fde26/.default'
10
+ export const ApxDoDScope = '0a069c81-8c7c-4712-886b-9c542d673ffb/.default'
11
+ export const ApxGallatinScope = 'bd004c8e-5acf-4c48-8570-4e7d46b2f63b/.default'
@@ -16,4 +16,35 @@ export interface AuthProvider {
16
16
  * @returns A promise that resolves to the access token.
17
17
  */
18
18
  getAccessToken: (authConfig: AuthConfiguration, scope: string) => Promise<string>
19
+
20
+ /**
21
+ * Get an access token for the agentic application
22
+ * @param agentAppInstanceId
23
+ * @returns a promise that resolves to the access token.
24
+ */
25
+ getAgenticApplicationToken: (agentAppInstanceId: string) => Promise<string>
26
+
27
+ /**
28
+ * Get an access token for the agentic instance
29
+ * @param agentAppInstanceId
30
+ * @returns a promise that resolves to the access token.
31
+ */
32
+ getAgenticInstanceToken: (agentAppInstanceId: string) => Promise<string>
33
+
34
+ /**
35
+ * Get an access token for the agentic user
36
+ * @param agentAppInstanceId
37
+ * @param upn
38
+ * @param scopes
39
+ * @returns a promise that resolves to the access token.
40
+ */
41
+ getAgenticUserToken: (agentAppInstanceId: string, upn: string, scopes: string[]) => Promise<string>
42
+
43
+ acquireTokenOnBehalfOf (scopes: string[], oboAssertion: string): Promise<string>
44
+ acquireTokenOnBehalfOf (authConfig: AuthConfiguration, scopes: string[], oboAssertion: string): Promise<string>
45
+ acquireTokenOnBehalfOf (
46
+ authConfigOrScopes: AuthConfiguration | string[],
47
+ scopesOrOboAssertion?: string[] | string,
48
+ oboAssertion?: string
49
+ ): Promise<string>
19
50
  }