I’m trying to make TLS calls using HttpClient in an Azure App Service (Windows) with a certificate that is dynamically loaded at runtime (e.g., from blob storage or Key Vault as a byte array).
A third-party service we must communicate with requires that we authenticate using a client certificate.
Current production setup
App Service (Windows), switched from 32-bit to 64-bit
.NET 9
Premium v3 P0V3 (one of the many set-ups I tried)
WEBSITE_LOAD_CERTIFICATES = 1
WEBSITE_LOAD_USER_PROFILE = 1
I’ve tried all relevant combinations of X509KeyStorageFlags, but none work in App Service:
MachineKeySet throws "The private key could not be loaded" — maybe because of App Service sandbox restrictions. What’s strange is that this used to work for months, and then suddenly started failing across multiple App Services — with identical code and certificates. Nothing changed on our end. Our certificates are valid and correctly formatted. This makes the behavior feel unstable and opaque, which is extremely concerning in a production context.
UserKeySet results in "The system cannot find the file specified" — likely because there’s no user profile loaded in the environment, even with a managed identity.
EphemeralKeySet works during loading, but fails later with "Authentication failed because the platform does not support ephemeral keys" when calling HttpClient.GetAsync. Of course, because it's a Windows machine.
Using a certificate from Key Vault still leaves me with the same problem — the certificate ends up in memory and needs to be converted to X509Certificate2, which runs into the same sandbox limitations.
Uploading the certificate manually through App Service and using the WEBSITE_LOAD_CERTIFICATES setting does work, because the platform handles storage and injection into the certificate store. But that’s not an option for dynamic scenarios, such as user-provided certificates.
One of my many attempts in code:
var limits = new Pkcs12LoaderLimits
{
PreserveStorageProvider = true,
};
var certificate = X509CertificateLoader.LoadPkcs12(_certificateBytes, _password,
keyStorageFlags: X509KeyStorageFlags.MachineKeySet, loaderLimits: limits);
var handler = new HttpClientHandler
{
ClientCertificateOptions = ClientCertificateOption.Manual,
UseDefaultCredentials = false
};
handler.ClientCertificates.Add(certificate);
using var httpClient = new HttpClient(handler) { BaseAddress = new Uri(_basePath) };
var response = await httpClient.GetAsync(requestUri);
Expected behavior
I should be able to:
Load a certificate at runtime (from blob, Key Vault, etc.)
Use it with HttpClient for mutual TLS authentication → without needing to pre-upload the cert through the portal via WEBSITE_LOAD_CERTIFICATES.
This should be possible in a stable and predictable way — not something that breaks seemingly at random. I need a solution I can rely on in production, not one that works one day and inexplicably fails the next.
The issue concerns a single API call that needs to be made from 3 different App Services. Each of our customers has their own unique certificate that must be loaded dynamically at runtime. This one call literally represents less than 1% of what our entire platform does and can achieve — it’s a tiny detail in the bigger picture. It’s therefore absurd that we would have to move away from App Services altogether just because of this.