DEV Community

Christos Matskas for The 425 Show

Posted on

A Python MSAL Token Cache for Confidential Clients

MSAL, the Microsoft Authentication Library, helps developers implement authentication and authorization using Azure AD or Azure AD B2C. With a few lines of code, you can add the necessary functionality sign in users and secure resources. MSAL comes with a lot of built-in capabilities to help you do as little work as possible. MFA, Conditional Access and advanced features are available out of the box - no code needed. In many cases, token caching is also provided out of the box. For example, the default cache is in memory. This works great for most dev scenarios, like testing web apps and APIs.

However, there are certain scenarios that in-memory token caching doesn't work. Ideally, any workload deployed to production should have a persisted and scalable token cache.

In this blog post, we'll look at how to setup a file-based token cache for our Python-based daemon app. The reason why we need a token cache is because daemon apps are ephemeral. The app runs for a bit to execute a certain task and then terminates. The problem here is that without a token cache, every time we run the daemon, we have to authenticate and acquire a token from Azure AD - which is not efficient!

Let's build a cache.

Building the MSAL Python Cache

The good news is that we don't really have to do a lot of work for this. The MSAL team has already built an extension library for Python to provide the basic plumbing for our token cache.

In our existing Python app, we need to add the new library and implement a bit of code to set everything up.

Open the requirements.txt, add the following and save the file:

msal-extensions>=0.3.0
Enter fullscreen mode Exit fullscreen mode

We can now update our dependencies

pip install -r requirement.txt
Enter fullscreen mode Exit fullscreen mode

Create a new file msalcache.py and add the following code

import sys
import logging

from msal_extensions import *

def build_persistence(location, fallback_to_plaintext=False):
    if sys.platform.startswith('win'):
        return FilePersistenceWithDataProtection(location)
    if sys.platform.startswith('darwin'):
        return KeychainPersistence(location, "my_service_name", "my_account_name")
    if sys.platform.startswith('linux'):
        try:
            return LibsecretPersistence(
                location,
                schema_name="my_schema_name",
                attributes={"attr1": "hello", "attr2": "world"},
                )
        except:
            if not fallback_to_plaintext:
                raise
            logging.exception("Encryption unavailable. Opting in to plain text.")
    return FilePersistence(location)
Enter fullscreen mode Exit fullscreen mode

That's it. We can now use this code to instantiate a cache and assign it to our MSAL Confidential Client.

Using the token cache with MSAL

Before instantiating our MSAL ConfidentialClient we need to create a cache. Add the following code to console.py (or your main code file)

persistence =msalcache.build_persistence("token_cache.bin")
print(f'The MSAL Cache supports encryption: {persistence.is_encrypted}')
cache = PersistedTokenCache(persistence)
Enter fullscreen mode Exit fullscreen mode

Finally, we have to update our ConfidentialClient client to use the cache. Update the code as per below:

app = msal.ConfidentialClientApplication(
    client_id=config["client_id"],
    client_credential=aad_client_secret.value,
    authority=config["authority"],
    token_cache=cache
)
Enter fullscreen mode Exit fullscreen mode

That's it!

Running the code from now on will make use of the cache and the call the acquire_token_silent() will yield an access token after the first time we run our daemon :)

You can get the source code for this project from our GitHub repo

If you want to learn more about the MSAL for Python library, you can read the docs here

Top comments (0)