AzureAD / microsoft-authentication-library-for-python

Microsoft Authentication Library (MSAL) for Python makes it easy to authenticate to Microsoft Entra ID. General docs are available here https://learn.microsoft.com/entra/msal/python/ Stable APIs are documented here https://msal-python.readthedocs.io. Questions can be asked on www.stackoverflow.com with tag "msal" + "python".
https://stackoverflow.com/questions/tagged/azure-ad-msal+python
Other
788 stars 194 forks source link

When asking for an ID token, acquire_token_silent always refreshes, even if the cached data is still valid #385

Closed wosc closed 3 years ago

wosc commented 3 years ago

I'm using msal to cache an ID token; from the code I figured out that this means specifying scopes=[client_id], and this does work fine, in principle.

Expected behavior If a non-expired ID token is in the cache, I expect acquire_token_silent to return that.

What you see instead acquire_token_silent does not find the cached ID token, since it only looks at access tokens, which of course can never match scopes=[client_id], so it always performs a refresh.

The MSAL Python version you are using 1.13.0

Workaround

I'm now examining the cached ID token manually before calling acquire_token_silent, like this:

from msal.token_cache import decode_id_token
import msal

app = msal.ConfidentialClientApplication(
            client_id, client_secret, token_cache=cache,
            authority='https://login.microsoftonline.com/%s' % tenant_id)
scopes = [client_id]

def get_id_token():
    accounts = app.get_accounts()
    if not accounts:
        return None

    result = app.token_cache.find(app.token_cache.CredentialType.ID_TOKEN)
    if result:
        token = result[0]['secret']
        data = decode_id_token(token)
        # Like _acquire_token_silent_from_cache_and_possibly_refresh_it
        expires_in = data['exp'] - time()
        if expires_in > 5 * 60:
            return token

    result = app.acquire_token_silent(scopes, accounts[0])
    return result['id_token']
rayluo commented 3 years ago

Historically, all acquire_token_xyz(..., scopes=[...]) methods in MSAL are meant to obtain access token (AT). ID token in MSAL is a happpy byprodct which provides the metadata for the current account. Your hack of "using scopes=[client_id] to obtain an ID token" is also the result of such a side effect. We could revisit this at a later time.

Meanwhile, based on your code snippet, your app's accounts[0] shows that it is a single-account app. In such case, you might as well just preserve and reuse the id_token_claims returned from the initial acquire_token_xyz(...) method. Those are the metadata associating with the signed-in account.

wosc commented 3 years ago

Alright, fair enough, if that's a "more like happily accidentally" supported use case, that makes sense. Thanks for explaining!