microsoft-agents-authentication-msal 1.10.0.dev5__tar.gz → 1.10.0.dev7__tar.gz

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 (23) hide show
  1. {microsoft_agents_authentication_msal-1.10.0.dev5/microsoft_agents_authentication_msal.egg-info → microsoft_agents_authentication_msal-1.10.0.dev7}/PKG-INFO +32 -2
  2. microsoft_agents_authentication_msal-1.10.0.dev7/VERSION.txt +1 -0
  3. {microsoft_agents_authentication_msal-1.10.0.dev5 → microsoft_agents_authentication_msal-1.10.0.dev7}/microsoft_agents/authentication/msal/__init__.py +2 -0
  4. microsoft_agents_authentication_msal-1.10.0.dev7/microsoft_agents/authentication/msal/connection_settings.py +87 -0
  5. {microsoft_agents_authentication_msal-1.10.0.dev5 → microsoft_agents_authentication_msal-1.10.0.dev7}/microsoft_agents/authentication/msal/msal_auth.py +94 -56
  6. {microsoft_agents_authentication_msal-1.10.0.dev5 → microsoft_agents_authentication_msal-1.10.0.dev7}/microsoft_agents/authentication/msal/msal_connection_manager.py +9 -2
  7. {microsoft_agents_authentication_msal-1.10.0.dev5 → microsoft_agents_authentication_msal-1.10.0.dev7}/microsoft_agents/authentication/msal/msal_token_credential.py +6 -3
  8. {microsoft_agents_authentication_msal-1.10.0.dev5 → microsoft_agents_authentication_msal-1.10.0.dev7/microsoft_agents_authentication_msal.egg-info}/PKG-INFO +32 -2
  9. {microsoft_agents_authentication_msal-1.10.0.dev5 → microsoft_agents_authentication_msal-1.10.0.dev7}/microsoft_agents_authentication_msal.egg-info/SOURCES.txt +1 -0
  10. microsoft_agents_authentication_msal-1.10.0.dev7/microsoft_agents_authentication_msal.egg-info/requires.txt +4 -0
  11. {microsoft_agents_authentication_msal-1.10.0.dev5 → microsoft_agents_authentication_msal-1.10.0.dev7}/readme.md +30 -0
  12. microsoft_agents_authentication_msal-1.10.0.dev5/VERSION.txt +0 -1
  13. microsoft_agents_authentication_msal-1.10.0.dev5/microsoft_agents_authentication_msal.egg-info/requires.txt +0 -4
  14. {microsoft_agents_authentication_msal-1.10.0.dev5 → microsoft_agents_authentication_msal-1.10.0.dev7}/LICENSE +0 -0
  15. {microsoft_agents_authentication_msal-1.10.0.dev5 → microsoft_agents_authentication_msal-1.10.0.dev7}/MANIFEST.in +0 -0
  16. {microsoft_agents_authentication_msal-1.10.0.dev5 → microsoft_agents_authentication_msal-1.10.0.dev7}/microsoft_agents/authentication/msal/errors/__init__.py +0 -0
  17. {microsoft_agents_authentication_msal-1.10.0.dev5 → microsoft_agents_authentication_msal-1.10.0.dev7}/microsoft_agents/authentication/msal/errors/error_resources.py +0 -0
  18. {microsoft_agents_authentication_msal-1.10.0.dev5 → microsoft_agents_authentication_msal-1.10.0.dev7}/microsoft_agents/authentication/msal/py.typed +0 -0
  19. {microsoft_agents_authentication_msal-1.10.0.dev5 → microsoft_agents_authentication_msal-1.10.0.dev7}/microsoft_agents_authentication_msal.egg-info/dependency_links.txt +0 -0
  20. {microsoft_agents_authentication_msal-1.10.0.dev5 → microsoft_agents_authentication_msal-1.10.0.dev7}/microsoft_agents_authentication_msal.egg-info/top_level.txt +0 -0
  21. {microsoft_agents_authentication_msal-1.10.0.dev5 → microsoft_agents_authentication_msal-1.10.0.dev7}/pyproject.toml +0 -0
  22. {microsoft_agents_authentication_msal-1.10.0.dev5 → microsoft_agents_authentication_msal-1.10.0.dev7}/setup.cfg +0 -0
  23. {microsoft_agents_authentication_msal-1.10.0.dev5 → microsoft_agents_authentication_msal-1.10.0.dev7}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: microsoft-agents-authentication-msal
3
- Version: 1.10.0.dev5
3
+ Version: 1.10.0.dev7
4
4
  Summary: A msal-based authentication library for Microsoft Agents
