microsoft/migrating-azure-keyvault
> Migrates from the deprecated Microsoft.Azure.KeyVault SDK to the modern Azure.Security.KeyVault client libraries (Secrets, Keys, Certificates). Use ONLY when Microsoft.Azure.KeyVault has been flagged as obsolete or deprecated and must be replaced — not for version-bump scenarios where Microsoft.Azure.KeyVault is still supported.
npx skills add https://github.com/microsoft/upgrade-agent-plugins --skill migrating-azure-keyvault
Migrate from the deprecated Microsoft.Azure.KeyVault SDK to the modern Azure.Security.KeyVault.* libraries. The new SDK splits the single KeyVaultClient into resource-specific clients (SecretClient, KeyClient, CertificateClient) and uses Azure.Identity for authentication instead of custom token callbacks. Both synchronous and asynchronous APIs are available.
<PackageReference Include="Microsoft.Azure.KeyVault" Version="{any}" />
<PackageReference Include="Microsoft.Azure.KeyVault.Models" Version="{any}" />
<!-- Legacy authentication helper -->
<PackageReference Include="Microsoft.Azure.Services.AppAuthentication" Version="{any}" />
<!-- Add only the packages for the resource types the project uses -->
<PackageReference Include="Azure.Security.KeyVault.Secrets" Version="{latest-stable}" />
<PackageReference Include="Azure.Security.KeyVault.Keys" Version="{latest-stable}" />
<PackageReference Include="Azure.Security.KeyVault.Certificates" Version="{latest-stable}" />
<!-- Unified authentication -->
<PackageReference Include="Azure.Identity" Version="{latest-stable}" />
Use tools or NuGet to find the latest stable versions. Only add the Azure.Security.KeyVault.* packages that the project actually needs.
Migration Progress:
- [ ] Step 1: Detect Key Vault SDK usage
- [ ] Step 2: Update package references
- [ ] Step 3: Replace authentication
- [ ] Step 4: Replace client initialization
- [ ] Step 5: Convert secret operations
- [ ] Step 6: Convert key and certificate operations
- [ ] Step 7: Migrate error handling
- [ ] Step 8: Build and verify
Scan the project for:
using Microsoft.Azure.KeyVault; and using Microsoft.Azure.KeyVault.Models;KeyVaultClient, SecretBundle, KeyBundle, CertificateBundleGetSecretAsync, SetSecretAsync, GetKeyAsync, GetCertificateAsyncKeyVaultClient.AuthenticationCallback, AzureServiceTokenProviderRemove Microsoft.Azure.KeyVault, Microsoft.Azure.KeyVault.Models, and Microsoft.Azure.Services.AppAuthentication from the project file. Add the appropriate Azure.Security.KeyVault.* and Azure.Identity packages.
// Old — custom token callback
var azureServiceTokenProvider = new AzureServiceTokenProvider();
var client = new KeyVaultClient(
new KeyVaultClient.AuthenticationCallback(
azureServiceTokenProvider.KeyVaultTokenCallback));
// New — Azure.Identity (works with managed identity, Azure CLI, Visual Studio, etc.)
var credential = new DefaultAzureCredential();
DefaultAzureCredential chains multiple authentication methods automatically. For production scenarios that need a specific identity, use ManagedIdentityCredential, ClientSecretCredential, or another concrete type from Azure.Identity.
// Old — single client for all resource types
var client = new KeyVaultClient(authCallback);
// New — one client per resource type
var vaultUri = new Uri("https://my-vault.vault.azure.net/");
var secretClient = new SecretClient(vaultUri, credential);
var keyClient = new KeyClient(vaultUri, credential);
var certificateClient = new CertificateClient(vaultUri, credential);
// Old
SecretBundle secret = await client.GetSecretAsync(vaultBaseUrl, "my-secret");
string value = secret.Value;
await client.SetSecretAsync(vaultBaseUrl, "my-secret", "new-value");
// New
KeyVaultSecret secret = await secretClient.GetSecretAsync("my-secret");
string value = secret.Value;
await secretClient.SetSecretAsync("my-secret", "new-value");
The new client takes the vault URI at construction — pass only the secret name to each operation.
// Old — Keys
KeyBundle key = await client.GetKeyAsync(vaultBaseUrl, "my-key");
// New — Keys
KeyVaultKey key = await keyClient.GetKeyAsync("my-key");
// Old — Certificates
CertificateBundle cert = await client.GetCertificateAsync(vaultBaseUrl, "my-cert");
// New — Certificates
KeyVaultCertificateWithPolicy cert = await certificateClient.GetCertificateAsync("my-cert");
// Old
try { /* operation */ }
catch (KeyVaultErrorException ex) when (ex.Response.StatusCode == HttpStatusCode.NotFound)
{ /* handle */ }
// New
try { /* operation */ }
catch (RequestFailedException ex) when (ex.Status == 404)
{ /* handle */ }
RequestFailedException is the unified exception type across all Azure.* client libraries.
dotnet build
| Old SDK (Microsoft.Azure.KeyVault) | New SDK (Azure.Security.KeyVault.*) | Notes |
|-------------------------------------|-------------------------------------|-------|
| KeyVaultClient | SecretClient / KeyClient / CertificateClient | One client per resource type |
| AuthenticationCallback | DefaultAzureCredential (Azure.Identity) | No manual token management |
| AzureServiceTokenProvider | DefaultAzureCredential | Automatic credential chaining |
| SecretBundle | KeyVaultSecret | Simpler model |
| KeyBundle | KeyVaultKey | Simpler model |
| CertificateBundle | KeyVaultCertificateWithPolicy | Includes policy in response |
| GetSecretAsync(vaultUrl, name) | GetSecretAsync(name) | Vault URL set at client construction |
| SetSecretAsync(vaultUrl, name, value) | SetSecretAsync(name, value) | Vault URL set at client construction |
| KeyVaultErrorException | RequestFailedException | Unified Azure SDK exception |
| Async-only APIs | Sync and async APIs | Both GetSecret and GetSecretAsync available |
DefaultAzureCredential tries multiple credential sources in order. If it fails, check that at least one source is configured: Azure CLI login (az login), Visual Studio authentication, environment variables (AZURE_CLIENT_ID, AZURE_TENANT_ID, AZURE_CLIENT_SECRET), or managed identity. Enable logging with AzureEventSourceListener to see which credential is attempted.
The new clients take the vault URI in the constructor. If the old code used different vault URLs for different operations, create separate client instances for each vault.
These types are replaced by KeyVaultSecret and KeyVaultKey in the new SDK. Update all variable declarations and return types. Properties like SecretBundle.Value map directly to KeyVaultSecret.Value.
The new Key Vault libraries depend on Azure.Core. If other Azure SDK packages are present, ensure all packages use compatible Azure.Core versions to avoid binding redirect issues.
Take microsoft/migrating-azure-keyvault from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.