microsoft-agents-authentication-msal 1.10.0.dev5__tar.gz → 1.10.0.dev6__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.dev6}/PKG-INFO +32 -2
  2. microsoft_agents_authentication_msal-1.10.0.dev6/VERSION.txt +1 -0
  3. {microsoft_agents_authentication_msal-1.10.0.dev5 → microsoft_agents_authentication_msal-1.10.0.dev6}/microsoft_agents/authentication/msal/__init__.py +2 -0
  4. microsoft_agents_authentication_msal-1.10.0.dev6/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.dev6}/microsoft_agents/authentication/msal/msal_auth.py +95 -56
  6. {microsoft_agents_authentication_msal-1.10.0.dev5 → microsoft_agents_authentication_msal-1.10.0.dev6}/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.dev6}/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.dev6/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.dev6}/microsoft_agents_authentication_msal.egg-info/SOURCES.txt +1 -0
  10. microsoft_agents_authentication_msal-1.10.0.dev6/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.dev6}/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.dev6}/LICENSE +0 -0
  15. {microsoft_agents_authentication_msal-1.10.0.dev5 → microsoft_agents_authentication_msal-1.10.0.dev6}/MANIFEST.in +0 -0
  16. {microsoft_agents_authentication_msal-1.10.0.dev5 → microsoft_agents_authentication_msal-1.10.0.dev6}/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.dev6}/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.dev6}/microsoft_agents/authentication/msal/py.typed +0 -0
  19. {microsoft_agents_authentication_msal-1.10.0.dev5 → microsoft_agents_authentication_msal-1.10.0.dev6}/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.dev6}/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.dev6}/pyproject.toml +0 -0
  22. {microsoft_agents_authentication_msal-1.10.0.dev5 → microsoft_agents_authentication_msal-1.10.0.dev6}/setup.cfg +0 -0
  23. {microsoft_agents_authentication_msal-1.10.0.dev5 → microsoft_agents_authentication_msal-1.10.0.dev6}/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.dev6
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.dev6
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.dev6
@@ -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,9 @@ import asyncio
8
8
  import logging
9
9
  import time
10
10
  import jwt
11
- from typing import Optional
11
+ import warnings
12
+
13
+ from typing import Any
12
14
  from urllib.parse import urlparse, ParseResult as URI
