Repository: Azure/azure-sdk-for-python
Pull request #40084: Corehttp auth flows
Author: login: xiangyan99
Labels: name: Azure.Core
Created: 2025-03-14T23:00:43Z | Merged: 2025-03-26T16:55:35Z



Diff:
diff --git a/sdk/core/corehttp/CHANGELOG.md b/sdk/core/corehttp/CHANGELOG.md
index 8f3d5e2965bb..b8d68c7b1be7 100644
--- a/sdk/core/corehttp/CHANGELOG.md
+++ b/sdk/core/corehttp/CHANGELOG.md
@@ -10,6 +10,7 @@
 - `BearerTokenCredentialPolicy` and `AsyncBearerTokenCredentialPolicy` now check if a credential has the `get_token_info` method defined. If so, the `get_token_info` method is used to acquire a token. [#38346](https://github.com/Azure/azure-sdk-for-python/pull/38346)
   - These policies now also check the `refresh_on` attribute when determining if a new token request should be made.
 - Added `model` attribute to `HttpResponseError` to allow accessing error attributes based on a known model. [#39636](https://github.com/Azure/azure-sdk-for-python/pull/39636)
+- Added `auth_flows` support in `BearerTokenCredentialPolicy`. [#40084](https://github.com/Azure/azure-sdk-for-python/pull/40084)
 
 ### Breaking Changes
 
diff --git a/sdk/core/corehttp/corehttp/runtime/policies/_authentication.py b/sdk/core/corehttp/corehttp/runtime/policies/_authentication.py
index 38a7360249ab..4816d3496b17 100644
--- a/sdk/core/corehttp/corehttp/runtime/policies/_authentication.py
+++ b/sdk/core/corehttp/corehttp/runtime/policies/_authentication.py
@@ -5,7 +5,7 @@
 # -------------------------------------------------------------------------
 from __future__ import annotations
 import time
-from typing import TYPE_CHECKING, Optional, TypeVar, MutableMapping, Any
+from typing import TYPE_CHECKING, Optional, TypeVar, MutableMapping, Any, Union
 
 from ...credentials import TokenRequestOptions
 from ...rest import HttpResponse, HttpRequest
@@ -32,15 +32,23 @@ class _BearerTokenCredentialPolicyBase:
     :param credential: The credential.
     :type credential: ~corehttp.credentials.TokenCredential
     :param str scopes: Lets you specify the type of access needed.
+    :keyword auth_flows: A list of authentication flows to use for the credential.
+    :paramtype auth_flows: list[dict[str, Union[str, list[dict[str, str]]]]]
     """
 
+    # pylint: disable=unused-argument
     def __init__(
-        self, credential: "TokenCredential", *scopes: str, **kwargs: Any  # pylint: disable=unused-argument
+        self,
+        credential: "TokenCredential",
+        *scopes: str,
+        auth_flows: Optional[list[dict[str, Union[str, list[dict[str, str]]]]]] = None,
+        **kwargs: Any,
     ) -> None:
         super(_BearerTokenCredentialPolicyBase, self).__init__()
         self._scopes = scopes
         self._credential = credential
         self._token: Optional["AccessTokenInfo"] = None
+        self._auth_flows = auth_flows
 
     @staticmethod
     def _enforce_https(request: PipelineRequest[HTTPRequestType]) -> None:
@@ -83,20 +91,30 @@ class BearerTokenCredentialPolicy(_BearerTokenCredentialPolicyBase, HTTPPolicy[H
     :param credential: The credential.
     :type credential: ~corehttp.TokenCredential
     :param str scopes: Lets you specify the type of access needed.
+    :keyword auth_flows: A list of authentication flows to use for the credential.
+    :paramtype auth_flows: list[dict[str, Union[str, list[dict[str, str]]]]]
     :raises: :class:`~corehttp.exceptions.ServiceRequestError`
     """
 
-    def on_request(self, request: PipelineRequest[HTTPRequestType]) -> None:
+    def on_request(
+        self,
+        request: PipelineRequest[HTTPRequestType],
+        *,
+        auth_flows: Optional[list[dict[str, Union[str, list[dict[str, str]]]]]] = None,
+    ) -> None:
         """Called before the policy sends a request.
 
         The base implementation authorizes the request with a bearer token.
 
         :param ~corehttp.runtime.pipeline.PipelineRequest request: the request
+        :keyword auth_flows: A list of authentication flows to use for the credential.
+        :paramtype auth_flows: list[dict[str, Union[str, list[dict[str, str]]]]]
         """
         self._enforce_https(request)
 
         if self._token is None or self._need_new_token:
-            self._token = self._credential.get_token_info(*self._scopes)
+            options: TokenRequestOptions = {"auth_flows": auth_flows} if auth_flows else {}  # type: ignore
+            self._token = self._credential.get_token_info(*self._scopes, options=options)
         self._update_headers(request.http_request.headers, self._token.token)
 
     def authorize_request(self, request: PipelineRequest[HTTPRequestType], *scopes: str, **kwargs: Any) -> None:
@@ -124,7 +142,7 @@ def send(self, request: PipelineRequest[HTTPRequestType]) -> PipelineResponse[HT
         :return: The pipeline response object
         :rtype: ~corehttp.runtime.pipeline.PipelineResponse
         """
-        self.on_request(request)
+        self.on_request(request, auth_flows=self._auth_flows)
         try:
             response = self.next.send(request)
         except Exception:
diff --git a/sdk/core/corehttp/corehttp/runtime/policies/_authentication_async.py b/sdk/core/corehttp/corehttp/runtime/policies/_authentication_async.py
index 8da76d8f79d1..05239b99fa5a 100644
--- a/sdk/core/corehttp/corehttp/runtime/policies/_authentication_async.py
+++ b/sdk/core/corehttp/corehttp/runtime/policies/_authentication_async.py
@@ -5,7 +5,7 @@
 # -------------------------------------------------------------------------
 from __future__ import annotations
 import time
-from typing import TYPE_CHECKING, Any, Awaitable, Optional, cast, TypeVar
+from typing import TYPE_CHECKING, Any, Awaitable, Optional, cast, TypeVar, Union
 
 from ...credentials import AccessTokenInfo, TokenRequestOptions
 from ..pipeline import PipelineRequest, PipelineResponse
@@ -29,16 +29,24 @@ class AsyncBearerTokenCredentialPolicy(AsyncHTTPPolicy[HTTPRequestType, AsyncHTT
     :param credential: The credential.
     :type credential: ~corehttp.credentials.TokenCredential
     :param str scopes: Lets you specify the type of access needed.
+    :keyword auth_flows: A list of authentication flows to use for the credential.
+    :paramtype auth_flows: list[dict[str, Union[str, list[dict[str, str]]]]]
     """
 
+    # pylint: disable=unused-argument
     def __init__(
-        self, credential: "AsyncTokenCredential", *scopes: str, **kwargs: Any  # pylint: disable=unused-argument
+        self,
+        credential: "AsyncTokenCredential",
+        *scopes: str,
+        auth_flows: Optional[list[dict[str, Union[str, list[dict[str, str]]]]]] = None,
+        **kwargs: Any,
     ) -> None:
         super().__init__()
         self._credential = credential
         self._lock_instance = None
         self._scopes = scopes
         self._token: Optional[AccessTokenInfo] = None
+        self._auth_flows = auth_flows
 
     @property
     def _lock(self):
@@ -46,11 +54,18 @@ def _lock(self):
             self._lock_instance = get_running_async_lock()
         return self._lock_instance
 
-    async def on_request(self, request: PipelineRequest[HTTPRequestType]) -> None:
+    async def on_request(
+        self,
+        request: PipelineRequest[HTTPRequestType],
+        *,
+        auth_flows: Optional[list[dict[str, Union[str, list[dict[str, str]]]]]] = None,
+    ) -> None:
         """Adds a bearer token Authorization header to request and sends request to next policy.
 
         :param request: The pipeline request object to be modified.
         :type request: ~corehttp.runtime.pipeline.PipelineRequest
+        :keyword auth_flows: A list of authentication flows to use for the credential.
+        :paramtype auth_flows: list[dict[str, Union[str, list[dict[str, str]]]]]
         :raises: :class:`~corehttp.exceptions.ServiceRequestError`
         """
         _BearerTokenCredentialPolicyBase._enforce_https(request)  # pylint:disable=protected-access
@@ -59,7 +74,8 @@ async def on_request(self, request: PipelineRequest[HTTPRequestType]) -> None:
             async with self._lock:
                 # double check because another coroutine may have acquired a token while we waited to acquire the lock
                 if self._token is None or self._need_new_token:
-                    self._token = await await_result(self._credential.get_token_info, *self._scopes)
+                    options: TokenRequestOptions = {"auth_flows": auth_flows} if auth_flows else {}  # type: ignore
+                    self._token = await await_result(self._credential.get_token_info, *self._scopes, options=options)
         request.http_request.headers["Authorization"] = "Bearer " + cast(AccessTokenInfo, self._token).token
 
     async def authorize_request(self, request: PipelineRequest[HTTPRequestType], *scopes: str, **kwargs: Any) -> None:
@@ -91,7 +107,7 @@ async def send(
         :return: The pipeline response object
         :rtype: ~corehttp.runtime.pipeline.PipelineResponse
         """
-        await await_result(self.on_request, request)
+        await await_result(self.on_request, request, auth_flows=self._auth_flows)
         try:
             response = await self.next.send(request)
         except Exception:
diff --git a/sdk/core/corehttp/tests/async_tests/test_authentication_async.py b/sdk/core/corehttp/tests/async_tests/test_authentication_async.py
index e41305903c64..c0105a715f4f 100644
--- a/sdk/core/corehttp/tests/async_tests/test_authentication_async.py
+++ b/sdk/core/corehttp/tests/async_tests/test_authentication_async.py
@@ -212,7 +212,7 @@ async def send(self, request):
     pipeline = AsyncPipeline(transport=transport, policies=[policy])
     await pipeline.run(HttpRequest("GET", "https://localhost"))
 
-    policy.on_request.assert_called_once_with(policy.request)
+    policy.on_request.assert_called_once_with(policy.request, auth_flows=None)
     policy.on_response.assert_called_once_with(policy.request, policy.response)
 
     # the policy should call on_exception when next.send() raises
@@ -275,7 +275,7 @@ def get_completed_future(result=None):
 @pytest.mark.asyncio
 async def test_async_token_credential_inheritance():
     class TestTokenCredential(AsyncTokenCredential):
-        async def get_token_info(self, *scopes, options=None):
+        async def get_token_info(self, *scopes, options={}):
             return "TOKEN"
 
     cred = TestTokenCredential()
@@ -319,3 +319,18 @@ async def test_need_new_token():
     # Token is not close to expiring, but refresh_on is in the past.
     policy._token = AccessTokenInfo("", now + 1200, refresh_on=now - 1)
     assert policy._need_new_token
+
+
+@pytest.mark.asyncio
+async def test_send_with_auth_flows():
+    auth_flows = [{"type": "flow1"}, {"type": "flow2"}]
+    credential = Mock(
+        spec_set=["get_token_info"],
+        get_token_info=Mock(return_value=get_completed_future(AccessTokenInfo("***", int(time.time()) + 3600))),
+    )
+    policy = AsyncBearerTokenCredentialPolicy(credential, "scope", auth_flows=auth_flows)
+    transport = Mock(send=Mock(return_value=get_completed_future(Mock(status_code=200))))
+
+    pipeline = AsyncPipeline(transport=transport, policies=[policy])
+    await pipeline.run(HttpRequest("GET", "https://localhost"))
+    policy._credential.get_token_info.assert_called_with("scope", options={"auth_flows": auth_flows})
diff --git a/sdk/core/corehttp/tests/test_authentication.py b/sdk/core/corehttp/tests/test_authentication.py
index f7a6a0da3be6..23889673c41e 100644
--- a/sdk/core/corehttp/tests/test_authentication.py
+++ b/sdk/core/corehttp/tests/test_authentication.py
@@ -139,7 +139,7 @@ def test_bearer_policy_default_context():
 
     pipeline.run(HttpRequest("GET", "https://localhost"))
 
-    credential.get_token_info.assert_called_once_with(expected_scope)
+    credential.get_token_info.assert_called_once_with(expected_scope, options={})
 
 
 def test_bearer_policy_context_unmodified_by_default():
@@ -194,7 +194,7 @@ def test_bearer_policy_cannot_complete_challenge():
 
     assert response.http_response is expected_response
     assert transport.send.call_count == 1
-    credential.get_token_info.assert_called_once_with(expected_scope)
+    credential.get_token_info.assert_called_once_with(expected_scope, options={})
 
 
 def test_bearer_policy_calls_sansio_methods():
@@ -221,7 +221,7 @@ def send(self, request):
     pipeline = Pipeline(transport=transport, policies=[policy])
     pipeline.run(HttpRequest("GET", "https://localhost"))
 
-    policy.on_request.assert_called_once_with(policy.request)
+    policy.on_request.assert_called_once_with(policy.request, auth_flows=None)
     policy.on_response.assert_called_once_with(policy.request, policy.response)
 
     # the policy should call on_exception when next.send() raises
@@ -415,3 +415,17 @@ def test_need_new_token():
     # Token is not close to expiring, but refresh_on is in the past.
     policy._token = AccessTokenInfo("", now + 1200, refresh_on=now - 1)
     assert policy._need_new_token
+
+
+def test_send_with_auth_flows():
+    auth_flows = [{"type": "flow1"}, {"type": "flow2"}]
+    credential = Mock(
+        spec_set=["get_token_info"],
+        get_token_info=Mock(return_value=AccessTokenInfo("***", int(time.time()) + 3600)),
+    )
+    policy = BearerTokenCredentialPolicy(credential, "scope", auth_flows=auth_flows)
+    transport = Mock(send=Mock(return_value=Mock(status_code=200)))
+
+    pipeline = Pipeline(transport=transport, policies=[policy])
+    pipeline.run(HttpRequest("GET", "https://localhost"))
+    policy._credential.get_token_info.assert_called_with("scope", options={"auth_flows": auth_flows})


Reviews:
user: login: copilot-pull-request-reviewer[bot]
body: ## Pull Request Overview

This PR introduces support for the auth_flows keyword in bearer token authentication flows across synchronous and asynchronous pipelines.  
- Updated tests to pass the new auth_flows parameter to request-handling methods.  
- Modified the _authentication and _authentication_async policies to incorporate auth_flows when obtaining tokens.  
- Updated CHANGELOG and added a type-ignore comment for OpenTelemetry context detachment.

### Reviewed Changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated no comments.

<details>
<summary>Show a summary per file</summary>

| File                                                                       | Description                                                                         |
|----------------------------------------------------------------------------|-------------------------------------------------------------------------------------|
| sdk/core/corehttp/tests/async_tests/test_authentication_async.py           | Updated test cases to pass auth_flows and modified the token credential method.     |
| sdk/core/corehttp/tests/test_authentication.py                             | Updated assertions and token request options for auth_flows.                        |
| sdk/core/corehttp/corehttp/runtime/policies/_authentication.py             | Changed on_request signature and added auth_flows support in token acquisition.     |
| sdk/core/corehttp/corehttp/runtime/policies/_authentication_async.py         | Updated asynchronous on_request to support auth_flows.                            |
| sdk/core/azure-core/azure/core/tracing/opentelemetry.py                     | Added "# type: ignore" for a detachment call.                                       |
| sdk/core/azure-core/CHANGELOG.md                                           | Documented the addition of auth_flows support in BearerTokenCredentialPolicy.         |
</details>



<details>
<summary>Comments suppressed due to low confidence (1)</summary>

**sdk/core/corehttp/tests/async_tests/test_authentication_async.py:278**
* Avoid using mutable default arguments. Change the default value of options to None and initialize it to {} within the function.
```
async def get_token_info(self, *scopes, options={):
```
</details>


state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-17T19:11:37Z
user: login: pvaneck
body: Can you explain the workflow here and how `auth_flows` will be used inside a credential's `get_token_info` method? Not quite sure why we need it at the policy level.
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-18T22:03:52Z
user: login: xiangyan99
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-18T23:09:20Z
user: login: xiangyan99
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-19T00:16:02Z
user: login: pvaneck
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-19T22:22:55Z
user: login: xiangyan99
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-19T22:26:59Z
user: login: pvaneck
state: APPROVED
author_association: MEMBER
submitted_at: 2025-03-19T23:31:40Z
user: login: pvaneck
body: Actually, looks like wrong changelog was updated
state: CHANGES_REQUESTED
author_association: MEMBER
submitted_at: 2025-03-19T23:32:35Z
user: login: pvaneck
state: APPROVED
author_association: MEMBER
submitted_at: 2025-03-20T00:10:59Z
user: login: msyyc
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-20T02:42:48Z
user: login: xiangyan99
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-20T15:20:51Z
user: login: msyyc
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-21T02:13:18Z
user: login: msyyc
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-26T06:16:14Z

Review comments:
diff_hunk: @@ -83,20 +90,25 @@ class BearerTokenCredentialPolicy(_BearerTokenCredentialPolicyBase, HTTPPolicy[H
     :param credential: The credential.
     :type credential: ~corehttp.TokenCredential
     :param str scopes: Lets you specify the type of access needed.
+    :keyword list[dict[str, str]] auth_flows: A list of authentication flows to use for the credential.
     :raises: :class:`~corehttp.exceptions.ServiceRequestError`
     """
 
-    def on_request(self, request: PipelineRequest[HTTPRequestType]) -> None:
+    def on_request(
+        self, request: PipelineRequest[HTTPRequestType], *, auth_flows: Optional[list[dict[str, str]]] = None
+    ) -> None:
         """Called before the policy sends a request.
 
         The base implementation authorizes the request with a bearer token.
 
         :param ~corehttp.runtime.pipeline.PipelineRequest request: the request
+        :keyword list[dict[str, str]] auth_flows: A list of authentication flows to use for the credential.
         """
         self._enforce_https(request)
 
         if self._token is None or self._need_new_token:
-            self._token = self._credential.get_token_info(*self._scopes)
+            options: TokenRequestOptions = {"auth_flows": auth_flows} if auth_flows else {}  # type: ignore
path: sdk/core/corehttp/corehttp/runtime/policies/_authentication.py
user: login: pvaneck
body: Add `auth_flows` to the TypedDict `TokenRequestOptions` class?
created_at: 2025-03-18T01:54:03Z
author_association: MEMBER
diff_hunk: @@ -83,20 +90,25 @@ class BearerTokenCredentialPolicy(_BearerTokenCredentialPolicyBase, HTTPPolicy[H
     :param credential: The credential.
     :type credential: ~corehttp.TokenCredential
     :param str scopes: Lets you specify the type of access needed.
+    :keyword list[dict[str, str]] auth_flows: A list of authentication flows to use for the credential.
     :raises: :class:`~corehttp.exceptions.ServiceRequestError`
     """
 
-    def on_request(self, request: PipelineRequest[HTTPRequestType]) -> None:
+    def on_request(
+        self, request: PipelineRequest[HTTPRequestType], *, auth_flows: Optional[list[dict[str, str]]] = None
path: sdk/core/corehttp/corehttp/runtime/policies/_authentication.py
user: login: pvaneck
body: Do we need to take in `auth_flows` as a parameter here? Or can we just access it in this method via `self._auth_flows`?
created_at: 2025-03-18T02:00:15Z
author_association: MEMBER
diff_hunk: @@ -240,4 +240,4 @@ def _detach_from_context(cls, token: object) -> None:
         :param token: The token to detach
         :type token: object
         """
-        otel_context_module.detach(token)
+        otel_context_module.detach(token)  # type: ignore
path: sdk/core/azure-core/azure/core/tracing/opentelemetry.py
user: login: pvaneck
body: This method is correctly typed in `main` now, so no longer need this to fix mypy.
created_at: 2025-03-18T20:36:53Z
author_association: MEMBER
diff_hunk: @@ -83,20 +90,25 @@ class BearerTokenCredentialPolicy(_BearerTokenCredentialPolicyBase, HTTPPolicy[H
     :param credential: The credential.
     :type credential: ~corehttp.TokenCredential
     :param str scopes: Lets you specify the type of access needed.
+    :keyword list[dict[str, str]] auth_flows: A list of authentication flows to use for the credential.
     :raises: :class:`~corehttp.exceptions.ServiceRequestError`
     """
 
-    def on_request(self, request: PipelineRequest[HTTPRequestType]) -> None:
+    def on_request(
+        self, request: PipelineRequest[HTTPRequestType], *, auth_flows: Optional[list[dict[str, str]]] = None
path: sdk/core/corehttp/corehttp/runtime/policies/_authentication.py
user: login: xiangyan99
body: I have the parameter because we will support per-operation auth_flow. :)
created_at: 2025-03-18T23:09:20Z
author_association: MEMBER
diff_hunk: @@ -83,20 +90,25 @@ class BearerTokenCredentialPolicy(_BearerTokenCredentialPolicyBase, HTTPPolicy[H
     :param credential: The credential.
     :type credential: ~corehttp.TokenCredential
     :param str scopes: Lets you specify the type of access needed.
+    :keyword list[dict[str, str]] auth_flows: A list of authentication flows to use for the credential.
     :raises: :class:`~corehttp.exceptions.ServiceRequestError`
     """
 
-    def on_request(self, request: PipelineRequest[HTTPRequestType]) -> None:
+    def on_request(
+        self, request: PipelineRequest[HTTPRequestType], *, auth_flows: Optional[list[dict[str, str]]] = None
+    ) -> None:
         """Called before the policy sends a request.
 
         The base implementation authorizes the request with a bearer token.
 
         :param ~corehttp.runtime.pipeline.PipelineRequest request: the request
+        :keyword list[dict[str, str]] auth_flows: A list of authentication flows to use for the credential.
         """
         self._enforce_https(request)
 
         if self._token is None or self._need_new_token:
-            self._token = self._credential.get_token_info(*self._scopes)
+            options: TokenRequestOptions = {"auth_flows": auth_flows} if auth_flows else {}  # type: ignore
path: sdk/core/corehttp/corehttp/runtime/policies/_authentication.py
user: login: xiangyan99
body: It is optional. I would hold until the GA at least. :)
created_at: 2025-03-19T00:16:02Z
author_association: MEMBER
diff_hunk: @@ -83,20 +90,25 @@ class BearerTokenCredentialPolicy(_BearerTokenCredentialPolicyBase, HTTPPolicy[H
     :param credential: The credential.
     :type credential: ~corehttp.TokenCredential
     :param str scopes: Lets you specify the type of access needed.
+    :keyword list[dict[str, str]] auth_flows: A list of authentication flows to use for the credential.
     :raises: :class:`~corehttp.exceptions.ServiceRequestError`
     """
 
-    def on_request(self, request: PipelineRequest[HTTPRequestType]) -> None:
+    def on_request(
+        self, request: PipelineRequest[HTTPRequestType], *, auth_flows: Optional[list[dict[str, str]]] = None
path: sdk/core/corehttp/corehttp/runtime/policies/_authentication.py
user: login: pvaneck
body: Per-operation parameters are generally passed through `request.context.options`. Would that not work here?
created_at: 2025-03-19T22:01:28Z
author_association: MEMBER
diff_hunk: @@ -83,20 +90,25 @@ class BearerTokenCredentialPolicy(_BearerTokenCredentialPolicyBase, HTTPPolicy[H
     :param credential: The credential.
     :type credential: ~corehttp.TokenCredential
     :param str scopes: Lets you specify the type of access needed.
+    :keyword list[dict[str, str]] auth_flows: A list of authentication flows to use for the credential.
     :raises: :class:`~corehttp.exceptions.ServiceRequestError`
     """
 
-    def on_request(self, request: PipelineRequest[HTTPRequestType]) -> None:
+    def on_request(
+        self, request: PipelineRequest[HTTPRequestType], *, auth_flows: Optional[list[dict[str, str]]] = None
path: sdk/core/corehttp/corehttp/runtime/policies/_authentication.py
user: login: xiangyan99
body: Isn't it passed into `send` method? I plan to do the logic (no auth, override auth, use default auth) in `send` and then call `on_request` with the parameter from the `send` method.
created_at: 2025-03-19T22:26:58Z
author_association: MEMBER
diff_hunk: @@ -32,15 +32,22 @@ class _BearerTokenCredentialPolicyBase:
     :param credential: The credential.
     :type credential: ~corehttp.credentials.TokenCredential
     :param str scopes: Lets you specify the type of access needed.
+    :keyword list[dict[str, str]] auth_flows: A list of authentication flows to use for the credential.
     """
 
+    # pylint: disable=unused-argument
     def __init__(
-        self, credential: "TokenCredential", *scopes: str, **kwargs: Any  # pylint: disable=unused-argument
+        self,
+        credential: "TokenCredential",
+        *scopes: str,
+        auth_flows: Optional[list[dict[str, str]]] = None,
path: sdk/core/corehttp/corehttp/runtime/policies/_authentication.py
user: login: msyyc
body: @xiangyan99 the flows info also contains `scopes` whose type is `list[str]`:
![image](https://github.com/user-attachments/assets/dae6938c-84b2-45d2-8faf-da3446d467e4)
Just confirm that all info of flows including "scopes" shall be passed to `auth_flow`?
If yes, the typing shall be `Optional[list[dict[str, Union[str, list[str]]]]]`. Since we can't expect whether there will be other type in the future so is it better for typing to be `Optional[list[dict[str, Any]]]`?
created_at: 2025-03-20T02:42:48Z
author_association: MEMBER
diff_hunk: @@ -32,15 +32,22 @@ class _BearerTokenCredentialPolicyBase:
     :param credential: The credential.
     :type credential: ~corehttp.credentials.TokenCredential
     :param str scopes: Lets you specify the type of access needed.
+    :keyword list[dict[str, str]] auth_flows: A list of authentication flows to use for the credential.
     """
 
+    # pylint: disable=unused-argument
     def __init__(
-        self, credential: "TokenCredential", *scopes: str, **kwargs: Any  # pylint: disable=unused-argument
+        self,
+        credential: "TokenCredential",
+        *scopes: str,
+        auth_flows: Optional[list[dict[str, str]]] = None,
path: sdk/core/corehttp/corehttp/runtime/policies/_authentication.py
user: login: xiangyan99
body: Yes. We need all the information to be passed into the ctor. I will update the typing. Is `scopes` always a list? @msyyc 
created_at: 2025-03-20T15:20:51Z
author_association: MEMBER
diff_hunk: @@ -32,15 +32,22 @@ class _BearerTokenCredentialPolicyBase:
     :param credential: The credential.
     :type credential: ~corehttp.credentials.TokenCredential
     :param str scopes: Lets you specify the type of access needed.
+    :keyword list[dict[str, str]] auth_flows: A list of authentication flows to use for the credential.
     """
 
+    # pylint: disable=unused-argument
     def __init__(
-        self, credential: "TokenCredential", *scopes: str, **kwargs: Any  # pylint: disable=unused-argument
+        self,
+        credential: "TokenCredential",
+        *scopes: str,
+        auth_flows: Optional[list[dict[str, str]]] = None,
path: sdk/core/corehttp/corehttp/runtime/policies/_authentication.py
user: login: msyyc
body: According to current definition in @typespec/http, it is always list : https://github.com/microsoft/typespec/blob/bf528cdd57a38bb25e61065c79509a5d5831e631/packages/http/src/types.ts#L132-L168. But I am not sure whether there will be other types added in the flow.
created_at: 2025-03-21T02:13:18Z
author_association: MEMBER
diff_hunk: @@ -32,15 +32,22 @@ class _BearerTokenCredentialPolicyBase:
     :param credential: The credential.
     :type credential: ~corehttp.credentials.TokenCredential
     :param str scopes: Lets you specify the type of access needed.
+    :keyword list[dict[str, str]] auth_flows: A list of authentication flows to use for the credential.
     """
 
+    # pylint: disable=unused-argument
     def __init__(
-        self, credential: "TokenCredential", *scopes: str, **kwargs: Any  # pylint: disable=unused-argument
+        self,
+        credential: "TokenCredential",
+        *scopes: str,
+        auth_flows: Optional[list[dict[str, str]]] = None,
path: sdk/core/corehttp/corehttp/runtime/policies/_authentication.py
user: login: msyyc
body: @xiangyan99 sorry, I find that `OAuth2Scope` is an [object](https://github.com/microsoft/typespec/blob/9faa31eb767c9ef00a9ef28b4bbeab955b7d1a94/packages/http/src/types.ts#L170-L173) instead of string so the typing shall be `Optional[list[dict[str, Union[str, list[dict[str, str]]]]]]`. 

created_at: 2025-03-26T06:16:13Z
author_association: MEMBER

PR comments:
user: login: azure-sdk
created_at: 2025-03-14T23:40:43Z
body: **API change check**

API changes are not detected in this pull request.
author_association: COLLABORATOR
user: login: pvaneck
created_at: 2025-03-19T22:24:10Z
body: Could you also share some context on how auth_flows will be used inside a credential's get_token_info method?
author_association: MEMBER
user: login: xiangyan99
created_at: 2025-03-19T22:28:24Z
body: > Could you also share some context on how auth_flows will be used inside a credential's get_token_info method?

get_token_info needs to get the meta data from auth_flows.

e.g. the credential needs to get the token url to know where the request should be sent to.

Under current design, auth_flows is a list of auth context.

We will share a sample in this release and in the sample, we will assume the first one in the list has the correct meta information for the credential.
author_association: MEMBER