From 670aa2dc5daaaf1cb673eea336e3713d1992c627 Mon Sep 17 00:00:00 2001 From: Paul Van Eck Date: Tue, 15 Jul 2025 21:54:20 +0000 Subject: [PATCH 1/4] [Identity] Enable brokered auth in DAC Signed-off-by: Paul Van Eck --- sdk/identity/azure-identity/CHANGELOG.md | 2 +- .../azure/identity/_credentials/broker.py | 78 +++++++++++++++++++ .../azure/identity/_credentials/default.py | 22 +++++- .../azure/identity/_internal/utils.py | 9 +++ .../azure-identity/tests/test_default.py | 45 +++++++++++ 5 files changed, 154 insertions(+), 2 deletions(-) create mode 100644 sdk/identity/azure-identity/azure/identity/_credentials/broker.py diff --git a/sdk/identity/azure-identity/CHANGELOG.md b/sdk/identity/azure-identity/CHANGELOG.md index 93bffec18471..1f6de60cde3c 100644 --- a/sdk/identity/azure-identity/CHANGELOG.md +++ b/sdk/identity/azure-identity/CHANGELOG.md @@ -8,7 +8,7 @@ - Valid values are `EnvironmentCredential`, `WorkloadIdentityCredential`, `ManagedIdentityCredential`, `AzureCliCredential`, `AzurePowershellCredential`, `AzureDeveloperCliCredential`, and `InteractiveBrowserCredential`. ([#41709](https://github.com/Azure/azure-sdk-for-python/pull/41709)) - Re-enabled `VisualStudioCodeCredential` - Previously deprecated `VisualStudioCodeCredential` has been re-implemented to work with the VS Code Azure Resources extension instead of the deprecated Azure Account extension. This requires the `azure-identity-broker` package to be installed for authentication. ([#41822](https://github.com/Azure/azure-sdk-for-python/pull/41822)) - `VisualStudioCodeCredential` is now included in the `DefaultAzureCredential` token chain by default. - +- `DefaultAzureCredential` now supports authentication with the currently signed-in Windows account, provided the `azure-identity-broker` package is installed. This auth mechanism is added at the end of the `DefaultAzureCredential` credential chain. ([#40335](https://github.com/Azure/azure-sdk-for-python/pull/40335)) ### Breaking Changes diff --git a/sdk/identity/azure-identity/azure/identity/_credentials/broker.py b/sdk/identity/azure-identity/azure/identity/_credentials/broker.py new file mode 100644 index 000000000000..a55116eaa461 --- /dev/null +++ b/sdk/identity/azure-identity/azure/identity/_credentials/broker.py @@ -0,0 +1,78 @@ +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ +import sys +from typing import Any + +import msal +from azure.core.credentials import AccessToken, AccessTokenInfo, SupportsTokenInfo +from .._exceptions import CredentialUnavailableError +from .._internal.utils import get_broker_credential, is_wsl + + +class BrokerCredential(SupportsTokenInfo): + """A broker credential that handles prerequisite checking and falls back appropriately. + + This credential checks if the azure-identity-broker package is available and the platform + is supported. If both conditions are met, it uses the real broker credential. Otherwise, + it raises CredentialUnavailableError with an appropriate message. + """ + + def __init__(self, **kwargs: Any) -> None: + + self._tenant_id = kwargs.pop("tenant_id", None) + self._client_id = kwargs.pop("client_id", None) + self._broker_credential = None + self._unavailable_message = None + + # Check prerequisites and initialize the appropriate credential + broker_credential_class = get_broker_credential() + if broker_credential_class and (sys.platform.startswith("win") or is_wsl()): + # The silent auth flow for brokered auth is available on Windows/WSL with the broker package + try: + broker_credential_args = { + "tenant_id": self._tenant_id, + "parent_window_handle": msal.PublicClientApplication.CONSOLE_WINDOW_HANDLE, + "use_default_broker_account": True, + **kwargs, + } + if self._client_id: + broker_credential_args["client_id"] = self._client_id + self._broker_credential = broker_credential_class(**broker_credential_args) + except Exception as ex: # pylint: disable=broad-except + self._unavailable_message = f"InteractiveBrowserBrokerCredential initialization failed: {ex}" + else: + # Determine the specific reason for unavailability + if broker_credential_class is None: + self._unavailable_message = ( + "InteractiveBrowserBrokerCredential unavailable. " + "The 'azure-identity-broker' package is required to use brokered authentication." + ) + else: + self._unavailable_message = ( + "InteractiveBrowserBrokerCredential unavailable. " + "Brokered authentication is only supported on Windows and WSL platforms." + ) + + def get_token(self, *scopes: str, **kwargs: Any) -> AccessToken: + if self._broker_credential: + return self._broker_credential.get_token(*scopes, **kwargs) + raise CredentialUnavailableError(message=self._unavailable_message) + + def get_token_info(self, *scopes: str, **kwargs: Any) -> AccessTokenInfo: + if self._broker_credential: + return self._broker_credential.get_token_info(*scopes, **kwargs) + raise CredentialUnavailableError(message=self._unavailable_message) + + def __enter__(self) -> "BrokerCredential": + if self._broker_credential: + self._broker_credential.__enter__() + return self + + def __exit__(self, *args): + if self._broker_credential: + self._broker_credential.__exit__(*args) + + def close(self) -> None: + self.__exit__() diff --git a/sdk/identity/azure-identity/azure/identity/_credentials/default.py b/sdk/identity/azure-identity/azure/identity/_credentials/default.py index 316b202d0771..2512445253ca 100644 --- a/sdk/identity/azure-identity/azure/identity/_credentials/default.py +++ b/sdk/identity/azure-identity/azure/identity/_credentials/default.py @@ -8,8 +8,9 @@ from azure.core.credentials import AccessToken, AccessTokenInfo, TokenRequestOptions, SupportsTokenInfo, TokenCredential from .._constants import EnvironmentVariables -from .._internal import get_default_authority, normalize_authority, within_dac, process_credential_exclusions +from .._internal.utils import get_default_authority, normalize_authority, within_dac, process_credential_exclusions from .azure_powershell import AzurePowerShellCredential +from .broker import BrokerCredential from .browser import InteractiveBrowserCredential from .chained import ChainedTokenCredential from .environment import EnvironmentCredential @@ -42,6 +43,9 @@ class DefaultAzureCredential(ChainedTokenCredential): 5. The identity currently logged in to the Azure CLI. 6. The identity currently logged in to Azure PowerShell. 7. The identity currently logged in to the Azure Developer CLI. + 8. Brokered authentication. On Windows and WSL, this uses an authentication broker such as + Web Account Manager (WAM). On other platforms or when the azure-identity-broker package is not installed, + this credential will raise CredentialUnavailableError. This default behavior is configurable with keyword arguments. @@ -64,6 +68,9 @@ class DefaultAzureCredential(ChainedTokenCredential): **False**. :keyword bool exclude_interactive_browser_credential: Whether to exclude interactive browser authentication (see :class:`~azure.identity.InteractiveBrowserCredential`). Defaults to **True**. + :keyword bool exclude_broker_credential: Whether to exclude the broker credential from the credential chain. + Defaults to **False**. When False, the broker credential is always included in the chain but will raise + CredentialUnavailableError if the azure-identity-broker package is not installed. :keyword str interactive_browser_tenant_id: Tenant ID to use when authenticating a user through :class:`~azure.identity.InteractiveBrowserCredential`. Defaults to the value of environment variable AZURE_TENANT_ID, if any. If unspecified, users will authenticate in their home tenants. @@ -147,6 +154,7 @@ def __init__(self, **kwargs: Any) -> None: # pylint: disable=too-many-statement }, "visual_studio_code": { "exclude_param": "exclude_visual_studio_code_credential", + "env_name": "visualstudiocodecredential", "default_exclude": False, }, "cli": { @@ -169,6 +177,11 @@ def __init__(self, **kwargs: Any) -> None: # pylint: disable=too-many-statement "env_name": "interactivebrowsercredential", "default_exclude": True, }, + "broker": { + "exclude_param": "exclude_broker_credential", + "env_name": "interactivebrowserbrokercredential", + "default_exclude": False, + }, } # Extract user-provided exclude flags and set defaults @@ -192,6 +205,7 @@ def __init__(self, **kwargs: Any) -> None: # pylint: disable=too-many-statement exclude_developer_cli_credential = exclude_flags["developer_cli"] exclude_powershell_credential = exclude_flags["powershell"] exclude_interactive_browser_credential = exclude_flags["interactive_browser"] + exclude_broker_credential = exclude_flags["broker"] credentials: List[SupportsTokenInfo] = [] within_dac.set(True) @@ -242,6 +256,12 @@ def __init__(self, **kwargs: Any) -> None: # pylint: disable=too-many-statement ) else: credentials.append(InteractiveBrowserCredential(tenant_id=interactive_browser_tenant_id, **kwargs)) + if not exclude_broker_credential: + broker_credential_args = {"tenant_id": interactive_browser_tenant_id, **kwargs} + if interactive_browser_client_id: + broker_credential_args["client_id"] = interactive_browser_client_id + credentials.append(BrokerCredential(**broker_credential_args)) + within_dac.set(False) super(DefaultAzureCredential, self).__init__(*credentials) diff --git a/sdk/identity/azure-identity/azure/identity/_internal/utils.py b/sdk/identity/azure-identity/azure/identity/_internal/utils.py index 2303906ec4eb..e60bffdd3a63 100644 --- a/sdk/identity/azure-identity/azure/identity/_internal/utils.py +++ b/sdk/identity/azure-identity/azure/identity/_internal/utils.py @@ -3,6 +3,7 @@ # Licensed under the MIT License. # ------------------------------------ import os +import platform import logging from contextvars import ContextVar from string import ascii_letters, digits @@ -209,3 +210,11 @@ def get_broker_credential() -> Optional[type]: return InteractiveBrowserBrokerCredential except ImportError: return None + + +def is_wsl() -> bool: + # This is how MSAL checks for WSL. + uname = platform.uname() + platform_name = getattr(uname, "system", uname[0]).lower() + release = getattr(uname, "release", uname[2]).lower() + return platform_name == "linux" and "microsoft" in release diff --git a/sdk/identity/azure-identity/tests/test_default.py b/sdk/identity/azure-identity/tests/test_default.py index b77bfbcbad20..7531e27f9e22 100644 --- a/sdk/identity/azure-identity/tests/test_default.py +++ b/sdk/identity/azure-identity/tests/test_default.py @@ -3,6 +3,7 @@ # Licensed under the MIT License. # ------------------------------------ import os +import sys from azure.core.credentials import AccessToken, AccessTokenInfo from azure.identity import ( @@ -19,6 +20,7 @@ from azure.identity._credentials.azure_cli import AzureCliCredential from azure.identity._credentials.azd_cli import AzureDeveloperCliCredential from azure.identity._credentials.managed_identity import ManagedIdentityCredential +from azure.identity._internal.utils import is_wsl import pytest from urllib.parse import urlparse @@ -175,12 +177,25 @@ def assert_credentials_not_present(chain, *excluded_credential_classes): credential = DefaultAzureCredential(exclude_developer_cli_credential=True) assert_credentials_not_present(credential, AzureDeveloperCliCredential) + # test excluding broker credential + credential = DefaultAzureCredential(exclude_broker_credential=True) + from azure.identity._credentials.broker import BrokerCredential + + assert_credentials_not_present(credential, BrokerCredential) + # interactive auth is excluded by default credential = DefaultAzureCredential(exclude_interactive_browser_credential=False) actual = {c.__class__ for c in credential.credentials} default = {c.__class__ for c in DefaultAzureCredential().credentials} assert actual - default == {InteractiveBrowserCredential} + # broker credential is included by default + credential = DefaultAzureCredential() + from azure.identity._credentials.broker import BrokerCredential + + actual = {c.__class__ for c in credential.credentials} + assert BrokerCredential in actual, "BrokerCredential should be included in DefaultAzureCredential by default" + @pytest.mark.parametrize("get_token_method", GET_TOKEN_METHODS) def test_shared_cache_tenant_id(get_token_method): @@ -432,3 +447,33 @@ def test_validate_cloud_shell_credential_in_dac(): DefaultAzureCredential(identity_config={"client_id": "foo"}) DefaultAzureCredential(identity_config={"object_id": "foo"}) DefaultAzureCredential(identity_config={"resource_id": "foo"}) + + +@pytest.mark.skipif(not sys.platform.startswith("win") and not is_wsl(), reason="tests Windows-specific behavior") +def test_broker_credential(): + """Test that DefaultAzureCredential uses the broker credential when available""" + with patch("azure.identity.broker.InteractiveBrowserBrokerCredential") as mock_credential: + credential = DefaultAzureCredential() + # The broker credential should be in the chain + broker_credentials = [c for c in credential.credentials if c.__class__.__name__ == "BrokerCredential"] + assert len(broker_credentials) == 1, "BrokerCredential should be in the chain" + # InteractiveBrowserBrokerCredential should be instantiated by BrokerCredential + assert mock_credential.call_count > 1, "InteractiveBrowserBrokerCredential should be instantiated" + + +def test_broker_credential_requirements_not_installed(): + """Test that DefaultAzureCredential includes BrokerCredential even when broker package is not installed""" + + # Mock the get_broker_credential function to return None (simulating package not installed) + with patch.dict("sys.modules", {"azure.identity.broker": None}): + credential = DefaultAzureCredential() + # The broker credential should still be in the chain + broker_credentials = [c for c in credential.credentials if c.__class__.__name__ == "BrokerCredential"] + assert ( + len(broker_credentials) == 1 + ), "BrokerCredential should be in the chain even when broker package is not installed" + + # Test that the broker credential raises CredentialUnavailableError + broker_cred = broker_credentials[0] + with pytest.raises(CredentialUnavailableError) as exc_info: + broker_cred.get_token_info("https://management.azure.com/.default") From 01ebed968c1513dbad7e6939789b26c483327526 Mon Sep 17 00:00:00 2001 From: Paul Van Eck Date: Thu, 17 Jul 2025 02:20:02 +0000 Subject: [PATCH 2/4] Update broker cred to disable interactive fallback Signed-off-by: Paul Van Eck --- .../azure/identity/broker/_browser.py | 38 ++++++++++--------- .../azure/identity/_credentials/broker.py | 1 + .../azure/identity/_credentials/default.py | 13 +++++-- .../azure-identity/tests/test_default.py | 29 +++++++++++++- 4 files changed, 60 insertions(+), 21 deletions(-) diff --git a/sdk/identity/azure-identity-broker/azure/identity/broker/_browser.py b/sdk/identity/azure-identity-broker/azure/identity/broker/_browser.py index af9763aa7271..68fe2f3d892d 100644 --- a/sdk/identity/azure-identity-broker/azure/identity/broker/_browser.py +++ b/sdk/identity/azure-identity-broker/azure/identity/broker/_browser.py @@ -58,7 +58,8 @@ class InteractiveBrowserBrokerCredential(_InteractiveBrowserCredential): are required to also provide its window handle, so that the sign in UI window will properly pop up on top of your window. :keyword bool use_default_broker_account: Enables automatically using the default broker account for - authentication instead of prompting the user with an account picker. Defaults to False. + authentication instead of prompting the user with an account picker. This is currently only supported on Windows + and WSL. Defaults to False. :keyword bool enable_msa_passthrough: Determines whether Microsoft Account (MSA) passthrough is enabled. Note, this is only needed for select legacy first-party applications. Defaults to False. :keyword bool disable_instance_discovery: Determines whether or not instance discovery is performed when attempting @@ -78,6 +79,7 @@ def __init__(self, **kwargs: Any) -> None: self._parent_window_handle = kwargs.pop("parent_window_handle", None) self._enable_msa_passthrough = kwargs.pop("enable_msa_passthrough", False) self._use_default_broker_account = kwargs.pop("use_default_broker_account", False) + self._disable_interactive_fallback = kwargs.pop("disable_interactive_fallback", False) super().__init__(**kwargs) @wrap_exceptions @@ -93,6 +95,7 @@ def _request_token(self, *scopes: str, **kwargs: Any) -> Dict: http_method=pop["resource_request_method"], url=pop["resource_request_url"], nonce=pop["nonce"] ) if sys.platform.startswith("win") or is_wsl(): + result = {} if self._use_default_broker_account: try: result = app.acquire_token_interactive( @@ -110,6 +113,10 @@ def _request_token(self, *scopes: str, **kwargs: Any) -> Dict: return result except socket.error: pass + + if self._disable_interactive_fallback: + self._check_result(result) + try: result = app.acquire_token_interactive( scopes=scopes_list, @@ -124,14 +131,8 @@ def _request_token(self, *scopes: str, **kwargs: Any) -> Dict: ) except socket.error as ex: raise CredentialUnavailableError(message="Couldn't start an HTTP server.") from ex - if "access_token" not in result and "error_description" in result: - if within_dac.get(): - raise CredentialUnavailableError(message=result["error_description"]) - raise ClientAuthenticationError(message=result.get("error_description")) - if "access_token" not in result: - if within_dac.get(): - raise CredentialUnavailableError(message="Failed to authenticate user") - raise ClientAuthenticationError(message="Failed to authenticate user") + + self._check_result(result) else: try: result = app.acquire_token_interactive( @@ -157,16 +158,19 @@ def _request_token(self, *scopes: str, **kwargs: Any) -> Dict: parent_window_handle=self._parent_window_handle, enable_msa_passthrough=self._enable_msa_passthrough, ) - if "access_token" in result: - return result - if "error_description" in result: - if within_dac.get(): - # pylint: disable=raise-missing-from - raise CredentialUnavailableError(message=result["error_description"]) - # pylint: disable=raise-missing-from - raise ClientAuthenticationError(message=result.get("error_description")) + self._check_result(result) return result + def _check_result(self, result: Dict[str, Any]) -> None: + if "access_token" not in result and "error_description" in result: + if within_dac.get(): + raise CredentialUnavailableError(message=result["error_description"]) + raise ClientAuthenticationError(message=result.get("error_description")) + if "access_token" not in result: + if within_dac.get(): + raise CredentialUnavailableError(message="Failed to authenticate user") + raise ClientAuthenticationError(message="Failed to authenticate user") + def _get_app(self, **kwargs: Any) -> msal.ClientApplication: tenant_id = resolve_tenant( self._tenant_id, additionally_allowed_tenants=self._additionally_allowed_tenants, **kwargs diff --git a/sdk/identity/azure-identity/azure/identity/_credentials/broker.py b/sdk/identity/azure-identity/azure/identity/_credentials/broker.py index a55116eaa461..d7ead3f9577f 100644 --- a/sdk/identity/azure-identity/azure/identity/_credentials/broker.py +++ b/sdk/identity/azure-identity/azure/identity/_credentials/broker.py @@ -35,6 +35,7 @@ def __init__(self, **kwargs: Any) -> None: "tenant_id": self._tenant_id, "parent_window_handle": msal.PublicClientApplication.CONSOLE_WINDOW_HANDLE, "use_default_broker_account": True, + "disable_interactive_fallback": True, **kwargs, } if self._client_id: diff --git a/sdk/identity/azure-identity/azure/identity/_credentials/default.py b/sdk/identity/azure-identity/azure/identity/_credentials/default.py index 2512445253ca..4e6e2ca1920c 100644 --- a/sdk/identity/azure-identity/azure/identity/_credentials/default.py +++ b/sdk/identity/azure-identity/azure/identity/_credentials/default.py @@ -74,6 +74,8 @@ class DefaultAzureCredential(ChainedTokenCredential): :keyword str interactive_browser_tenant_id: Tenant ID to use when authenticating a user through :class:`~azure.identity.InteractiveBrowserCredential`. Defaults to the value of environment variable AZURE_TENANT_ID, if any. If unspecified, users will authenticate in their home tenants. + :keyword str broker_tenant_id: The tenant ID to use when using brokered authentication. Defaults to the value of + environment variable AZURE_TENANT_ID, if any. If unspecified, users will authenticate in their home tenants. :keyword str managed_identity_client_id: The client ID of a user-assigned managed identity. Defaults to the value of the environment variable AZURE_CLIENT_ID, if any. If not specified, a system-assigned identity will be used. :keyword str workload_identity_client_id: The client ID of an identity assigned to the pod. Defaults to the value @@ -82,6 +84,8 @@ class DefaultAzureCredential(ChainedTokenCredential): Defaults to the value of environment variable AZURE_TENANT_ID, if any. :keyword str interactive_browser_client_id: The client ID to be used in interactive browser credential. If not specified, users will authenticate to an Azure development application. + :keyword str broker_client_id: The client ID to be used in brokered authentication. If not specified, users will + authenticate to an Azure development application. :keyword str shared_cache_username: Preferred username for :class:`~azure.identity.SharedTokenCacheCredential`. Defaults to the value of environment variable AZURE_USERNAME, if any. :keyword str shared_cache_tenant_id: Preferred tenant for :class:`~azure.identity.SharedTokenCacheCredential`. @@ -124,6 +128,9 @@ def __init__(self, **kwargs: Any) -> None: # pylint: disable=too-many-statement ) interactive_browser_client_id = kwargs.pop("interactive_browser_client_id", None) + broker_tenant_id = kwargs.pop("broker_tenant_id", os.environ.get(EnvironmentVariables.AZURE_TENANT_ID)) + broker_client_id = kwargs.pop("broker_client_id", None) + shared_cache_username = kwargs.pop("shared_cache_username", os.environ.get(EnvironmentVariables.AZURE_USERNAME)) shared_cache_tenant_id = kwargs.pop( "shared_cache_tenant_id", os.environ.get(EnvironmentVariables.AZURE_TENANT_ID) @@ -257,9 +264,9 @@ def __init__(self, **kwargs: Any) -> None: # pylint: disable=too-many-statement else: credentials.append(InteractiveBrowserCredential(tenant_id=interactive_browser_tenant_id, **kwargs)) if not exclude_broker_credential: - broker_credential_args = {"tenant_id": interactive_browser_tenant_id, **kwargs} - if interactive_browser_client_id: - broker_credential_args["client_id"] = interactive_browser_client_id + broker_credential_args = {"tenant_id": broker_tenant_id, **kwargs} + if broker_client_id: + broker_credential_args["client_id"] = broker_client_id credentials.append(BrokerCredential(**broker_credential_args)) within_dac.set(False) diff --git a/sdk/identity/azure-identity/tests/test_default.py b/sdk/identity/azure-identity/tests/test_default.py index 7531e27f9e22..d2f4bc1f0bbf 100644 --- a/sdk/identity/azure-identity/tests/test_default.py +++ b/sdk/identity/azure-identity/tests/test_default.py @@ -458,7 +458,34 @@ def test_broker_credential(): broker_credentials = [c for c in credential.credentials if c.__class__.__name__ == "BrokerCredential"] assert len(broker_credentials) == 1, "BrokerCredential should be in the chain" # InteractiveBrowserBrokerCredential should be instantiated by BrokerCredential - assert mock_credential.call_count > 1, "InteractiveBrowserBrokerCredential should be instantiated" + assert mock_credential.call_count >= 1, "InteractiveBrowserBrokerCredential should be instantiated" + + +def test_broker_credential_client_id(): + """Test that DefaultAzureCredential allows configuring a client ID for BrokerCredential""" + + client_id = "broker-client-id" + credential = DefaultAzureCredential(broker_client_id=client_id) + broker_credentials = [c for c in credential.credentials if c.__class__.__name__ == "BrokerCredential"] + assert ( + len(broker_credentials) == 1 + ), "BrokerCredential should be in the chain even when broker package is not installed" + broker_credential = broker_credentials[0] + assert broker_credential._client_id == client_id, "Credential should be instantiated with the specified client ID" + + +def test_broker_credential_tenant_id(): + """Test that DefaultAzureCredential allows configuring a tenant ID for BrokerCredential""" + + tenant_id = "broker-tenant-id" + + credential = DefaultAzureCredential(broker_tenant_id=tenant_id) + broker_credentials = [c for c in credential.credentials if c.__class__.__name__ == "BrokerCredential"] + assert ( + len(broker_credentials) == 1 + ), "BrokerCredential should be in the chain even when broker package is not installed" + broker_credential = broker_credentials[0] + assert broker_credential._tenant_id == tenant_id, "Credential should be instantiated with the specified tenant ID" def test_broker_credential_requirements_not_installed(): From 85cd3b0576ae32c3362ebe22d8794a165c1c7dac Mon Sep 17 00:00:00 2001 From: Paul Van Eck Date: Thu, 17 Jul 2025 19:51:16 +0000 Subject: [PATCH 3/4] Update docs Signed-off-by: Paul Van Eck --- sdk/identity/azure-identity/README.md | 2 +- .../azure-identity/azure/identity/_credentials/default.py | 8 +++----- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/sdk/identity/azure-identity/README.md b/sdk/identity/azure-identity/README.md index 49a4c39b6037..a6d4e837cdc9 100644 --- a/sdk/identity/azure-identity/README.md +++ b/sdk/identity/azure-identity/README.md @@ -321,7 +321,7 @@ The Azure Identity library offers both in-memory and persistent disk caching. Fo ## Brokered authentication -An authentication broker is an application that runs on a user’s machine and manages the authentication handshakes and token maintenance for connected accounts. Currently, only the Windows Web Account Manager (WAM) is supported. To enable support, use the [`azure-identity-broker`][azure_identity_broker] package. For details on authenticating using WAM, see the [broker plugin documentation][azure_identity_broker_readme]. +An authentication broker is an application that runs on a user’s machine and manages the authentication handshakes and token maintenance for connected accounts. Currently, only the Windows Web Account Manager (WAM) is supported. Authentication via WAM is used by `DefaultAzureCredential` to enable secure sign-in. To enable support, use the [`azure-identity-broker`][azure_identity_broker] package. For details on authenticating using WAM, see the [broker plugin documentation][azure_identity_broker_readme]. ## Troubleshooting diff --git a/sdk/identity/azure-identity/azure/identity/_credentials/default.py b/sdk/identity/azure-identity/azure/identity/_credentials/default.py index 4e6e2ca1920c..6b1cbac65b55 100644 --- a/sdk/identity/azure-identity/azure/identity/_credentials/default.py +++ b/sdk/identity/azure-identity/azure/identity/_credentials/default.py @@ -43,9 +43,8 @@ class DefaultAzureCredential(ChainedTokenCredential): 5. The identity currently logged in to the Azure CLI. 6. The identity currently logged in to Azure PowerShell. 7. The identity currently logged in to the Azure Developer CLI. - 8. Brokered authentication. On Windows and WSL, this uses an authentication broker such as - Web Account Manager (WAM). On other platforms or when the azure-identity-broker package is not installed, - this credential will raise CredentialUnavailableError. + 8. Brokered authentication. On Windows and WSL only, this uses the default account logged in via + Web Account Manager (WAM) if the `azure-identity-broker` package is installed. This default behavior is configurable with keyword arguments. @@ -69,8 +68,7 @@ class DefaultAzureCredential(ChainedTokenCredential): :keyword bool exclude_interactive_browser_credential: Whether to exclude interactive browser authentication (see :class:`~azure.identity.InteractiveBrowserCredential`). Defaults to **True**. :keyword bool exclude_broker_credential: Whether to exclude the broker credential from the credential chain. - Defaults to **False**. When False, the broker credential is always included in the chain but will raise - CredentialUnavailableError if the azure-identity-broker package is not installed. + Defaults to **False**. :keyword str interactive_browser_tenant_id: Tenant ID to use when authenticating a user through :class:`~azure.identity.InteractiveBrowserCredential`. Defaults to the value of environment variable AZURE_TENANT_ID, if any. If unspecified, users will authenticate in their home tenants. From 01e58730ea26f69e437e5ad84968777d3c427ed4 Mon Sep 17 00:00:00 2001 From: Paul Van Eck Date: Thu, 17 Jul 2025 20:13:11 +0000 Subject: [PATCH 4/4] Remove env name Signed-off-by: Paul Van Eck --- .../azure-identity/azure/identity/_credentials/default.py | 1 - 1 file changed, 1 deletion(-) diff --git a/sdk/identity/azure-identity/azure/identity/_credentials/default.py b/sdk/identity/azure-identity/azure/identity/_credentials/default.py index 6b1cbac65b55..436d3535ded1 100644 --- a/sdk/identity/azure-identity/azure/identity/_credentials/default.py +++ b/sdk/identity/azure-identity/azure/identity/_credentials/default.py @@ -184,7 +184,6 @@ def __init__(self, **kwargs: Any) -> None: # pylint: disable=too-many-statement }, "broker": { "exclude_param": "exclude_broker_credential", - "env_name": "interactivebrowserbrokercredential", "default_exclude": False, }, }