Secure Plugin Development in Dataverse: Using Managed Identity with Azure Key Vault (No Secrets!)

Managing secrets and API keys securely in cloud-based enterprise apps is critical — especially in Dynamics 365 and Power Platform projects where plugins often need to call external APIs. In this post, I’ll walk you through how I implemented Managed Identity with Federated Credentials for a Dataverse Plugin to securely retrieve secrets from Azure Key Vault, removing the need for storing API keys in configuration entities or environment variables.
This setup was essential for my use case — validating phone numbers and email addresses using a third-party external service — but the approach can apply to any plugin needing secure secret access.
Where Can You Store Secrets? (And Why Most Options Are Insecure)
One of the most important decisions when building secure Dynamics 365 and Dataverse plugins is: Where do you store your secrets?
This simple but powerful table shows what many of us have been doing — and why we need a better way:
Location | Description | Security |
Environment Variable (string) | Easy to configure but not encrypted | ❌ Insecure |
Plugin Secure Configuration | Accessible via code, still vulnerable | ❌ Insecure |
Custom config entity | Store encrypted values in a table, but still manually handled | ❌ Insecure |
Hardcoded in code | The worst option – secrets in source control | ❌ Insecure |
Environment Variable (Key Vault) | Promising but not usable in plugins (yet) | 🚫 Not Applicable |
💥 Insight: Most of us have been forced to adopt insecure workarounds because Dataverse plugins historically lacked support for secure secret retrieval.
What Changed?
With the GA release of Managed Identity support for Dataverse plugins in March 2025, we now have a secure, modern approach.
🔐 Why Use Managed Identity with Plugins?
Before diving into the technicals, let's explore why you'd use this setup:
No secrets in the plugin code
No environment variables holding secrets
No need for client secrets or certificates
Secrets are retrieved securely from Azure Key Vault, using Azure AD tokens via a federated App Registration
🛠️ Step-by-Step Implementation
1. Create an Azure App Registration with Federated Credentials
Use the App Registration as your identity provider instead of a traditional Managed Identity. This is crucial if you're deploying your plugin into a Power Platform environment that supports Federated Credentials.
In your app registration:
Go to Certificates & secrets → Federated credentials
Set Issuer to your Dataverse STS:
https://[environment ID prefix].[environment ID suffix].environment.api.powerplatform.com/sts
Environment ID prefix - The environment ID, except for the last two characters.
Environment ID suffix - The last two characters of the environment ID.
Example: https://02e1c0123456789f46a.09.environment.api.powerplatform.com/sts
Use a subject in this format: component:pluginassembly,thumbprint:YOUR_CERT_THUMBPRINT},environment:{YOUR_ENV_ID}
Set Audience to: api://azureadtokenexchange
2. Create and Sign Your Plugin with a Certificate
Your plugin assembly must be signed with a valid certificate whose thumbprint is referenced in the federated credential.
Here’s a PowerShell snippet to create and export the certificate:
$cert = New-SelfSignedCertificate ` -Subject "CN=PluginCert" ` -CertStoreLocation "Cert:\\CurrentUser\\My" ` -Type CodeSigningCert ` -KeyExportPolicy Exportable ` -KeySpec Signature ` -KeyLength 2048 ` -HashAlgorithm SHA256 $pwd = ConvertTo-SecureString -String "YourPassword" -Force -AsPlainText Export-PfxCertificate -Cert "Cert:\\CurrentUser\\My\$($cert.Thumbprint)" -FilePath "C:\\Temp\\PluginCert.pfx" -Password $pwd
Get your thumbprint using powershell:
Export to PFX
$pwd = ConvertTo-SecureString -String "Clarion" -Force -AsPlainText
Export-PfxCertificate -Cert "Cert:\CurrentUser\My\$($cert.Thumbprint)" -FilePath "C:\Temp\LoqatePluginCert.pfx" -Password $pwd
Then sign the DLL: signtool sign /fd SHA256 /f "C:\Temp\PluginCert.pfx" /p YourPassword "Path\To\Plugin.dll"
Example: signtool sign /fd SHA256 /f "C:\Temp\LoqatePluginCert.pfx" /p yourpass "C:\Users\KJaravaza\source\repos\EmailValidation\bin\Debug\EmailValidation.dll"
3. Register and Deploy the Plugin
Deploy the signed plugin assembly into Dataverse using standard methods (Plugin Registration Tool, Power Platform CLI, or DevOps pipelines).
Then link the plugin to your federated identity using a PATCH request:
PATCH /api/data/v9.2/pluginassemblies({pluginAssemblyId})
{
"managedidentityid@odata.bind": "/managedidentities({managedIdentityId})"
}
🔐 Set Up Azure Key Vault
Create your Key Vault and store the API secret (e.g., Loqate API key) under a name like LoqateAPIKey
.
Assign Roles
Your App Registration needs:
Key Vault Secrets User
Key Vault Reader (sometimes needed for specific scenarios)
Use the Azure Portal or CLI to assign these roles.
Key Vault Access Policies (Alternative to RBAC)
In some setups — especially if Access Policies are enabled instead of RBAC — you'll also need to add your App Registration explicitly to the access policies list in Key Vault.
Steps (in the Azure Portal)
Go to your Key Vault
Select Access policies
Click + Add Access Policy
Grant Get and List permissions under Secret Permissions
Under Principal, select your App Registration
Save the changes
📝 Microsoft is shifting towards RBAC-only access for Key Vault, but some environments still require Access Policies. Check which model your vault is using before proceeding.
Sample Code Snippet
Here’s a simplified plugin method to securely access secrets from Key Vault:
var managedIdentityService = (IManagedIdentityService)serviceProvider.GetService(typeof(IManagedIdentityService));
var token = managedIdentityService.AcquireToken(new[] { "https://vault.azure.net/.default" });
using (var httpClient = new HttpClient())
{
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
var response = await httpClient.GetStringAsync("https://your-kv.vault.azure.net/secrets/APIKey?api-version=7.3");
dynamic result = JsonConvert.DeserializeObject(response);
string apiKey = result?.value;
}
Final Thoughts & Recommendations
Now that I’ve successfully implemented Managed Identity in a real-world plugin, here are a few things I learned (and wish I knew sooner):
Federated credentials are the way forward for secure, scalable plugin deployments.
Federated identity setup is strict — your issuer, subject, and audience must match exactly.
Trace logs help — but be careful not to expose secrets. Strip out API keys from traces.
Access Policy vs RBAC — understand what your Key Vault is configured to use. your plugin with a certificate and use its thumbprint in federated identity setup.
📚 Resources
Subscribe to my newsletter
Read articles from Kefasi Jaravaza directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
