microsoft-authentication-library-for-python icon indicating copy to clipboard operation
microsoft-authentication-library-for-python copied to clipboard

[Feature Request] Client assertion should accept a callback function

Open jdeus opened this issue 1 year ago • 2 comments

MSAL client type

Confidential

Problem Statement

When client_credential is set to client_assertion, the only acceptable value is a token. However, tokens have a definite validity and as a result, the library as is it not suitable when using dynamic tokens - such as when using workload identities in AKS - because at some point the token becomes expired and a new instance of the Confidential client has to be initiated, which is not straightforward.

Proposed solution

I propose that client_assertion should accept a callback function which is evaluated on demand by the MSAL library, allowing the user-supplied function to retrieve a custom token.

This feature is already available in the .NET and JS versions of this library.

jdeus avatar Sep 18 '24 17:09 jdeus

Guess what? Since day 1, MSAL Python has an undocumented feature of accepting this:

def assertion_callback():
    return "dynamically obtain your new assertion here"

app = ConfidentialClientApplication(
   ...,
   client_credential={"client_assertion": assertion_callback},
)

Note that the callback will be called whenever a token request needs to be sent on the wire. That means:

  1. If you are acquiring the same token (via acquire_token_for_client(..., scopes=["same", "scopes"]) or via acquire_token_silent(...)), MSAL Python's token cache will automatically kick in, no new token request will be made, and your callback won't be called, which is good for efficiency.
  2. If you are acquiring a new token (via acquire_token_for_client(..., scopes=["different", "scopes"]), or via acquire_token_on_behalf_of("a new user assertion", ...)), your callback will be frequently called. But lucky that MSAL Python also has an internal helper AutoRefresher.
    from msal import AutoRefresher  # NOT YET available, but we can expose it in our next release
    smart_callback = AutoRefresher(assertion_callback, expires_in=3600)
    app = ConfidentialClientApplication(
       ...,
       client_credential={"client_assertion": smart_callback},
    )
    

rayluo avatar Sep 18 '24 22:09 rayluo

Cool, can you please (soft) deprecate the string variant then and ensure the docs are updated?

It just causes confusion and there is really no scenario where a string should be provided, because the string assertion expires.

bgavrilMS avatar Sep 19 '24 10:09 bgavrilMS