PQC Edge and Identity, Advanced · 2 of 2
Identity Libraries and Post-Quantum: What MSAL Decides, What It Inherits, What the Identity Provider Decides
An app that gets tokens with MSAL touches six pieces of cryptography with three different owners. Here is which post-quantum change is yours, and which you wait for.
Ask a development team whether its sign-in code is ready for post-quantum cryptography and the usual answer is a shrug towards the library: we use the Microsoft Authentication Library (MSAL), so presumably Microsoft will take care of it. That answer is half right, and the wrong half is expensive. One ordinary token request touches several separate pieces of cryptography: the encrypted connection to the token endpoint, the credential the app proves itself with, the protection on the stored tokens, the signature on the token, the check the receiving API performs, and the connection to that API. MSAL implements almost none of them. Some it inherits from the platform it runs on, some belong to the identity provider, and some belong to you. This article draws that responsibility map layer by layer, using public Microsoft documentation as the worked example, so a team can tell the post-quantum changes it can make this quarter from the ones it can only prepare for.
One token, six pieces of cryptography, three owners
MSAL is a family of libraries for .NET, JavaScript, Java, Python, Android and iOS that acquire security tokens from the Microsoft identity platform, the service behind Microsoft Entra ID. A token is a small signed document, usually a JSON Web Token (JWT), that tells an application programming interface (API) who the caller is and what it may do. MSAL's job is the protocol work: it builds the requests defined by OAuth 2.0 and OpenID Connect, the industry standards for delegated access and sign-in, sends them, keeps a token cache and refreshes tokens before they expire. That is valuable work, but it is not cryptography in the sense that matters here.
Follow one token from request to use and six separate pieces of cryptography appear. First, the Transport Layer Security (TLS) connection that carries the request to the token endpoint. Second, the client credential, the secret, certificate or federated assertion with which a server-side app proves its own identity. Third, the protection on the token cache, wherever the tokens are stored between uses. Fourth, the signature the identity provider puts on the token. Fifth, the check an API performs on that signature before trusting the token. Sixth, the TLS connection that carries the token to the API.
Each layer has a different owner, and post-quantum migration moves at the pace of the owner. The platform's TLS stack decides the first; you and the identity provider share the second; you decide the third; the provider decides the fourth; the API's own validation library and its owners decide the fifth; and whoever runs the API's front door decides the sixth. The table maps each one against what the public documentation says today, read on 29 October 2026, and what a team can do now.
| Layer | Decided by | What the docs say today | Your move now |
|---|---|---|---|
| 1. TLS to token endpoint | Platform TLS stack and the provider's endpoint | MSAL uses the platform's HTTP client; .NET defers TLS to the OS | Keep the platform current; do not pin TLS settings in code |
| 2. Client credential | You (type, key) and the provider (accepted algorithms) | Assertion header alg PS256; app certificates RSA only | Retire secrets; short-lived certificates in hardware-backed stores |
| 3. Token cache | You | DPAPI, Keychain, LibSecret, optional Data Protection, MSAL.js AES-GCM | Check where the cache lives and that encryption is on |
| 4. Token signature | Identity provider | Signed with algorithms such as RS256; keys roll with no set schedule | Nothing to configure; follow published announcements |
| 5. Validation in the API | You, through the API's validation library | Fetch keys from the provider's key set, cache by key ID | Make validators tolerate unknown key types and pin algorithms |
| 6. TLS to the API | Whoever runs the API's edge | The edge's own TLS policy | Decide strict or compatible per path |
The connection to the token endpoint is inherited, not implemented
MSAL does not contain a TLS implementation. It hands every HTTP request to the platform's networking stack and takes whatever security that stack negotiates. In MSAL.NET this is explicit: an app that needs control can implement IMsalHttpClientFactory, and MSAL then asks that factory for the HttpClient it uses for each request. The documented reasons for doing so are proxies, connection pooling and user-agent headers, not algorithms. Underneath HttpClient, .NET's guidance is to defer the TLS version to the operating system, which on Windows means Schannel, the Windows TLS provider, and lets an application pick up improvements after the operating system is upgraded.
The same pattern holds elsewhere. MSAL for Python uses a session from the popular requests library by default, passing through options such as certificate verification and proxies; the actual TLS comes from Python's ssl module, which wraps whatever OpenSSL build Python was compiled against. MSAL.js runs inside a browser, so the connection to the token endpoint is the browser's own. In every case, whether the key exchange to the token endpoint can use a hybrid post-quantum group, one that combines a classical elliptic-curve exchange with ML-KEM, the Module-Lattice-Based Key-Encapsulation Mechanism standardised by the United States National Institute of Standards and Technology (NIST), depends on two parties that are not MSAL.
The first party is your platform: it must offer a hybrid group. On Windows that is a Schannel setting; in Python it depends on the OpenSSL version; in a browser it depends on the browser version. The second party is the identity provider's endpoint: it must accept the group, and that is the provider's decision, which this article does not attempt to report. Check it from your own client with your own tooling, record the date, and do not assume it from a setting. The practical rule for code is negative: do not pin TLS versions, suites or groups in application code, because pinned settings stop a platform improvement from reaching your token requests.
What a recorded session would hand a future attacker
Post-quantum key exchange matters because of an attack that starts now and finishes later: an adversary records encrypted traffic today and decrypts it once a large enough quantum computer can break the classical key exchange. For token traffic, the useful question is not whether a recorded session could be decrypted in principle, but what the attacker would find inside it and whether that would still be worth anything years later. The answer depends heavily on how the app proves its identity.
A client secret is a password for an application. It travels in the token request, it is typically valid for months or years, and it can be reused by anyone who learns it. A recorded session carrying a client secret is therefore a long-lived prize. A certificate credential works differently: the app signs a short JWT, called a client assertion, whose documented claims include an expiry time and a unique identifier, and only that signed assertion crosses the wire. Recovering it later yields something that has already expired. A managed identity, which Azure services provide so that code needs no stored credential at all, puts no app-held credential into that request.
Two more items deserve a place on the scale. Refresh tokens, which let an app obtain new access tokens without the user signing in again, live longer than access tokens and are the most valuable thing most token responses contain. Access tokens themselves are short-lived. Rank your apps by what their recorded traffic would expose, and the first post-quantum action on this layer becomes obvious and entirely within your control: move confidential clients off client secrets, onto certificates or managed identity, before spending effort anywhere else.
Client credentials: you hold the key, the provider picks the algorithm
The client credential is the one layer where the work is genuinely shared. You choose the credential type, generate the key, decide where it lives and how often it rotates. The identity provider decides which algorithms it will accept. The public documentation is specific about today's answer. The certificate-credentials page describes the client assertion header with an algorithm value that should be PS256, an RSA signature with the probabilistic signature scheme padding, and a SHA-256 thumbprint of the certificate. The guide to creating a self-signed certificate for an app states that Microsoft Entra ID currently supports only RSA keys, recommends 2048-bit keys, and accepts certificates signed with SHA-256, SHA-384 or SHA-512.
That settles who moves first. A post-quantum certificate credential, for example one using ML-DSA, the Module-Lattice-Based Digital Signature Algorithm, cannot be adopted by an app until the provider accepts it. No amount of client-side effort changes that. What the client side can do is make the eventual switch cheap and the current exposure small, and nearly all of that work is ordinary credential hygiene with a post-quantum justification.
Start with an inventory: for every app registration, record whether it uses a secret, a certificate, a federated credential or a managed identity, and who owns it. Then shrink the classical exposure. Retire secrets first. Keep certificate private keys in a hardware-backed store, so they can be used without being exported. Shorten certificate validity and automate renewal, registering the next certificate before the current one expires so rotation never causes an outage. Where workloads run on Azure, prefer managed identity; where they run elsewhere, prefer federation, which exchanges a token the workload already has for an Entra token without any stored secret. Each of these steps also makes a future algorithm change a routine rotation rather than a project.
- Inventory every app registration's credential type and owner.
- Retire client secrets in favour of certificates, managed identity or federation.
- Keep certificate keys non-exportable in a hardware-backed store.
- Shorten validity and automate renewal with an overlapping next certificate.
- Treat the future algorithm change as one more planned rotation.
The token cache is not a post-quantum problem, and that is good news
Every MSAL app keeps a token cache, and a natural worry is whether that cache needs post-quantum protection too. It does not, for a reason worth understanding. The protections the documentation describes are symmetric or operating-system services. On Windows the desktop cache is protected with the Data Protection API (DPAPI); the cross-platform extension libraries use the macOS Keychain and, on Linux, LibSecret. Web apps are pointed to a distributed cache, with encryption at rest available through ASP.NET Core Data Protection. MSAL.js version 4 encrypts tokens kept in browser local storage, unless the user chooses to stay signed in, with the Advanced Encryption Standard in Galois/Counter Mode (AES-GCM), using a key derived with the HMAC-based key derivation function (HKDF) from a base key held in a session cookie.
Shor's algorithm, the quantum algorithm that threatens public-key cryptography, does not break symmetric encryption, so none of these mechanisms is on the post-quantum migration list. The genuine risks on this layer are about access, not algorithms. The documentation's own sample for a distributed cache shows encryption switched off, with a comment that you can choose whether to encrypt, so check what your deployment actually does. MSAL.js states plainly that its local-storage encryption is meant to reduce how long artefacts persist, not to add security, because anyone who can read the storage can usually reach the key or request tokens directly.
This is good news for planning. A team can tick the cache off its post-quantum list and redirect that effort to the questions that matter for a cache full of refresh tokens: where it lives, who and what can read it, whether encryption at rest is actually enabled in production, and whether a compromised host would expose tokens for many users or audiences at once.
The token's signature belongs to the identity provider
The most visible piece of cryptography in the whole flow, the signature on the token, is the piece a customer controls least. The identity provider holds the private key, chooses the algorithm and decides when keys change. The access-token documentation says tokens are signed with industry-standard asymmetric algorithms such as RS256, an RSA signature over a SHA-256 hash, and that each token's header names the algorithm and a key identifier, the kid. The public keys are published in a JSON Web Key Set (JWKS), a document listing the provider's current signing keys, at an address advertised by the OpenID Connect discovery document.
The signing-key rollover guidance adds the operational fact that matters most: keys roll over periodically and, in an emergency, immediately, and there is no set or guaranteed time between rolls. Applications are expected to fetch new keys automatically, ideally through a standard library. In other words, the provider already changes signing keys on its own schedule, and every well-built API already copes with that. An algorithm change is the same event with one extra twist, which the next section addresses.
What has Microsoft actually published about post-quantum plans here? The Microsoft Security blog of 20 August 2025 describes a company-wide roadmap that aims for early adoption of quantum-safe capabilities by 2029 and completion of the transition across services and products by 2033, and it names Microsoft Entra authentication among the core infrastructure services to be prioritised. It names no token-signing algorithm, no change to MSAL and no date specific to either, and no further public detail was found when this article was written. Treat anything more specific that you hear second-hand as unconfirmed until it appears in official documentation.
Your API's validator is the part that must be ready first
Here is the twist. When a provider eventually publishes a post-quantum signing key, it will appear in the key set before any token is signed with it, because that is how rollover works: new keys are published early so that validators can fetch them. The format for such keys already exists. RFC 9964 defines ML-DSA for the JSON Object Signing and Encryption family, introducing a new key type, AKP, with algorithm names such as ML-DSA-44. An API whose validation library throws an error on an unrecognised key type would then fail on every request, before a single post-quantum token exists. The layer you own is the one that can break first.
Making a validator ready is mostly engineering discipline. Keep the validation library current and centrally updated, so a fix reaches every API. Make sure an unknown key type in the key set is skipped and logged, not fatal. Pin the accepted algorithms per issuer in configuration, rather than trusting whatever algorithm the token's header claims, so adding a new algorithm is a deliberate change. Follow the documented caching guidance for libraries that do not do it for you: cache many distinct keys, ten to a thousand, indexed by kid, with a time-to-live of 24 hours and a refresh every hour and at start-up.
Then prove it offline, without touching any live system. Build a test key set that contains the provider's current style of RSA key alongside the example AKP key published in RFC 9964, feed it to your validator, and check two things: the parser does not crash, and a valid RSA-signed test token still validates. Note who does not need this work: client applications are told to treat access tokens as opaque strings and never validate them, so the readiness effort belongs to the APIs and to any agent tool server that accepts tokens.
ALLOWED_ALGS = {ISSUER: {"RS256"}} # widen deliberately, never from the token header
def load_keys(jwks):
keys = {}
for jwk in jwks["keys"]:
try:
keys[jwk["kid"]] = parse_jwk(jwk)
except UnsupportedKeyType:
log.info("skipping kid=%s kty=%s", jwk.get("kid"), jwk.get("kty"))
return keys
def check_header(issuer, header):
if header.get("alg") not in ALLOWED_ALGS[issuer]:
raise InvalidToken("algorithm not allowed for this issuer")What this means for AI agents and the people who run them
AI agents are heavy token users. An agent typically obtains one token for its model endpoint and another for every tool or downstream API it calls, often through the Azure SDK's credential classes, which the MSAL.NET documentation says use MSAL.NET internally, or through MSAL directly. Every layer of the map therefore applies to an agent many times over, and some layers become sharper. An agent host configured with a client secret in an environment variable is the worst case for recorded traffic, because every token request it makes carries a long-lived, reusable credential. Managed identity or federation removes that exposure entirely.
Agents also concentrate cache risk. One agent process may hold tokens for many audiences at once, so where its cache lives and who can read it matters more than for a single-purpose app, while the encryption algorithm protecting that cache remains a non-issue. And every tool an agent calls is an API that validates tokens, which makes tool servers, including servers that speak the Model Context Protocol (MCP), the open protocol for connecting agents to tools, part of the validator readiness work. A tool server that crashes on an unfamiliar key type takes the agent down with it.
For the people responsible for these systems, the map turns into a short list of decisions. Decide which layers are yours and act on them now: no secrets on agent hosts, short-lived certificates or managed identity, cache locations reviewed, validators tested against an unknown key type. Decide which layers you are waiting for and say so plainly in your plans: the provider's token-signing algorithm and accepted credential algorithms. And for the connection from agents to their tools, apply the edge's own strict-or-compatible decision, because the TLS policy in front of each API is a separate choice that no identity library makes for you.
Key takeaways
- An MSAL app touches six pieces of cryptography; MSAL implements none of the post-quantum-relevant ones and inherits its TLS from the platform.
- Hybrid key exchange to the token endpoint needs both your platform's TLS stack and the provider's endpoint; never pin TLS settings in code.
- What a recorded session yields depends on the credential: retire client secrets first, in favour of certificates, managed identity or federation.
- Token cache protection is symmetric or operating-system managed, so it is not a post-quantum item; check access and whether encryption is on.
- The provider owns the token signature, but your API's validator can break first: skip unknown key types, pin algorithms per issuer, and test with the RFC 9964 example key.
Glossary
- MSAL
- The Microsoft Authentication Library, a family of libraries that acquire, cache and refresh tokens from the Microsoft identity platform.
- Client assertion
- A short signed JWT with which a server-side app proves possession of its certificate when requesting a token.
- Client secret
- A password-like value registered for an application, reusable by anyone who obtains it until it expires.
- JSON Web Key Set (JWKS)
- A published document listing an identity provider's current public signing keys, each with a key identifier.
- Key identifier (kid)
- The value in a token header that tells a validator which published key to use.
- Signing key rollover
- The provider's replacement of its token-signing keys, periodically or in an emergency, which validators must follow automatically.
- AKP key type
- The JSON Web Key type defined in RFC 9964 for algorithm key pairs such as ML-DSA keys.
- Managed identity
- An identity that a cloud platform gives a workload so it can obtain tokens without storing any credential in code or configuration.
Further reading
Sources
This article is based only on public, authoritative Microsoft documentation.
- Overview of the Microsoft Authentication Library (MSAL) — Microsoft Learn
- Providing your own HttpClient (MSAL.NET) — Microsoft Learn
- TLS/SSL best practices (.NET) — Microsoft Learn
- ConfidentialClientApplication (MSAL for Python) — Microsoft Learn
- Managed identity with MSAL.NET — Microsoft Learn
- Public and confidential client apps (MSAL) — Microsoft Learn
- Microsoft identity platform certificate credentials — Microsoft Learn
- Create a self-signed public certificate to authenticate your application — Microsoft Learn
- Token cache serialization (MSAL.NET) — Microsoft Learn
- Caching in MSAL.js — Microsoft Learn
- Access tokens in the Microsoft identity platform — Microsoft Learn
- Signing key rollover in the Microsoft identity platform — Microsoft Learn
- OpenID Connect on the Microsoft identity platform — Microsoft Learn
- RFC 9964: ML-DSA for JSON Object Signing and Encryption (JOSE) and CBOR Object Signing and Encryption (COSE)
- Quantum-safe security: Progress towards next-generation cryptography — Microsoft Security blog (2025-08-20)