@@ -1209,32 +1209,24 @@ def acquire_token_silent(
1209
1209
** kwargs ):
1210
1210
"""Acquire an access token for given account, without user interaction.
1211
1211
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.
1216
1214
This method will combine the cache empty and refresh error
1217
1215
into one return value, `None`.
1218
1216
If your app does not care about the exact token refresh error during
1219
1217
token cache look-up, then this method is easier and recommended.
1220
1218
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
-
1229
1219
:return:
1230
1220
- A dict containing no "error" key,
1231
1221
and typically contains an "access_token" key,
1232
1222
if cache lookup succeeded.
1233
1223
- None when cache lookup does not yield a token.
1234
1224
"""
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 (
1236
1228
scopes , account , authority = authority , force_refresh = force_refresh ,
1237
- claims_challenge = claims_challenge , ** kwargs )
1229
+ claims_challenge = claims_challenge , ** kwargs ))
1238
1230
return result if result and "error" not in result else None
1239
1231
1240
1232
def acquire_token_silent_with_error (
@@ -1258,9 +1250,10 @@ def acquire_token_silent_with_error(
1258
1250
1259
1251
:param list[str] scopes: (Required)
1260
1252
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``.
1264
1257
:param force_refresh:
1265
1258
If True, it will skip Access Token look-up,
1266
1259
and try to find a Refresh Token to obtain a new Access Token.
@@ -1276,6 +1269,20 @@ def acquire_token_silent_with_error(
1276
1269
- None when there is simply no token in the cache.
1277
1270
- A dict containing an "error" key, when token refresh failed.
1278
1271
"""
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 ):
1279
1286
assert isinstance (scopes , list ), "Invalid parameter type"
1280
1287
self ._validate_ssh_cert_input_data (kwargs .get ("data" , {}))
1281
1288
correlation_id = msal .telemetry ._get_new_correlation_id ()
@@ -1335,7 +1342,11 @@ def _acquire_token_silent_from_cache_and_possibly_refresh_it(
1335
1342
force_refresh = False , # type: Optional[boolean]
1336
1343
claims_challenge = None ,
1337
1344
correlation_id = None ,
1345
+ http_exceptions = None ,
1338
1346
** 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.
1339
1350
access_token_from_cache = None
1340
1351
if not (force_refresh or claims_challenge ): # Bypass AT when desired or using claims
1341
1352
query = {
@@ -1372,6 +1383,10 @@ def _acquire_token_silent_from_cache_and_possibly_refresh_it(
1372
1383
else :
1373
1384
refresh_reason = msal .telemetry .FORCE_REFRESH # TODO: It could also mean claims_challenge
1374
1385
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 ,)
1375
1390
try :
1376
1391
data = kwargs .get ("data" , {})
1377
1392
if account and account .get ("authority_type" ) == _AUTHORITY_TYPE_CLOUDSHELL :
@@ -1391,14 +1406,19 @@ def _acquire_token_silent_from_cache_and_possibly_refresh_it(
1391
1406
if response : # The broker provided a decisive outcome, so we use it
1392
1407
return self ._process_broker_response (response , scopes , data )
1393
1408
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 )
1399
1419
if (result and "error" not in result ) or (not access_token_from_cache ):
1400
1420
return result
1401
- except : # The exact HTTP exception is transportation-layer dependent
1421
+ except http_exceptions :
1402
1422
# Typically network error. Potential AAD outage?
1403
1423
if not access_token_from_cache : # It means there is no fall back option
1404
1424
raise # We choose to bubble up the exception
@@ -2007,6 +2027,9 @@ class ConfidentialClientApplication(ClientApplication): # server-side web app
2007
2027
def acquire_token_for_client (self , scopes , claims_challenge = None , ** kwargs ):
2008
2028
"""Acquires token for the current confidential client, not for an end user.
2009
2029
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
+
2010
2033
:param list[str] scopes: (Required)
2011
2034
Scopes requested to access a protected API (a resource).
2012
2035
:param claims_challenge:
@@ -2020,24 +2043,37 @@ def acquire_token_for_client(self, scopes, claims_challenge=None, **kwargs):
2020
2043
- A successful response would contain "access_token" key,
2021
2044
- an error response would contain "error" and usually "error_description".
2022
2045
"""
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
+ ):
2024
2060
if self .authority .tenant .lower () in ["common" , "organizations" ]:
2025
2061
warnings .warn (
2026
2062
"Using /common or /organizations authority "
2027
2063
"in acquire_token_for_client() is unreliable. "
2028
2064
"Please use a specific tenant instead." , DeprecationWarning )
2029
2065
self ._validate_ssh_cert_input_data (kwargs .get ("data" , {}))
2030
2066
telemetry_context = self ._build_telemetry_context (
2031
- self .ACQUIRE_TOKEN_FOR_CLIENT_ID )
2067
+ self .ACQUIRE_TOKEN_FOR_CLIENT_ID , refresh_reason = refresh_reason )
2032
2068
client = self ._regional_client or self .client
2033
- response = _clean_up ( client .obtain_token_for_client (
2069
+ response = client .obtain_token_for_client (
2034
2070
scope = scopes , # This grant flow requires no scope decoration
2035
2071
headers = telemetry_context .generate_headers (),
2036
2072
data = dict (
2037
2073
kwargs .pop ("data" , {}),
2038
2074
claims = _merge_claims_challenge_and_capabilities (
2039
2075
self ._client_capabilities , claims_challenge )),
2040
- ** kwargs ))
2076
+ ** kwargs )
2041
2077
telemetry_context .update_telemetry (response )
2042
2078
return response
2043
2079
0 commit comments