From 6b1a98515091c5a1ae831dd6911fa68c8913e0bc Mon Sep 17 00:00:00 2001 From: Rodrigo Brandao Date: Tue, 10 Feb 2026 18:53:39 -0800 Subject: [PATCH 1/3] Draft implementation of FIC auth --- .../authentication/msal/msal_auth.py | 8 +++++ .../hosting/core/app/agent_application.py | 36 ++++++++++++------- .../authorization/agent_auth_configuration.py | 2 ++ .../hosting/core/authorization/auth_types.py | 1 + 4 files changed, 35 insertions(+), 12 deletions(-) diff --git a/libraries/microsoft-agents-authentication-msal/microsoft_agents/authentication/msal/msal_auth.py b/libraries/microsoft-agents-authentication-msal/microsoft_agents/authentication/msal/msal_auth.py index 8c46a7f9..ecfb6560 100644 --- a/libraries/microsoft-agents-authentication-msal/microsoft_agents/authentication/msal/msal_auth.py +++ b/libraries/microsoft-agents-authentication-msal/microsoft_agents/authentication/msal/msal_auth.py @@ -203,6 +203,7 @@ def _create_client_application( SystemAssignedManagedIdentity(), http_client=Session(), ) + else: authority = MsalAuth._resolve_authority(self._msal_configuration, tenant_id) @@ -233,6 +234,13 @@ def _create_client_application( "thumbprint": thumbprint, "private_key": private_key, } + elif self._msal_configuration.AUTH_TYPE == AuthTypes.federated_credentials: + assert self._msal_configuration.FEDERATED_CLIENT_ID + mi_client = ManagedIdentityClient( + SystemAssignedManagedIdentity(), # TODO + http_client=Session(), + ) + self._client_credential_cache = mi_client.acquire_token_for_client(resource=self._msal_configuration.FEDERATED_CLIENT_ID) else: logger.error( f"Unsupported authentication type: {self._msal_configuration.AUTH_TYPE}" diff --git a/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/app/agent_application.py b/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/app/agent_application.py index d0eb6c1e..60875a0e 100644 --- a/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/app/agent_application.py +++ b/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/app/agent_application.py @@ -120,9 +120,11 @@ def __init__( "ApplicationOptions.storage is required and was not configured.", stack_info=True, ) - raise ApplicationError(""" + raise ApplicationError( + """ The `ApplicationOptions.storage` property is required and was not configured. - """) + """ + ) if options.long_running_messages and ( not options.adapter or not options.bot_app_id @@ -131,10 +133,12 @@ def __init__( "ApplicationOptions.long_running_messages requires an adapter and bot_app_id.", stack_info=True, ) - raise ApplicationError(""" + raise ApplicationError( + """ The `ApplicationOptions.long_running_messages` property is unavailable because no adapter or `bot_app_id` was configured. - """) + """ + ) if options.adapter: self._adapter = options.adapter @@ -176,10 +180,12 @@ def adapter(self) -> ChannelServiceAdapter: "AgentApplication.adapter(): self._adapter is not configured.", stack_info=True, ) - raise ApplicationError(""" + raise ApplicationError( + """ The AgentApplication.adapter property is unavailable because it was not configured when creating the AgentApplication. - """) + """ + ) return self._adapter @@ -197,10 +203,12 @@ def auth(self) -> Authorization: "AgentApplication.auth(): self._auth is not configured.", stack_info=True, ) - raise ApplicationError(""" + raise ApplicationError( + """ The `AgentApplication.auth` property is unavailable because no Auth options were configured. - """) + """ + ) return self._auth @@ -584,10 +592,12 @@ async def sign_in_success(context: TurnContext, state: TurnState, connection_id: f"Failed to register sign-in success handler for route handler {func.__name__}", stack_info=True, ) - raise ApplicationError(""" + raise ApplicationError( + """ The `AgentApplication.on_sign_in_success` method is unavailable because no Auth options were configured. - """) + """ + ) return func def on_sign_in_failure( @@ -618,10 +628,12 @@ async def sign_in_failure(context: TurnContext, state: TurnState, connection_id: f"Failed to register sign-in failure handler for route handler {func.__name__}", stack_info=True, ) - raise ApplicationError(""" + raise ApplicationError( + """ The `AgentApplication.on_sign_in_failure` method is unavailable because no Auth options were configured. - """) + """ + ) return func def error( diff --git a/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/authorization/agent_auth_configuration.py b/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/authorization/agent_auth_configuration.py index dfccfde0..2605d3b0 100644 --- a/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/authorization/agent_auth_configuration.py +++ b/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/authorization/agent_auth_configuration.py @@ -32,6 +32,7 @@ class AgentAuthConfiguration: CONNECTION_NAME: Optional[str] SCOPES: Optional[list[str]] AUTHORITY: Optional[str] + FEDERATED_CLIENT_ID: Optional[str] ALT_BLUEPRINT_ID: Optional[str] ANONYMOUS_ALLOWED: bool = False @@ -69,6 +70,7 @@ def __init__( self.CONNECTION_NAME = connection_name or kwargs.get("CONNECTIONNAME", None) self.SCOPES = scopes or kwargs.get("SCOPES", None) self.ALT_BLUEPRINT_ID = kwargs.get("ALT_BLUEPRINT_NAME", None) + self.FEDERATED_CLIENT_ID = kwargs.get("FEDERATEDCLIENTID", None) self.ANONYMOUS_ALLOWED = anonymous_allowed or kwargs.get( "ANONYMOUS_ALLOWED", False ) diff --git a/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/authorization/auth_types.py b/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/authorization/auth_types.py index 58784ae8..595734d9 100644 --- a/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/authorization/auth_types.py +++ b/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/authorization/auth_types.py @@ -10,3 +10,4 @@ class AuthTypes(str, Enum): client_secret = "ClientSecret" user_managed_identity = "UserManagedIdentity" system_managed_identity = "SystemManagedIdentity" + federated_credentials = "FederatedCredentials" \ No newline at end of file From cf1969fd2247a847b312d41d80ee9a2025fd635d Mon Sep 17 00:00:00 2001 From: Rodrigo Brandao Date: Tue, 10 Feb 2026 19:07:54 -0800 Subject: [PATCH 2/3] Extracting access token --- .../microsoft_agents/authentication/msal/msal_auth.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/libraries/microsoft-agents-authentication-msal/microsoft_agents/authentication/msal/msal_auth.py b/libraries/microsoft-agents-authentication-msal/microsoft_agents/authentication/msal/msal_auth.py index ecfb6560..21718bdd 100644 --- a/libraries/microsoft-agents-authentication-msal/microsoft_agents/authentication/msal/msal_auth.py +++ b/libraries/microsoft-agents-authentication-msal/microsoft_agents/authentication/msal/msal_auth.py @@ -240,7 +240,15 @@ def _create_client_application( SystemAssignedManagedIdentity(), # TODO http_client=Session(), ) - self._client_credential_cache = mi_client.acquire_token_for_client(resource=self._msal_configuration.FEDERATED_CLIENT_ID) + mi_token = mi_client.acquire_token_for_client(resource=self._msal_configuration.FEDERATED_CLIENT_ID) + if "access_token" not in mi_token: + logger.error( + f"Failed to acquire token for federated credentials: {mi_token}" + ) + raise ValueError( + authentication_errors.FailedToAcquireToken.format(str(mi_token)) + ) + self._client_credential_cache = mi_token["access_token"] else: logger.error( f"Unsupported authentication type: {self._msal_configuration.AUTH_TYPE}" From 17a0716ca5c097ccb2641d0c68525247a22fc6e3 Mon Sep 17 00:00:00 2001 From: Rodrigo Brandao Date: Wed, 11 Feb 2026 15:43:57 -0800 Subject: [PATCH 3/3] Formatting --- .../microsoft_agents/authentication/msal/msal_auth.py | 6 ++++-- .../hosting/core/authorization/auth_types.py | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/libraries/microsoft-agents-authentication-msal/microsoft_agents/authentication/msal/msal_auth.py b/libraries/microsoft-agents-authentication-msal/microsoft_agents/authentication/msal/msal_auth.py index 21718bdd..553b3f55 100644 --- a/libraries/microsoft-agents-authentication-msal/microsoft_agents/authentication/msal/msal_auth.py +++ b/libraries/microsoft-agents-authentication-msal/microsoft_agents/authentication/msal/msal_auth.py @@ -237,10 +237,12 @@ def _create_client_application( elif self._msal_configuration.AUTH_TYPE == AuthTypes.federated_credentials: assert self._msal_configuration.FEDERATED_CLIENT_ID mi_client = ManagedIdentityClient( - SystemAssignedManagedIdentity(), # TODO + SystemAssignedManagedIdentity(), # TODO http_client=Session(), ) - mi_token = mi_client.acquire_token_for_client(resource=self._msal_configuration.FEDERATED_CLIENT_ID) + mi_token = mi_client.acquire_token_for_client( + resource=self._msal_configuration.FEDERATED_CLIENT_ID + ) if "access_token" not in mi_token: logger.error( f"Failed to acquire token for federated credentials: {mi_token}" diff --git a/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/authorization/auth_types.py b/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/authorization/auth_types.py index 595734d9..655630a4 100644 --- a/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/authorization/auth_types.py +++ b/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/authorization/auth_types.py @@ -10,4 +10,4 @@ class AuthTypes(str, Enum): client_secret = "ClientSecret" user_managed_identity = "UserManagedIdentity" system_managed_identity = "SystemManagedIdentity" - federated_credentials = "FederatedCredentials" \ No newline at end of file + federated_credentials = "FederatedCredentials"