13
15
  from msal import (
14
16
  ConfidentialClientApplication,
@@ -23,6 +25,7 @@ from azure.core.credentials_async import AsyncTokenCredential
23
25
 
24
26
  from requests import Session
25
27
 
28
+ from microsoft_agents.activity.config import Configuration
26
29
  from microsoft_agents.activity._utils import _DeferredString
27
30
 
28
31
  from microsoft_agents.hosting.core import (
@@ -31,7 +34,8 @@ from microsoft_agents.hosting.core import (
31
34
  AgentAuthConfiguration,
32
35
  )
33
36
  from microsoft_agents.hosting.core.authorization.telemetry import spans
34
- from microsoft_agents.authentication.msal.errors import authentication_errors
37
+ from .connection_settings import MsalConnectionSettings
38
+ from .errors import authentication_errors
35
39
 
36
40
  logger = logging.getLogger(__name__)
37
41
 
@@ -47,29 +51,69 @@ async def _async_acquire_token_for_client(msal_auth_client, *args, **kwargs):
47
51
 
48
52
  class MsalAuth(AccessTokenProviderBase):
49
53
 
50
- def __init__(self, msal_configuration: AgentAuthConfiguration):
54
+ def __init__(
55
+ self,
56
+ msal_configuration: (
57
+ Configuration | MsalConnectionSettings | AgentAuthConfiguration
58
+ ),
59
+ ):
51
60
  """Initializes the MsalAuth class with the given configuration.
52
61
 
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`
62
+ :param msal_configuration: Raw Configuration or bound MsalConnectionSettings.
63
+ AgentAuthConfiguration remains accepted for deprecated compatibility.
64
+ Do not mutate settings or their nested values after passing them in.
65
+ :type config: Configuration | MsalConnectionSettings | AgentAuthConfiguration
56
66
  """
67
+ config = msal_configuration
68
+ if isinstance(config, MsalConnectionSettings):
69
+ self._deprecated_config = None
70
+ _msal_configuration = config
71
+ elif isinstance(config, Configuration):
72
+ self._deprecated_config = None
73
+ _msal_configuration = MsalConnectionSettings.from_configuration(config)
74
+ else:
75
+ warnings.warn(
76
+ "AgentAuthConfiguration is deprecated and will be removed in future versions. "
77
+ "Please pass a config of type Mapping instead.",
78
+ DeprecationWarning,
79
+ stacklevel=2,
80
+ )
81
+ self._deprecated_config = config
82
+ _msal_configuration = MsalConnectionSettings._from_agent_auth_config(config)
57
83
 
58
- self._msal_configuration = msal_configuration
84
+ self._msal_configuration = _msal_configuration
59
85
  self._msal_auth_client_map: dict[
60
86
  str, ConfidentialClientApplication | ManagedIdentityClient
61
87
  ] = {}
62
88
 
63
89
  # TokenCache is thread-safe and async-safe per MSAL documentation
64
90
  self._token_cache = TokenCache()
65
- logger.debug("Initializing MsalAuth")
91
+ logger.debug("Initializing MsalAuth provider.")
66
92
 
67
93
  @property
68
94
  def configuration(self) -> AgentAuthConfiguration:
69
- """Returns the MSAL authentication configuration.
95
+ """Return the deprecated AgentAuthConfiguration compatibility view.
96
+
97
+ Use :attr:`config` for the bound MsalConnectionSettings instead.
70
98
 
71
- :return: The MSAL authentication configuration.
72
- :rtype: :class:`microsoft_agents.hosting.core.authorization.agent_auth_configuration.AgentAuthConfiguration`
99
+ :return: The legacy authentication configuration.
100
+ :rtype: AgentAuthConfiguration
101
+ """
102
+ warnings.warn(
103
+ "Accessing the deprecated configuration. This will be removed in future versions.",
104
+ DeprecationWarning,
105
+ stacklevel=2,
106
+ )
107
+ if self._deprecated_config is None:
108
+ self._deprecated_config = self._msal_configuration._to_agent_auth_config()
109
+ return self._deprecated_config
110
+
111
+ @property
112
+ def config(self) -> MsalConnectionSettings:
113
+ """Return the bound MSAL settings; nested mutable values remain mutable.
114
+
115
+ :return: The MSAL connection settings.
116
+ :rtype: MsalConnectionSettings
73
117
  """
74
118
  return self._msal_configuration
75
119
 
@@ -110,12 +154,10 @@ class MsalAuth(AccessTokenProviderBase):
110
154
  """
111
155
  with spans.GetAccessToken(
112
156
  scopes,
113
- self._msal_configuration.AUTH_TYPE,
157
+ self._msal_configuration.auth_type,
114
158
  ):
115
159
  logger.debug(
116
- "Requesting access token for resource: %s, scopes: %s",
117
- resource_url,
118
- scopes,
160
+ f"Requesting access token for resource: {resource_url}, scopes: {scopes}"
119
161
  )
120
162
  valid_uri, instance_uri = self._uri_validator(resource_url)
121
163
  if not valid_uri:
@@ -191,7 +233,7 @@ class MsalAuth(AccessTokenProviderBase):
191
233
  )
192
234
 
193
235
  if "access_token" not in token:
194
- logger.error("Failed to acquire token on behalf of user.")
236
+ logger.error(f"Failed to acquire token on behalf of user.")
195
237
  raise ValueError(
196
238
  authentication_errors.FailedToAcquireToken.format(str(token))
197
239
  )
@@ -199,8 +241,7 @@ class MsalAuth(AccessTokenProviderBase):
199
241
  return token["access_token"]
200
242
 
201
243
  logger.error(
202
- "On-behalf-of flow is not supported with the current authentication type: %s",
203
- msal_auth_client.__class__.__name__,
244
+ f"On-behalf-of flow is not supported with the current authentication type: {msal_auth_client.__class__.__name__}"
204
245
  )
205
246
  raise NotImplementedError(
206
247
  authentication_errors.OnBehalfOfFlowNotSupportedAuthType.format(
@@ -210,49 +251,49 @@ class MsalAuth(AccessTokenProviderBase):
210
251
 
211
252
  @staticmethod
212
253
  def _resolve_authority(
213
- config: AgentAuthConfiguration, tenant_id: str | None = None
254
+ config: MsalConnectionSettings, tenant_id: str | None = None
214
255
  ) -> str:
215
256
  tenant_id = MsalAuth._resolve_tenant_id(config, tenant_id)
216
257
  if not tenant_id:
217
258
  return (
218
- config.AUTHORITY
219
- or f"https://login.microsoftonline.com/{config.TENANT_ID}"
259
+ config.authority
260
+ or f"https://login.microsoftonline.com/{config.tenant_id}"
220
261
  )
221
262
 
222
- if config.AUTHORITY:
263
+ if config.authority:
223
264
  return re.sub(
224
265
  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
266
  f"/{tenant_id}",
226
- config.AUTHORITY,
267
+ config.authority,
227
268
  )
228
269
 
229
270
  return f"https://login.microsoftonline.com/{tenant_id}"
230
271
 
231
272
  @staticmethod
232
- def _resolve_azure_region(config: AgentAuthConfiguration) -> str | None:
273
+ def _resolve_azure_region(config: MsalConnectionSettings) -> str | None:
233
274
  """Resolves the Azure regional token service (ESTS-R) to use, if configured.
234
275
 
235
- :param config: The agent authentication configuration.
236
- :type config: :class:`microsoft_agents.hosting.core.AgentAuthConfiguration`
276
+ :param config: The bound MSAL connection settings.
277
+ :type config: :class:`microsoft_agents.authentication.msal.MsalConnectionSettings`
237
278
  :return: The resolved Azure region or None if not configured.
238
279
  :rtype: str | None
239
280
 
240
281
  Returns the configured region only when it is populated and non-whitespace,
241
282
  otherwise None so that MSAL falls back to the global token service.
242
283
  """
243
- azure_region = getattr(config, "AZURE_REGION", None)
284
+ azure_region = config.azure_region
244
285
  if azure_region and azure_region.strip():
245
286
  return azure_region
246
287
  return None
247
288
 
248
289
  @staticmethod
249
- def _resolve_idpm_resource(config: AgentAuthConfiguration) -> str:
290
+ def _resolve_idpm_resource(config: MsalConnectionSettings) -> str:
250
291
  """Resolves the resource URL for Identity Proxy Manager (IDPM) token acquisition.
251
292
 
252
293
  When no resource is configured, defaults to the AzureAdTokenExchange resource.
253
294
  Otherwise the configured value must be a valid absolute URI.
254
295
  """
255
- idpm_resource = getattr(config, "IDPM_RESOURCE", None)
296
+ idpm_resource = config.idpm_resource
256
297
  if not idpm_resource:
257
298
  return "api://AzureAdTokenExchange/.default"
258
299
 
@@ -264,35 +305,35 @@ class MsalAuth(AccessTokenProviderBase):
264
305
 
265
306
  @staticmethod
266
307
  def _resolve_tenant_id(
267
- config: AgentAuthConfiguration, tenant_id: str | None = None
308
+ config: MsalConnectionSettings, tenant_id: str | None = None
268
309
  ) -> str:
269
310
 
270
- if not config.TENANT_ID:
311
+ if not config.tenant_id:
271
312
  if tenant_id:
272
313
  return tenant_id
273
314
  raise ValueError("TENANT_ID is not set in the configuration.")
274
315
 
275
- if tenant_id or config.TENANT_ID.lower() == "common":
316
+ if tenant_id or config.tenant_id.lower() == "common":
276
317
  return tenant_id
277
318
 
278
- return config.TENANT_ID
319
+ return config.tenant_id
279
320
 
280
321
  def _create_client_application(
281
322
  self, tenant_id: str | None = None
282
323
  ) -> ConfidentialClientApplication | ManagedIdentityClient:
283
324
 
284
- if self._msal_configuration.AUTH_TYPE in (
325
+ if self._msal_configuration.auth_type in (
285
326
  AuthTypes.user_managed_identity,
286
327
  AuthTypes.identity_proxy_manager,
287
328
  ):
288
329
  return ManagedIdentityClient(
289
330
  UserAssignedManagedIdentity(
290
- client_id=self._msal_configuration.CLIENT_ID
331
+ client_id=self._msal_configuration.client_id
291
332
  ),
292
333
  http_client=Session(),
293
334
  )
294
335
 
295
- elif self._msal_configuration.AUTH_TYPE == AuthTypes.system_managed_identity:
336
+ elif self._msal_configuration.auth_type == AuthTypes.system_managed_identity:
296
337
  return ManagedIdentityClient(
297
338
  SystemAssignedManagedIdentity(),
298
339
  http_client=Session(),
@@ -301,18 +342,18 @@ class MsalAuth(AccessTokenProviderBase):
301
342
  authority = MsalAuth._resolve_authority(self._msal_configuration, tenant_id)
302
343
  client_credential = None
303
344
 
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:
345
+ if self._msal_configuration.auth_type == AuthTypes.client_secret:
346
+ client_credential = self._msal_configuration.client_secret
347
+ elif self._msal_configuration.auth_type == AuthTypes.certificate:
307
348
  client_credential = {
308
- "private_key_pfx_path": self._msal_configuration.CERT_PFX_FILE,
349
+ "private_key_pfx_path": self._msal_configuration.cert_pfx_file,
309
350
  }
310
- if self._msal_configuration.SEND_X5C:
351
+ if self._msal_configuration.send_x5c:
311
352
  client_credential["public_certificate"] = True
312
- elif self._msal_configuration.AUTH_TYPE == AuthTypes.federated_credentials:
353
+ elif self._msal_configuration.auth_type == AuthTypes.federated_credentials:
313
354
  mi_client = ManagedIdentityClient(
314
355
  UserAssignedManagedIdentity(
315
- client_id=self._msal_configuration.FEDERATED_CLIENT_ID
356
+ client_id=self._msal_configuration.federated_client_id
316
357
  ),
317
358
  http_client=Session(),
318
359
  )
@@ -323,8 +364,7 @@ class MsalAuth(AccessTokenProviderBase):
323
364
  )
324
365
  if "access_token" not in result:
325
366
  logger.error(
326
- "Failed to acquire token for federated credentials: %s",
327
- result,
367
+ f"Failed to acquire token for federated credentials: {result}"
328
368
  )
329
369
  raise ValueError(
330
370
  authentication_errors.FailedToAcquireToken.format(
@@ -334,13 +374,13 @@ class MsalAuth(AccessTokenProviderBase):
334
374
  return result["access_token"]
335
375
 
336
376
  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:
377
+ elif self._msal_configuration.auth_type == AuthTypes.workload_identity:
378
+ if not self._msal_configuration.federated_token_file:
339
379
  raise ValueError(
340
380
  "FEDERATED_TOKEN_FILE must be set in configuration."
341
381
  )
342
382
 
343
- federated_token_file = self._msal_configuration.FEDERATED_TOKEN_FILE
383
+ federated_token_file = self._msal_configuration.federated_token_file
344
384
 
345
385
  def get_assertion() -> str:
346
386
  with open(federated_token_file, encoding="utf-8") as f:
@@ -349,15 +389,14 @@ class MsalAuth(AccessTokenProviderBase):
349
389
  client_credential = {"client_assertion": get_assertion}
350
390
  else:
351
391
  logger.error(
352
- "Unsupported authentication type: %s",
353
- self._msal_configuration.AUTH_TYPE,
392
+ f"Unsupported authentication type: {self._msal_configuration.auth_type}"
354
393
  )
355
394
  raise NotImplementedError(
356
395
  str(authentication_errors.AuthenticationTypeNotSupported)
357
396
  )
358
397
 
359
398
  return ConfidentialClientApplication(
360
- client_id=self._msal_configuration.CLIENT_ID,
399
+ client_id=self._msal_configuration.client_id,
361
400
  authority=authority,
362
401
  client_credential=client_credential,
363
402
  azure_region=MsalAuth._resolve_azure_region(self._msal_configuration),
@@ -368,7 +407,7 @@ class MsalAuth(AccessTokenProviderBase):
368
407
  ) -> str:
369
408
  # Create a unique representation for the client based on tenant_id and instance_id
370
409
  # 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
410
+ tenant_id = tenant_id or self._msal_configuration.tenant_id
372
411
  return f"tenant:{tenant_id}.instance:{instance_id}"
373
412
 
374
413
  def _get_client(
@@ -388,7 +427,7 @@ class MsalAuth(AccessTokenProviderBase):
388
427
  result = urlparse(url_str)
389
428
  return all([result.scheme, result.netloc]), result
390
429
  except AttributeError:
391
- logger.error("URI parsing error for %s", url_str)
430
+ logger.error(f"URI parsing error for {url_str}")
392
431
  return False, None
393
432
 
394
433
  def _resolve_scopes_list(self, instance_url: URI, scopes=None) -> list[str]:
@@ -396,7 +435,7 @@ class MsalAuth(AccessTokenProviderBase):
396
435
  return scopes
397
436
 
398
437
  temp_list: list[str] = []
399
- lst = self._msal_configuration.SCOPES or []
438
+ lst = self._msal_configuration.scopes or []
400
439
  for scope in lst:
401
440
  scope_placeholder = scope
402
441
  if "{instance}" in scope_placeholder.lower():
@@ -404,7 +443,7 @@ class MsalAuth(AccessTokenProviderBase):
404
443
  "{instance}", f"{instance_url.scheme}://{instance_url.hostname}"
405
444
  )
406
445
  temp_list.append(scope_placeholder)
407
- logger.debug("Resolved scopes: %s", temp_list)
446
+ logger.debug(f"Resolved scopes: {temp_list}")
408
447
  return temp_list
409
448
 
410
449
  # the call to MSAL is blocking, but in the future we want to create an asyncio task
@@ -446,7 +485,7 @@ class MsalAuth(AccessTokenProviderBase):
446
485
  return None
447
486
 
448
487
  if (
449
- self._msal_configuration.AUTH_TYPE == AuthTypes.identity_proxy_manager
488
+ self._msal_configuration.auth_type == AuthTypes.identity_proxy_manager
450
489
  and isinstance(msal_auth_client, ManagedIdentityClient)
451
490
  ):
452
491
  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.dev6
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.dev6
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.dev6
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