Microsoft Authentication Extensions for Python

Cross-platform encrypted token cache persistence for MSAL Python, backed by DPAPI, Keychain, and libsecret.

SDK
PyPI
v1.3.1
45stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
30/100Needs Attention
Development Activity0
Maintenance20
Community28
Maturity60
Momentum12

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
73/100Good
Architecture80
Code Quality78
Innovation62
Learning Curve70

Microsoft Authentication Extensions for Python (msal-extensions) adds a persistence layer on top of the Microsoft Authentication Library for Python (MSAL), letting desktop applications save their token cache to disk instead of keeping it only in memory. On Windows it encrypts the cache file with the Win32 Data Protection API, on macOS it stores the data in the system Keychain, and on Linux it uses libsecret, giving a consistent save()/load() interface regardless of platform while keeping the underlying secret material encrypted at rest.

The library’s PersistedTokenCache wraps msal.SerializableTokenCache with an inter-process file lock (CrossPlatLock, built on portalocker with a plain file-lock fallback) so that multiple instances of the same desktop app, or multiple different apps, can share a single sign-on cache without corrupting it. This makes it the standard companion for any Python desktop or CLI tool that authenticates against Azure Active Directory / the Microsoft identity platform and needs its sign-in state to survive across process restarts.

What You Get

  • FilePersistence for plain-text cache storage, plus build_encrypted_persistence() to auto-select the right encrypted backend for the current OS
  • FilePersistenceWithDataProtection using Windows DPAPI, KeychainPersistence using the macOS Keychain, and LibsecretPersistence using Linux libsecret
  • PersistedTokenCache, a drop-in subclass of msal.SerializableTokenCache that transparently reloads from and flushes back to the chosen persistence on every modify()/search()
  • CrossPlatLock, a cross-process file lock (portalocker-backed with a pure file-lock fallback) that coordinates concurrent access from multiple app instances
  • Typed persistence exceptions (PersistenceNotFound, PersistenceEncryptionError, PersistenceDecryptionError) for uniform error handling across platforms

Common Use Cases

  • Giving a Python desktop app single sign-on (SSO) so users stay signed in to Azure AD across restarts
  • Sharing one encrypted token cache file between several related desktop apps or CLI tools on the same machine
  • Building an Azure CLI-style tool that needs a secure, OS-native place to cache OAuth tokens
  • Falling back to plain-text file persistence in constrained/CI environments where OS encryption backends aren’t available

Under The Hood

Architecture The package layers cleanly around a single abstract interface, BasePersistence in persistence.py, which defines save(), load(), time_last_modified(), and get_location(). Concrete backends (FilePersistence, FilePersistenceWithDataProtection, KeychainPersistence, LibsecretPersistence) implement that interface against OS-specific storage, with the encrypted variants favoring composition over inheritance — KeychainPersistence and LibsecretPersistence each hold an internal FilePersistence purely to track a signal file’s modification time. token_cache.py builds PersistedTokenCache on top of any persistence instance, subclassing msal.SerializableTokenCache and wrapping every mutating call in CrossPlatLock (from cache_lock.py, or filelock.py as a fallback when portalocker isn’t installed) so concurrent processes don’t corrupt the shared cache file. The only coupling point across the whole design is the persistence interface itself, which is what lets build_encrypted_persistence() swap backends per-OS without touching the cache layer.

Tech Stack A pure-Python package targeting Python 3.9+, with msal>=1.29,<2 as its only hard dependency and portalocker as an optional extra for its cross-process file lock. Encryption is delegated entirely to OS-native mechanisms rather than a bundled crypto library: Windows DPAPI via windows.py, macOS Keychain via osx.py (shelling out to native Keychain APIs), and Linux libsecret via libsecret.py. CI runs through both an Azure Pipelines config and a GitHub Actions workflow (python-package.yml), and a Dockerfile/docker_run.sh pair exists for exercising the Linux libsecret path in a container.

Code Quality Tests live under tests/ and cover the cross-platform lock (test_crossplatlock.py, plus a dedicated performance test for the file lock), the persistence backends (test_persistence.py, test_macos_backend.py, test_windows_backend.py, test_agnostic_backend.py), and use helper modules (http_client.py, lock_acquire.py, cache_file_generator.py) to simulate multi-process scenarios. Error handling is explicit and layered: OS-specific exceptions are caught and re-raised as a small unified hierarchy (PersistenceNotFound, PersistenceEncryptionError, PersistenceDecryptionError) so callers don’t need to special-case each platform. A .pylintrc and consistent docstrings throughout point to an actively linted codebase, though the code still carries some Python 2 compatibility shims (try/except ImportError for pathlib2, ABCMeta fallback) alongside modern type comments rather than full type hints.

What Makes It Unique Rather than inventing its own encryption, the library’s contribution is a uniform persistence contract over three completely different native secret stores, paired with a locking scheme specifically designed to interoperate with the equivalent .NET MSAL extensions library sharing the same cache file format. That cross-language, cross-process compatibility — multiple apps in different languages safely reading and writing one on-disk token cache — is the part standard file-encryption libraries don’t offer out of the box.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search