Skip to content

Commit 3b96de6

Browse files
committed
Implement remove_tokens_for_client()
1 parent b286540 commit 3b96de6

File tree

2 files changed

+42
-0
lines changed

2 files changed

+42
-0
lines changed

msal/application.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2178,6 +2178,19 @@ def _acquire_token_for_client(
21782178
telemetry_context.update_telemetry(response)
21792179
return response
21802180

2181+
def remove_tokens_for_client(self):
2182+
"""Remove all tokens that were previously acquired via
2183+
:func:`~acquire_token_for_client()` for the current client."""
2184+
for env in [self.authority.instance] + self._get_authority_aliases(
2185+
self.authority.instance):
2186+
for at in self.token_cache.find(TokenCache.CredentialType.ACCESS_TOKEN, query={
2187+
"client_id": self.client_id,
2188+
"environment": env,
2189+
"home_account_id": None, # These are mostly app-only tokens
2190+
}):
2191+
self.token_cache.remove_at(at)
2192+
# acquire_token_for_client() obtains no RTs, so we have no RT to remove
2193+
21812194
def acquire_token_on_behalf_of(self, user_assertion, scopes, claims_challenge=None, **kwargs):
21822195
"""Acquires token using on-behalf-of (OBO) flow.
21832196

tests/test_application.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -662,6 +662,35 @@ def test_organizations_authority_should_emit_warning(self):
662662
authority="https://login.microsoftonline.com/organizations")
663663

664664

665+
class TestRemoveTokensForClient(unittest.TestCase):
666+
def test_remove_tokens_for_client_should_remove_client_tokens_only(self):
667+
at_for_user = "AT for user"
668+
cca = msal.ConfidentialClientApplication(
669+
"client_id", client_credential="secret",
670+
authority="https://login.microsoftonline.com/microsoft.onmicrosoft.com")
671+
self.assertEqual(
672+
0, len(cca.token_cache.find(msal.TokenCache.CredentialType.ACCESS_TOKEN)))
673+
cca.acquire_token_for_client(
674+
["scope"],
675+
post=lambda url, **kwargs: MinimalResponse(
676+
status_code=200, text=json.dumps({"access_token": "AT for client"})))
677+
self.assertEqual(
678+
1, len(cca.token_cache.find(msal.TokenCache.CredentialType.ACCESS_TOKEN)))
679+
cca.acquire_token_by_username_password(
680+
"johndoe", "password", ["scope"],
681+
post=lambda url, **kwargs: MinimalResponse(
682+
status_code=200, text=json.dumps(build_response(
683+
access_token=at_for_user, expires_in=3600,
684+
uid="uid", utid="utid", # This populates home_account_id
685+
))))
686+
self.assertEqual(
687+
2, len(cca.token_cache.find(msal.TokenCache.CredentialType.ACCESS_TOKEN)))
688+
cca.remove_tokens_for_client()
689+
remaining_tokens = cca.token_cache.find(msal.TokenCache.CredentialType.ACCESS_TOKEN)
690+
self.assertEqual(1, len(remaining_tokens))
691+
self.assertEqual(at_for_user, remaining_tokens[0].get("secret"))
692+
693+
665694
class TestScopeDecoration(unittest.TestCase):
666695
def _test_client_id_should_be_a_valid_scope(self, client_id, other_scopes):
667696
# B2C needs this https://learn.microsoft.com/en-us/azure/active-directory-b2c/access-tokens#openid-connect-scopes

0 commit comments

Comments
 (0)