@@ -1209,32 +1209,24 @@ def acquire_token_silent(
12091209 ** kwargs ):
12101210 """Acquire an access token for given account, without user interaction.
12111211
1212- It is done either by finding a valid access token from cache,
1213- or by finding a valid refresh token from cache and then automatically
1214- use it to redeem a new access token.
1215-
1212+ It has same parameters as the :func:`~acquire_token_silent_with_error`.
1213+ The difference is the behavior of the return value.
12161214 This method will combine the cache empty and refresh error
12171215 into one return value, `None`.
12181216 If your app does not care about the exact token refresh error during
12191217 token cache look-up, then this method is easier and recommended.
12201218
1221- Internally, this method calls :func:`~acquire_token_silent_with_error`.
1222-
1223- :param claims_challenge:
1224- The claims_challenge parameter requests specific claims requested by the resource provider
1225- in the form of a claims_challenge directive in the www-authenticate header to be
1226- returned from the UserInfo Endpoint and/or in the ID Token and/or Access Token.
1227- It is a string of a JSON object which contains lists of claims being requested from these locations.
1228-
12291219 :return:
12301220 - A dict containing no "error" key,
12311221 and typically contains an "access_token" key,
12321222 if cache lookup succeeded.
12331223 - None when cache lookup does not yield a token.
12341224 """
1235- result = self .acquire_token_silent_with_error (
1225+ if not account :
1226+ return None # A backward-compatible NO-OP to drop the account=None usage
1227+ result = _clean_up (self ._acquire_token_silent_with_error (
12361228 scopes , account , authority = authority , force_refresh = force_refresh ,
1237- claims_challenge = claims_challenge , ** kwargs )
1229+ claims_challenge = claims_challenge , ** kwargs ))
12381230 return result if result and "error" not in result else None
12391231
12401232 def acquire_token_silent_with_error (
@@ -1258,9 +1250,10 @@ def acquire_token_silent_with_error(
12581250
12591251 :param list[str] scopes: (Required)
12601252 Scopes requested to access a protected API (a resource).
1261- :param account:
1262- one of the account object returned by :func:`~get_accounts`,
1263- or use None when you want to find an access token for this client.
1253+ :param account: (Required)
1254+ One of the account object returned by :func:`~get_accounts`.
1255+ Starting from MSAL Python 1.23,
1256+ a ``None`` input will become a NO-OP and always return ``None``.
12641257 :param force_refresh:
12651258 If True, it will skip Access Token look-up,
12661259 and try to find a Refresh Token to obtain a new Access Token.
@@ -1276,6 +1269,20 @@ def acquire_token_silent_with_error(
12761269 - None when there is simply no token in the cache.
12771270 - A dict containing an "error" key, when token refresh failed.
12781271 """
1272+ if not account :
1273+ return None # A backward-compatible NO-OP to drop the account=None usage
1274+ return _clean_up (self ._acquire_token_silent_with_error (
1275+ scopes , account , authority = authority , force_refresh = force_refresh ,
1276+ claims_challenge = claims_challenge , ** kwargs ))
1277+
1278+ def _acquire_token_silent_with_error (
1279+ self ,
1280+ scopes , # type: List[str]
1281+ account , # type: Optional[Account]
1282+ authority = None , # See get_authorization_request_url()
1283+ force_refresh = False , # type: Optional[boolean]
1284+ claims_challenge = None ,
1285+ ** kwargs ):
12791286 assert isinstance (scopes , list ), "Invalid parameter type"
12801287 self ._validate_ssh_cert_input_data (kwargs .get ("data" , {}))
12811288 correlation_id = msal .telemetry ._get_new_correlation_id ()
@@ -1335,7 +1342,11 @@ def _acquire_token_silent_from_cache_and_possibly_refresh_it(
13351342 force_refresh = False , # type: Optional[boolean]
13361343 claims_challenge = None ,
13371344 correlation_id = None ,
1345+ http_exceptions = None ,
13381346 ** kwargs ):
1347+ # This internal method has two calling patterns:
1348+ # it accepts a non-empty account to find token for a user,
1349+ # and accepts account=None to find a token for the current app.
13391350 access_token_from_cache = None
13401351 if not (force_refresh or claims_challenge ): # Bypass AT when desired or using claims
13411352 query = {
@@ -1372,6 +1383,10 @@ def _acquire_token_silent_from_cache_and_possibly_refresh_it(
13721383 else :
13731384 refresh_reason = msal .telemetry .FORCE_REFRESH # TODO: It could also mean claims_challenge
13741385 assert refresh_reason , "It should have been established at this point"
1386+ if not http_exceptions : # It can be a tuple of exceptions
1387+ # The exact HTTP exceptions are transportation-layer dependent
1388+ from requests .exceptions import RequestException # Lazy load
1389+ http_exceptions = (RequestException ,)
13751390 try :
13761391 data = kwargs .get ("data" , {})
13771392 if account and account .get ("authority_type" ) == _AUTHORITY_TYPE_CLOUDSHELL :
@@ -1391,14 +1406,19 @@ def _acquire_token_silent_from_cache_and_possibly_refresh_it(
13911406 if response : # The broker provided a decisive outcome, so we use it
13921407 return self ._process_broker_response (response , scopes , data )
13931408
1394- result = _clean_up (self ._acquire_token_silent_by_finding_rt_belongs_to_me_or_my_family (
1395- authority , self ._decorate_scope (scopes ), account ,
1396- refresh_reason = refresh_reason , claims_challenge = claims_challenge ,
1397- correlation_id = correlation_id ,
1398- ** kwargs ))
1409+ if account :
1410+ result = self ._acquire_token_silent_by_finding_rt_belongs_to_me_or_my_family (
1411+ authority , self ._decorate_scope (scopes ), account ,
1412+ refresh_reason = refresh_reason , claims_challenge = claims_challenge ,
1413+ correlation_id = correlation_id ,
1414+ ** kwargs )
1415+ else : # The caller is acquire_token_for_client()
1416+ result = self ._acquire_token_for_client (
1417+ scopes , refresh_reason , claims_challenge = claims_challenge ,
1418+ ** kwargs )
13991419 if (result and "error" not in result ) or (not access_token_from_cache ):
14001420 return result
1401- except : # The exact HTTP exception is transportation-layer dependent
1421+ except http_exceptions :
14021422 # Typically network error. Potential AAD outage?
14031423 if not access_token_from_cache : # It means there is no fall back option
14041424 raise # We choose to bubble up the exception
@@ -2007,6 +2027,9 @@ class ConfidentialClientApplication(ClientApplication): # server-side web app
20072027 def acquire_token_for_client (self , scopes , claims_challenge = None , ** kwargs ):
20082028 """Acquires token for the current confidential client, not for an end user.
20092029
2030+ Since MSAL Python 1.23, it will automatically look for token from cache,
2031+ and only send request to Identity Provider when cache misses.
2032+
20102033 :param list[str] scopes: (Required)
20112034 Scopes requested to access a protected API (a resource).
20122035 :param claims_challenge:
@@ -2020,24 +2043,37 @@ def acquire_token_for_client(self, scopes, claims_challenge=None, **kwargs):
20202043 - A successful response would contain "access_token" key,
20212044 - an error response would contain "error" and usually "error_description".
20222045 """
2023- # TBD: force_refresh behavior
2046+ if kwargs .get ("force_refresh" ):
2047+ raise ValueError ( # We choose to disallow force_refresh
2048+ "Historically, this method does not support force_refresh behavior. "
2049+ )
2050+ return _clean_up (self ._acquire_token_silent_with_error (
2051+ scopes , None , claims_challenge = claims_challenge , ** kwargs ))
2052+
2053+ def _acquire_token_for_client (
2054+ self ,
2055+ scopes ,
2056+ refresh_reason ,
2057+ claims_challenge = None ,
2058+ ** kwargs
2059+ ):
20242060 if self .authority .tenant .lower () in ["common" , "organizations" ]:
20252061 warnings .warn (
20262062 "Using /common or /organizations authority "
20272063 "in acquire_token_for_client() is unreliable. "
20282064 "Please use a specific tenant instead." , DeprecationWarning )
20292065 self ._validate_ssh_cert_input_data (kwargs .get ("data" , {}))
20302066 telemetry_context = self ._build_telemetry_context (
2031- self .ACQUIRE_TOKEN_FOR_CLIENT_ID )
2067+ self .ACQUIRE_TOKEN_FOR_CLIENT_ID , refresh_reason = refresh_reason )
20322068 client = self ._regional_client or self .client
2033- response = _clean_up ( client .obtain_token_for_client (
2069+ response = client .obtain_token_for_client (
20342070 scope = scopes , # This grant flow requires no scope decoration
20352071 headers = telemetry_context .generate_headers (),
20362072 data = dict (
20372073 kwargs .pop ("data" , {}),
20382074 claims = _merge_claims_challenge_and_capabilities (
20392075 self ._client_capabilities , claims_challenge )),
2040- ** kwargs ))
2076+ ** kwargs )
20412077 telemetry_context .update_telemetry (response )
20422078 return response
20432079
0 commit comments