5
5
  Author: Microsoft Corporation
6
6
  License-Expression: MIT
@@ -15,7 +15,7 @@ Classifier: Operating System :: OS Independent
15
15
  Requires-Python: >=3.10
16
16
  Description-Content-Type: text/markdown
17
17
  License-File: LICENSE
18
- Requires-Dist: microsoft-agents-hosting-core==1.10.0.dev5
18
+ Requires-Dist: microsoft-agents-hosting-core==1.10.0.dev7
19
19
  Requires-Dist: azure-core
20
20
  Requires-Dist: msal>=1.34.0
21
21
  Requires-Dist: requests>=2.32.3
@@ -253,6 +253,36 @@ def start_server(
253
253
  [...]
254
254
  ```
255
255
 
256
+ ## Typed Connection Settings
257
+
258
+ `MsalAuth` accepts `Configuration` or `MsalConnectionSettings` as well as the existing
259
+ `AgentAuthConfiguration` input. Use `provider.config` to read bound MSAL settings.
260
+
261
+ ```python
262
+ from microsoft_agents.activity.config import Configuration
263
+ from microsoft_agents.authentication.msal import MsalConnectionManager
264
+
265
+ connections = MsalConnectionManager(
266
+ config=Configuration(
267
+ connections={
268
+ "SERVICE_CONNECTION": {
269
+ "settings": {
270
+ "auth_type": "ClientSecret",
271
+ "client_id": "your-client-id",
272
+ "tenant_id": "your-tenant-id",
273
+ "client_secret": "your-client-secret",
274
+ }
275
+ }
276
+ }
277
+ )
278
+ )
279
+ settings = connections.get_default_connection().config
280
+ ```
281
+
282
+ Load credentials from your application's secure configuration rather than hardcoding
283
+ them. Legacy constructor calls and the `provider.configuration` compatibility view
284
+ remain supported. Token credentials reuse the provider's bound settings.
285
+
256
286
  ## Authentication Types
257
287
  The M365 Agents SDK in Python supports the following Auth types:
258
288
  ```python
@@ -0,0 +1 @@
1
+ 1.10.0.dev7
@@ -4,8 +4,10 @@
4
4
  from .msal_auth import MsalAuth
5
5
  from .msal_connection_manager import MsalConnectionManager
6
6
  from .msal_token_credential import MsalTokenCredential
7
+ from .connection_settings import MsalConnectionSettings
7
8
 
8
9
  __all__ = [
10
+ "MsalConnectionSettings",
9
11
  "MsalAuth",
10
12
  "MsalConnectionManager",
11
13
  "MsalTokenCredential",
@@ -0,0 +1,87 @@
1
+ # Copyright (c) Microsoft Corporation. All rights reserved.
2
+ # Licensed under the MIT License.
3
+
4
+ from dataclasses import dataclass, field
5
+
6
+ from microsoft_agents.activity.config import Configuration, xpath
7
+ from microsoft_agents.hosting.core import (
8
+ AgentAuthConfiguration,
9
+ AuthTypes,
10
+ ConnectionSettingsBase,
11
+ )
12
+
13
+
14
+ @dataclass(frozen=True)
15
+ class MsalConnectionSettings(ConnectionSettingsBase):
16
+ """MSAL-specific settings, bound independently of inbound JWT policy."""
17
+
18
+ auth_type: str = AuthTypes.client_secret
19
+ client_secret: str | None = field(default=None, repr=False)
20
+ cert_pfx_file: str | None = None
21
+ send_x5c: bool = False
22
+ connection_name: str | None = None
23
+ federated_client_id: str | None = None
24
+ federated_token_file: str | None = None
25
+ idpm_resource: str | None = None
26
+ azure_region: str | None = None
27
+
28
+ def __post_init__(self):
29
+ if self.auth_type == AuthTypes.certificate and not self.cert_pfx_file:
30
+ raise ValueError(
31
+ "CERT_PFX_FILE is required for certificate authentication."
32
+ )
33
+ if (
34
+ self.auth_type == AuthTypes.federated_credentials
35
+ and not self.federated_client_id
36
+ ):
37
+ raise ValueError(
38
+ "FEDERATED_CLIENT_ID is required for federated_credentials authentication."
39
+ )
40
+ if (
41
+ self.auth_type == AuthTypes.workload_identity
42
+ and not self.federated_token_file
43
+ ):
44
+ raise ValueError(
45
+ "FEDERATED_TOKEN_FILE is required for workload_identity authentication."
46
+ )
47
+
48
+ @classmethod
49
+ def _get_init_kwargs(cls, config: Configuration) -> dict:
50
+ base = super()._get_init_kwargs(config)
51
+ base.update(
52
+ {
53
+ "auth_type": config.get_str(
54
+ xpath("auth_type"), default=AuthTypes.client_secret
55
+ ),
56
+ "client_secret": config.get_strn(xpath("client_secret")),
57
+ "cert_pfx_file": config.get_strn(xpath("cert_pfx_file")),
58
+ "send_x5c": config.get_bool(xpath("send_x5c"), default=False),
59
+ "connection_name": config.get_strn(xpath("connection_name")),
60
+ "federated_client_id": config.get_strn(xpath("federated_client_id")),
61
+ "federated_token_file": config.get_strn(xpath("federated_token_file")),
62
+ "idpm_resource": config.get_strn(xpath("idpm_resource")),
63
+ "azure_region": config.get_strn(
64
+ xpath("azure_region"), xpath("regional_authority")
65
+ ),
66
+ }
67
+ )
68
+ return base
69
+
70
+ def _to_agent_auth_config(self) -> AgentAuthConfiguration:
71
+ fields = dict(
72
+ auth_type=self.auth_type,
73
+ client_id=self.client_id,
74
+ tenant_id=self.tenant_id,
75
+ authority=self.authority,
76
+ client_secret=self.client_secret,
77
+ cert_pfx_file=self.cert_pfx_file,
78
+ send_x5c=self.send_x5c,
79
+ connection_name=self.connection_name,
80
+ federated_client_id=self.federated_client_id,
81
+ federated_token_file=self.federated_token_file,
82
+ ALT_BLUEPRINT_NAME=self.alternate_blueprint_connection_name,
83
+ idpm_resource=self.idpm_resource,
84
+ azure_region=self.azure_region,
85
+ scopes=self.scopes,
86
+ )
87
+ return AgentAuthConfiguration(**{**self.extras, **fields})
@@ -8,7 +8,8 @@ import asyncio
8
8
  import logging
9
9
  import time
10
10
  import jwt
11
- from typing import Optional
11
+ import warnings
12
+
12
13
  from urllib.parse import urlparse, ParseResult as URI
13
14
  from msal import (
14
15
  ConfidentialClientApplication,
@@ -23,6 +24,7 @@ from azure.core.credentials_async import AsyncTokenCredential
23
24
 
24
25
  from requests import Session
25
26
 
27
+ from microsoft_agents.activity.config import Configuration
26
28
  from microsoft_agents.activity._utils import _DeferredString
27
29
 
28
30
  from microsoft_agents.hosting.core import (
@@ -31,7 +33,8 @@ from microsoft_agents.hosting.core import (
31
33
  AgentAuthConfiguration,
32
34
  )
33
35
  from microsoft_agents.hosting.core.authorization.telemetry import spans
34
- from microsoft_agents.authentication.msal.errors import authentication_errors
36
+ from .connection_settings import MsalConnectionSettings
37
+ from .errors import authentication_errors
35
38
 
36
39
  logger = logging.getLogger(__name__)
37
40
 
@@ -47,29 +50,69 @@ async def _async_acquire_token_for_client(msal_auth_client, *args, **kwargs):
47
50
 
48
51
  class MsalAuth(AccessTokenProviderBase):
49
52
 
50
- def __init__(self, msal_configuration: AgentAuthConfiguration):
53
+ def __init__(
54
+ self,
55
+ msal_configuration: (
56
+ Configuration | MsalConnectionSettings | AgentAuthConfiguration
57
+ ),
58
+ ):
51
59
  """Initializes the MsalAuth class with the given configuration.
52
60
 
53
- :param msal_configuration: The MSAL authentication configuration. Assumed to
54
- not be mutated after being passed in.
55
- :type msal_configuration: :class:`microsoft_agents.hosting.core.authorization.agent_auth_configuration.AgentAuthConfiguration`
61
+ :param msal_configuration: Raw Configuration or bound MsalConnectionSettings.
62
+ AgentAuthConfiguration remains accepted for deprecated compatibility.
63
+ Do not mutate settings or their nested values after passing them in.
64
+ :type config: Configuration | MsalConnectionSettings | AgentAuthConfiguration
56
65
  """
66
+ config = msal_configuration
67
+ if isinstance(config, MsalConnectionSettings):
68
+ self._deprecated_config = None
69
+ _msal_configuration = config
70
+ elif isinstance(config, Configuration):
71
+ self._deprecated_config = None
72
+ _msal_configuration = MsalConnectionSettings.from_configuration(config)
73
+ else:
74
+ warnings.warn(
75
+ "AgentAuthConfiguration is deprecated and will be removed in future versions. "
76
+ "Please pass a config of type Mapping instead.",
77
+ DeprecationWarning,
78
+ stacklevel=2,
79
+ )
80
+ self._deprecated_config = config
81
+ _msal_configuration = MsalConnectionSettings._from_agent_auth_config(config)
57
82
 
58
- self._msal_configuration = msal_configuration
83
+ self._msal_configuration = _msal_configuration
59
84
  self._msal_auth_client_map: dict[
60
85
  str, ConfidentialClientApplication | ManagedIdentityClient
61
86
  ] = {}
62
87
 
63
88
  # TokenCache is thread-safe and async-safe per MSAL documentation
64
89
  self._token_cache = TokenCache()
65
- logger.debug("Initializing MsalAuth")
90
+ logger.debug("Initializing MsalAuth provider.")
66
91
 
67
92
  @property
68
93
  def configuration(self) -> AgentAuthConfiguration:
69
- """Returns the MSAL authentication configuration.
94
+ """Return the deprecated AgentAuthConfiguration compatibility view.
95
+
96
+ Use :attr:`config` for the bound MsalConnectionSettings instead.
70
97
 
71
- :return: The MSAL authentication configuration.
72
- :rtype: :class:`microsoft_agents.hosting.core.authorization.agent_auth_configuration.AgentAuthConfiguration`
98
+ :return: The legacy authentication configuration.
99
+ :rtype: AgentAuthConfiguration
100
+ """
101
+ warnings.warn(
102
+ "Accessing the deprecated configuration. This will be removed in future versions.",
103
+ DeprecationWarning,
104
+ stacklevel=2,
105
+ )
106
+ if self._deprecated_config is None:
107
+ self._deprecated_config = self._msal_configuration._to_agent_auth_config()
108
+ return self._deprecated_config
109
+
110
+ @property
111
+ def config(self) -> MsalConnectionSettings:
112
+ """Return the bound MSAL settings; nested mutable values remain mutable.
113
+
114
+ :return: The MSAL connection settings.
115
+ :rtype: MsalConnectionSettings
73
116
  """
74
117
  return self._msal_configuration
75
118
 
@@ -110,12 +153,10 @@ class MsalAuth(AccessTokenProviderBase):
110
153
  """
111
154
  with spans.GetAccessToken(
112
155
  scopes,
113
- self._msal_configuration.AUTH_TYPE,
156
+ self._msal_configuration.auth_type,
114
157
  ):
115
158
  logger.debug(
116
- "Requesting access token for resource: %s, scopes: %s",
117
- resource_url,
118
- scopes,
159
+ f"Requesting access token for resource: {resource_url}, scopes: {scopes}"
119
160
  )
120
161
  valid_uri, instance_uri = self._uri_validator(resource_url)
121
162
  if not valid_uri:
@@ -191,7 +232,7 @@ class MsalAuth(AccessTokenProviderBase):
191
232
  )
192
233
 
193
234
  if "access_token" not in token:
194
- logger.error("Failed to acquire token on behalf of user.")
235
+ logger.error(f"Failed to acquire token on behalf of user.")
195
236
  raise ValueError(
196
237
  authentication_errors.FailedToAcquireToken.format(str(token))
197
238
  )
@@ -199,8 +240,7 @@ class MsalAuth(AccessTokenProviderBase):
199
240
  return token["access_token"]
200
241
 
201
242
  logger.error(
202
- "On-behalf-of flow is not supported with the current authentication type: %s",
203
- msal_auth_client.__class__.__name__,
243
+ f"On-behalf-of flow is not supported with the current authentication type: {msal_auth_client.__class__.__name__}"
204
244
  )
205
245
  raise NotImplementedError(
206
246
  authentication_errors.OnBehalfOfFlowNotSupportedAuthType.format(
@@ -210,49 +250,49 @@ class MsalAuth(AccessTokenProviderBase):
210
250
 
211
251
  @staticmethod
212
252
  def _resolve_authority(
213
- config: AgentAuthConfiguration, tenant_id: str | None = None
253
+ config: MsalConnectionSettings, tenant_id: str | None = None
214
254
  ) -> str:
215
255
  tenant_id = MsalAuth._resolve_tenant_id(config, tenant_id)
216
256
  if not tenant_id:
217
257
  return (
218
- config.AUTHORITY
219
- or f"https://login.microsoftonline.com/{config.TENANT_ID}"
258
+ config.authority
259
+ or f"https://login.microsoftonline.com/{config.tenant_id}"
220
260
  )
221
261
 
222
- if config.AUTHORITY:
262
+ if config.authority:
223
263
  return re.sub(
224
264
  r"/(?:common|[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})(?=/|$)",
225
265
  f"/{tenant_id}",
226
- config.AUTHORITY,
266
+ config.authority,
227
267
  )
228
268
 
229
269
  return f"https://login.microsoftonline.com/{tenant_id}"
230
270
 
231
271
  @staticmethod
232
- def _resolve_azure_region(config: AgentAuthConfiguration) -> str | None:
272
+ def _resolve_azure_region(config: MsalConnectionSettings) -> str | None:
233
273
  """Resolves the Azure regional token service (ESTS-R) to use, if configured.
234
274
 
235
- :param config: The agent authentication configuration.
236
- :type config: :class:`microsoft_agents.hosting.core.AgentAuthConfiguration`
275
+ :param config: The bound MSAL connection settings.
276
+ :type config: :class:`microsoft_agents.authentication.msal.MsalConnectionSettings`
237
277
  :return: The resolved Azure region or None if not configured.
238
278
  :rtype: str | None
239
279
 
240
280
  Returns the configured region only when it is populated and non-whitespace,
241
281
  otherwise None so that MSAL falls back to the global token service.
242
282
  """
243
- azure_region = getattr(config, "AZURE_REGION", None)
283
+ azure_region = config.azure_region
244
284
  if azure_region and azure_region.strip():
245
285
  return azure_region
246
286
  return None
247
287
 
248
288
  @staticmethod
249
- def _resolve_idpm_resource(config: AgentAuthConfiguration) -> str:
289
+ def _resolve_idpm_resource(config: MsalConnectionSettings) -> str:
250
290
  """Resolves the resource URL for Identity Proxy Manager (IDPM) token acquisition.
251
291
 
252
292
  When no resource is configured, defaults to the AzureAdTokenExchange resource.
253
293
  Otherwise the configured value must be a valid absolute URI.
254
294
  """
255
- idpm_resource = getattr(config, "IDPM_RESOURCE", None)
295
+ idpm_resource = config.idpm_resource
256
296
  if not idpm_resource:
257
297
  return "api://AzureAdTokenExchange/.default"
258
298
 
@@ -264,35 +304,35 @@ class MsalAuth(AccessTokenProviderBase):
264
304
 
265
305
  @staticmethod
266
306
  def _resolve_tenant_id(
267
- config: AgentAuthConfiguration, tenant_id: str | None = None
307
+ config: MsalConnectionSettings, tenant_id: str | None = None
268
308
  ) -> str:
269
309
 
270
- if not config.TENANT_ID:
310
+ if not config.tenant_id:
271
311
  if tenant_id:
272
312
  return tenant_id
273
313
  raise ValueError("TENANT_ID is not set in the configuration.")
274
314
 
275
- if tenant_id or config.TENANT_ID.lower() == "common":
315
+ if tenant_id or config.tenant_id.lower() == "common":
276
316
  return tenant_id
277
317
 
278
- return config.TENANT_ID
318
+ return config.tenant_id
279
319
 
280
320
  def _create_client_application(
281
321
  self, tenant_id: str | None = None
282
322
  ) -> ConfidentialClientApplication | ManagedIdentityClient:
283
323
 
284
- if self._msal_configuration.AUTH_TYPE in (
324
+ if self._msal_configuration.auth_type in (
285
325
  AuthTypes.user_managed_identity,
286
326
  AuthTypes.identity_proxy_manager,
287
327
  ):
288
328
  return ManagedIdentityClient(
289
329
  UserAssignedManagedIdentity(
290
- client_id=self._msal_configuration.CLIENT_ID
330
+ client_id=self._msal_configuration.client_id
291
331
  ),
292
332
  http_client=Session(),
293
333
  )
294
334
 
295
- elif self._msal_configuration.AUTH_TYPE == AuthTypes.system_managed_identity:
335
+ elif self._msal_configuration.auth_type == AuthTypes.system_managed_identity:
296
336
  return ManagedIdentityClient(
297
337
  SystemAssignedManagedIdentity(),
298
338
  http_client=Session(),
@@ -301,18 +341,18 @@ class MsalAuth(AccessTokenProviderBase):
301
341
  authority = MsalAuth._resolve_authority(self._msal_configuration, tenant_id)
302
342
  client_credential = None
303
343
 
304
- if self._msal_configuration.AUTH_TYPE == AuthTypes.client_secret:
305
- client_credential = self._msal_configuration.CLIENT_SECRET
306
- elif self._msal_configuration.AUTH_TYPE == AuthTypes.certificate:
344
+ if self._msal_configuration.auth_type == AuthTypes.client_secret:
345
+ client_credential = self._msal_configuration.client_secret
346
+ elif self._msal_configuration.auth_type == AuthTypes.certificate:
307
347
  client_credential = {
308
- "private_key_pfx_path": self._msal_configuration.CERT_PFX_FILE,
348
+ "private_key_pfx_path": self._msal_configuration.cert_pfx_file,
309
349
  }
310
- if self._msal_configuration.SEND_X5C:
350
+ if self._msal_configuration.send_x5c:
311
351
  client_credential["public_certificate"] = True
312
- elif self._msal_configuration.AUTH_TYPE == AuthTypes.federated_credentials:
352
+ elif self._msal_configuration.auth_type == AuthTypes.federated_credentials:
313
353
  mi_client = ManagedIdentityClient(
314
354
  UserAssignedManagedIdentity(
315
- client_id=self._msal_configuration.FEDERATED_CLIENT_ID
355
+ client_id=self._msal_configuration.federated_client_id
316
356
  ),
317
357
  http_client=Session(),
318
358
  )
@@ -323,8 +363,7 @@ class MsalAuth(AccessTokenProviderBase):
323
363
  )
324
364
  if "access_token" not in result:
325
365
  logger.error(
326
- "Failed to acquire token for federated credentials: %s",
327
- result,
366
+ f"Failed to acquire token for federated credentials: {result}"
328
367
  )
329
368
  raise ValueError(
330
369
  authentication_errors.FailedToAcquireToken.format(
@@ -334,13 +373,13 @@ class MsalAuth(AccessTokenProviderBase):
334
373
  return result["access_token"]
335
374
 
336
375
  client_credential = {"client_assertion": get_assertion}
337
- elif self._msal_configuration.AUTH_TYPE == AuthTypes.workload_identity:
338
- if not self._msal_configuration.FEDERATED_TOKEN_FILE:
376
+ elif self._msal_configuration.auth_type == AuthTypes.workload_identity:
377
+ if not self._msal_configuration.federated_token_file:
339
378
  raise ValueError(
340
379
  "FEDERATED_TOKEN_FILE must be set in configuration."
341
380
  )
342
381
 
343
- federated_token_file = self._msal_configuration.FEDERATED_TOKEN_FILE
382
+ federated_token_file = self._msal_configuration.federated_token_file
344
383
 
345
384
  def get_assertion() -> str:
346
385
  with open(federated_token_file, encoding="utf-8") as f:
@@ -349,15 +388,14 @@ class MsalAuth(AccessTokenProviderBase):
349
388
  client_credential = {"client_assertion": get_assertion}
350
389
  else:
351
390
  logger.error(
352
- "Unsupported authentication type: %s",
353
- self._msal_configuration.AUTH_TYPE,
391
+ f"Unsupported authentication type: {self._msal_configuration.auth_type}"
354
392
  )
355
393
  raise NotImplementedError(
356
394
  str(authentication_errors.AuthenticationTypeNotSupported)
357
395
  )
358
396
 
359
397
  return ConfidentialClientApplication(
360
- client_id=self._msal_configuration.CLIENT_ID,
398
+ client_id=self._msal_configuration.client_id,
361
399
  authority=authority,
362
400
  client_credential=client_credential,
363
401
  azure_region=MsalAuth._resolve_azure_region(self._msal_configuration),
@@ -368,7 +406,7 @@ class MsalAuth(AccessTokenProviderBase):
368
406
  ) -> str:
369
407
  # Create a unique representation for the client based on tenant_id and instance_id
370
408
  # instance_id None is for when no agentic instance is associated with the request.
371
- tenant_id = tenant_id or self._msal_configuration.TENANT_ID
409
+ tenant_id = tenant_id or self._msal_configuration.tenant_id
372
410
  return f"tenant:{tenant_id}.instance:{instance_id}"
373
411
 
374
412
  def _get_client(
@@ -388,7 +426,7 @@ class MsalAuth(AccessTokenProviderBase):
388
426
  result = urlparse(url_str)
389
427
  return all([result.scheme, result.netloc]), result
390
428
  except AttributeError:
391
- logger.error("URI parsing error for %s", url_str)
429
+ logger.error(f"URI parsing error for {url_str}")
392
430
  return False, None
393
431
 
394
432
  def _resolve_scopes_list(self, instance_url: URI, scopes=None) -> list[str]:
@@ -396,7 +434,7 @@ class MsalAuth(AccessTokenProviderBase):
396
434
  return scopes
397
435
 
398
436
  temp_list: list[str] = []
399
- lst = self._msal_configuration.SCOPES or []
437
+ lst = self._msal_configuration.scopes or []
400
438
  for scope in lst:
401
439
  scope_placeholder = scope
402
440
  if "{instance}" in scope_placeholder.lower():
@@ -404,7 +442,7 @@ class MsalAuth(AccessTokenProviderBase):
404
442
  "{instance}", f"{instance_url.scheme}://{instance_url.hostname}"
405
443
  )
406
444
  temp_list.append(scope_placeholder)
407
- logger.debug("Resolved scopes: %s", temp_list)
445
+ logger.debug(f"Resolved scopes: {temp_list}")
408
446
  return temp_list
409
447
 
410
448
  # the call to MSAL is blocking, but in the future we want to create an asyncio task
@@ -446,7 +484,7 @@ class MsalAuth(AccessTokenProviderBase):
446
484
  return None
447
485
 
448
486
  if (
449
- self._msal_configuration.AUTH_TYPE == AuthTypes.identity_proxy_manager
487
+ self._msal_configuration.auth_type == AuthTypes.identity_proxy_manager
450
488
  and isinstance(msal_auth_client, ManagedIdentityClient)
451
489
  ):
452
490
  resource = MsalAuth._resolve_idpm_resource(self._msal_configuration)
@@ -1,6 +1,7 @@
1
1
  # Copyright (c) Microsoft Corporation. All rights reserved.
2
2
  # Licensed under the MIT License.
3
3
 
4
+ from microsoft_agents.activity.config import Configuration
4
5
  from microsoft_agents.hosting.core import (
5
6
  AgentAuthConfiguration,
6
7
  ConnectionManager,
@@ -23,15 +24,20 @@ class MsalConnectionManager(ConnectionManager):
23
24
  self,
24
25
  connections_configurations: dict[str, AgentAuthConfiguration] | None = None,
25
26
  connections_map: list[dict[str, str]] | None = None,
27
+ *,
28
+ config: Configuration | None = None,
26
29
  **kwargs,
27
30
  ):
28
31
  """
29
32
  Initialize the MSAL connection manager.
30
33
 
31
- :param connections_configurations: A dictionary of connection configurations.
34
+ :param connections_configurations: Deprecated legacy connection configurations.
32
35
  :type connections_configurations: dict[str, :class:`microsoft_agents.hosting.core.AgentAuthConfiguration`]
33
- :param connections_map: A list of connection mappings.
36
+ :param connections_map: Deprecated list of connection mappings.
34
37
  :type connections_map: list[dict[str, str]]
38
+ :param config: Application Configuration containing connections and routing.
39
+ Prefer this over the deprecated positional configuration arguments.
40
+ :type config: Configuration | None
35
41
  :raises ValueError: If no service connection configuration is provided.
36
42
  """
37
43
 
@@ -39,5 +45,6 @@ class MsalConnectionManager(ConnectionManager):
39
45
  provider_factory=MsalAuth,
40
46
  connections_configurations=connections_configurations,
41
47
  connections_map=connections_map,
48
+ config=config,
42
49
  **kwargs,
43
50
  )
@@ -8,6 +8,7 @@ from azure.core.credentials_async import AsyncTokenCredential
8
8
 
9
9
  from microsoft_agents.hosting.core import AgentAuthConfiguration
10
10
 
11
+ from .connection_settings import MsalConnectionSettings
11
12
  from .msal_auth import MsalAuth
12
13
 
13
14
  logger = logging.getLogger(__name__)
@@ -28,14 +29,16 @@ class MsalTokenCredential(AsyncTokenCredential):
28
29
 
29
30
  def __init__(
30
31
  self,
31
- config: AgentAuthConfiguration,
32
+ config: MsalConnectionSettings | AgentAuthConfiguration,
32
33
  *,
33
34
  provider: MsalAuth | None = None,
34
35
  ):
35
36
  """Initializes the MsalTokenCredential with the given configuration.
36
37
 
37
- :param config: The agent authentication configuration.
38
- :type config: :class:`microsoft_agents.hosting.core.AgentAuthConfiguration`
38
+ :param config: Bound MSAL settings. AgentAuthConfiguration remains accepted
39
+ for deprecated compatibility.
40
+ :type config: MsalConnectionSettings | AgentAuthConfiguration
41
+ :param provider: An existing provider to reuse instead of constructing one.
39
42
  """
40
43
  self._config = config
41
44
  self._provider: MsalAuth | None = provider
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: microsoft-agents-authentication-msal
3
- Version: 1.10.0.dev5
3
+ Version: 1.10.0.dev7
4
4
  Summary: A msal-based authentication library for Microsoft Agents
5
5
  Author: Microsoft Corporation
6
6
  License-Expression: MIT
@@ -15,7 +15,7 @@ Classifier: Operating System :: OS Independent
15
15
  Requires-Python: >=3.10
16
16
  Description-Content-Type: text/markdown
17
17
  License-File: LICENSE
18
- Requires-Dist: microsoft-agents-hosting-core==1.10.0.dev5
18
+ Requires-Dist: microsoft-agents-hosting-core==1.10.0.dev7
19
19
  Requires-Dist: azure-core
20
20
  Requires-Dist: msal>=1.34.0
21
21
  Requires-Dist: requests>=2.32.3
@@ -253,6 +253,36 @@ def start_server(
253
253
  [...]
254
254
  ```
255
255
 
256
+ ## Typed Connection Settings
257
+
258
+ `MsalAuth` accepts `Configuration` or `MsalConnectionSettings` as well as the existing
259
+ `AgentAuthConfiguration` input. Use `provider.config` to read bound MSAL settings.
260
+
261
+ ```python
262
+ from microsoft_agents.activity.config import Configuration
263
+ from microsoft_agents.authentication.msal import MsalConnectionManager
264
+
265
+ connections = MsalConnectionManager(
266
+ config=Configuration(
267
+ connections={
268
+ "SERVICE_CONNECTION": {
269
+ "settings": {
270
+ "auth_type": "ClientSecret",
271
+ "client_id": "your-client-id",
272
+ "tenant_id": "your-tenant-id",
273
+ "client_secret": "your-client-secret",
274
+ }
275
+ }
276
+ }
277
+ )
278
+ )
279
+ settings = connections.get_default_connection().config
280
+ ```
281
+
282
+ Load credentials from your application's secure configuration rather than hardcoding
283
+ them. Legacy constructor calls and the `provider.configuration` compatibility view
284
+ remain supported. Token credentials reuse the provider's bound settings.
285
+
256
286
  ## Authentication Types
257
287
  The M365 Agents SDK in Python supports the following Auth types:
258
288
  ```python
@@ -5,6 +5,7 @@ pyproject.toml
5
5
  readme.md
6
6
  setup.py
7
7
  microsoft_agents/authentication/msal/__init__.py
8
+ microsoft_agents/authentication/msal/connection_settings.py
8
9
  microsoft_agents/authentication/msal/msal_auth.py
9
10
  microsoft_agents/authentication/msal/msal_connection_manager.py
10
11
  microsoft_agents/authentication/msal/msal_token_credential.py
@@ -0,0 +1,4 @@
1
+ microsoft-agents-hosting-core==1.10.0.dev7
2
+ azure-core
3
+ msal>=1.34.0
4
+ requests>=2.32.3
@@ -229,6 +229,36 @@ def start_server(
229
229
  [...]
230
230
  ```
231
231
 
232
+ ## Typed Connection Settings
233
+
234
+ `MsalAuth` accepts `Configuration` or `MsalConnectionSettings` as well as the existing
235
+ `AgentAuthConfiguration` input. Use `provider.config` to read bound MSAL settings.
236
+
237
+ ```python
238
+ from microsoft_agents.activity.config import Configuration
239
+ from microsoft_agents.authentication.msal import MsalConnectionManager
240
+
241
+ connections = MsalConnectionManager(
242
+ config=Configuration(
243
+ connections={
244
+ "SERVICE_CONNECTION": {
245
+ "settings": {
246
+ "auth_type": "ClientSecret",
247
+ "client_id": "your-client-id",
248
+ "tenant_id": "your-tenant-id",
249
+ "client_secret": "your-client-secret",
250
+ }
251
+ }
252
+ }
253
+ )
254
+ )
255
+ settings = connections.get_default_connection().config
256
+ ```
257
+
258
+ Load credentials from your application's secure configuration rather than hardcoding
259
+ them. Legacy constructor calls and the `provider.configuration` compatibility view
260
+ remain supported. Token credentials reuse the provider's bound settings.
261
+
232
262
  ## Authentication Types
233
263
  The M365 Agents SDK in Python supports the following Auth types:
234
264
  ```python
@@ -1 +0,0 @@
1
- 1.10.0.dev5
@@ -1,4 +0,0 @@
1
- microsoft-agents-hosting-core==1.10.0.dev5
2
- azure-core
3
- msal>=1.34.0
4
- requests>=2.32.3