Managing sensitive information such as database connection strings, API keys, passwords, and application credentials is an important part of developing secure ASP.NET Core applications. Storing these values directly in source code or configuration files can expose them to unauthorized users and create security risks.
Azure Key Vault provides a secure way to store and manage secrets in Microsoft Azure. ASP.NET Core applications can access these secrets at runtime using the Azure Key Vault SDK and Microsoft Entra ID authentication, allowing developers to separate sensitive configuration from application code.
In this article, you will learn how to retrieve secrets from Azure Key Vault in an ASP.NET Core application using C#. We will explore the required NuGet packages, configure authentication with DefaultAzureCredential, register the SecretClient using dependency injection, and retrieve a secret from an ASP.NET Core Web API controller.
By the end of this guide, you will understand how to integrate Azure Key Vault into an ASP.NET Core application and follow security best practices when working with sensitive configuration data.
Getting Started
If you are new to Azure Key Vault secret management in C#, I recommend reading my previous article, Retrieve Azure Key Vault Secret in C# and .NET Core: A Complete Guide. It introduces the fundamentals of retrieving secrets using the Azure Key Vault SDK. In this article, we will build on that knowledge and explore how to integrate Azure Key Vault into an ASP.NET Core application using dependency injection and secure authentication.
PrerequisitesBefore retrieving secrets from Azure Key Vault in an ASP.NET Core application, ensure that you have the following prerequisites:
- Azure subscription: An active Microsoft Azure subscription.
- Azure Key Vault: An existing Key Vault containing at least one secret, such as
DatabaseConnectionStringorApiKey. - ASP.NET Core Web API project: A Web API project created using a supported version of .NET.
- Required permissions: Appropriate Microsoft Entra ID permissions to read secrets from the Key Vault. For example, the
Key Vault Secrets Userrole can provide secret-reading access when the vault uses the Azure RBAC permission model. - .NET SDK: The .NET SDK compatible with your ASP.NET Core project.
- Authentication setup: For local development, you can sign in through Azure CLI or Visual Studio. In Azure hosting environments, a managed identity is generally recommended.
Create a secret in Azure Key Vault
If you haven't created a secret yet, follow these steps:- Sign in to the Azure portal.
- Open your Key Vault.
- Select Objects → Secrets.
- Select Generate/Import.
- Enter a secret name, such as
AzureSecrectString. - Enter a sample value, such as
Hello from Azure Key Vault. - Select Create.
We will use AzureSecrectString throughout this example to demonstrate retrieving a secret from the Web API. You should also know your Key Vault URL, which follows this format:
</> Plain Text
https://<your-key-vault-name>.vault.azure.net/
Install the Required NuGet Packages
To retrieve secrets from Azure Key Vault in an ASP.NET Core application, you need two NuGet packages: Azure.Security.KeyVault.Secrets and Azure.Identity. These packages provide the client APIs for accessing Key Vault secrets and authenticating with Microsoft Entra ID.
</> powershell
Install-Package Azure.Security.KeyVault.Secrets
Install-Package Azure.Identity
Azure.Security.KeyVault.Secrets: ProvidesSecretClientand related classes for retrieving, creating, and managing Azure Key Vault secrets.Azure.Identity: ProvidesDefaultAzureCredentialand other authentication mechanisms for obtaining Microsoft Entra ID access tokens.
After installing the packages, restore dependencies and build your project to ensure that the required libraries are available.
Configure Azure Key Vault Authentication
Azure Key Vault requires applications to authenticate before accessing secrets. In an ASP.NET Core application, you can use the DefaultAzureCredential class from the Azure.Identity package to obtain credentials without hardcoding access tokens or passwords in your source code.
DefaultAzureCredential can use different authentication mechanisms depending on the environment. For example, it can use your signed-in developer account during local development and a managed identity when the application runs in a supported Azure hosting environment.
- Sign in to Azure during local development
If you use Azure CLI, open a terminal and run:
</> Bash
az login
Complete the sign-in process using an Azure account that has permission to read secrets from your Key Vault.You can also authenticate through supported Visual Studio credentials. DefaultAzureCredential will discover an available credential according to its configured credential chain.
- Grant permission to read secrets
Your authenticated identity must have permission to retrieve secret values.
If your Key Vault uses the Azure RBAC permission model, you can assign the Key Vault Secrets User role to the identity running your application. This role provides access to read secret contents, subject to the assigned scope.
To configure this in the Azure portal:- Open your Key Vault in the Azure portal.
- Select Access control (IAM).
- Select Add → Add role assignment.
- Select the Key Vault Secrets User role.
- Select the user or managed identity that your application will use.
- Review the role assignment and complete the process.
If your vault uses the legacy access-policy model instead, configure the appropriate secret
Getpermission under the vault's access policies.Important: Assign permissions to the identity actually used by your application. The account you use in Visual Studio, the Azure CLI identity, and the production managed identity may be different.
- Configure the Key Vault URL
Open
appsettings.jsonin your ASP.NET Core project and add the following configuration:</> JSON
Replace{ "KeyVault": { "VaultUri": "https://your-key-vault-name.vault.azure.net/" } }your-key-vault-namewith your actual Key Vault name.The VaultUrisetting identifies the Key Vault endpoint. It is not a secret, so it can be stored in application configuration. Do not store passwords, client secrets, or other sensitive values directly in this file.In the next section, we will use this configuration to register
SecretClientwith ASP.NET Core dependency injection.
Summary
Now, let's create a complete ASP.NET Core Web API example that retrieves a secret from Azure Key Vault using C#.
In this example, we will retrieve the AzureSecrectString secret created earlier. We will use dependency injection to register SecretClient and a service class to keep the Key Vault logic separate from the API controller.
Program.cs: Registers the Key Vault client and configures the application.appsettings.json: Stores the Azure Key Vault endpoint.Services/KeyVaultService.cs: Contains the logic for retrieving secrets from Azure Key Vault.Controllers/SecretsController.cs: Defines API endpoints that allow clients to retrieve secrets through the ASP.NET Core Web API.
Register SecretClient in Program.cs
</> C#
using Azure.Identity;
using Azure.Security.KeyVault.Secrets;
using AzureKeyVaultApi.Services;
var builder = WebApplication.CreateBuilder(args);
// Add controller support.
builder.Services.AddControllers();
// Read the Key Vault URL from configuration.
string vaultUri = builder.Configuration["KeyVault:VaultUri"]
?? throw new InvalidOperationException(
"Key Vault URI is not configured.");
// Register SecretClient with dependency injection.
builder.Services.AddSingleton(
new SecretClient(
new Uri(vaultUri),
new DefaultAzureCredential()));
// Register the Key Vault service.
builder.Services.AddScoped<IKeyVaultService, KeyVaultService>();
var app = builder.Build();
app.MapControllers();
app.Run();
The SecretClient is registered as a singleton because the Azure SDK client is designed to be reused. DefaultAzureCredential handles authentication, while the IKeyVaultService registration allows the application to inject the secret-retrieval service wherever it is needed.
Create a folder named Services and add a file named IKeyVaultService.cs. This class will communicate with Azure Key Vault and retrieve the requested secret.
</> C#
using Azure.Security.KeyVault.Secrets;
namespace AzureKeyVaultApi.Services
{
public interface IKeyVaultService
{
Task<string> GetSecretAsync(string secretName);
}
public class KeyVaultService : IKeyVaultService
{
private readonly SecretClient _secretClient;
public KeyVaultService(SecretClient secretClient)
{
_secretClient = secretClient;
}
public async Task<string> GetSecretAsync(
string secretName)
{
KeyVaultSecret secret =
await _secretClient.GetSecretAsync(secretName);
return secret.Value;
}
}
}
Explanation of the code
The IKeyVaultService interface defines the GetSecretAsync() method, which accepts a secret name and returns its value asynchronously.
The KeyVaultService class implements this interface and receives a SecretClient instance through constructor injection. This avoids creating a new Key Vault client every time a secret needs to be retrieved.
Inside the GetSecretAsync() method, _secretClient.GetSecretAsync(secretName) sends a request to Azure Key Vault to retrieve the specified secret. The returned KeyVaultSecret object contains the secret's metadata and value. The method returns secret.Value to its caller.
The Azure SDK provides GetSecretAsync() specifically for retrieving secrets asynchronously.
Create a Controllers folder if your project does not already have one. Add a controller named SecretsController.cs.
</> C#
using AzureKeyVaultApi.Services;
using Microsoft.AspNetCore.Mvc;
namespace AzureKeyVaultApi.Controllers
{
[ApiController]
[Route("api/[controller]")]
public class SecretsController : ControllerBase
{
private readonly IKeyVaultService _keyVaultService;
public SecretsController(
IKeyVaultService keyVaultService)
{
_keyVaultService = keyVaultService;
}
[HttpGet("{secretName}")]
public async Task<IActionResult> GetSecret(
string secretName)
{
try
{
string secretValue =
await _keyVaultService.GetSecretAsync(
secretName);
// Demonstration only: do not expose
// real secret values through an API.
return Ok(new
{
Name = secretName,
Value = secretValue
});
}
catch (Azure.RequestFailedException ex)
when (ex.Status == 404)
{
return NotFound(new
{
Message = "The requested secret was not found."
});
}
}
}
}
Explanation of the code
The SecretsController handles incoming HTTP requests and uses constructor injection to receive an instance of IKeyVaultService.
The GetSecret() action accepts a secret name through the route and calls the service's GetSecretAsync() method. If the secret exists and the caller has permission to read it, the controller receives its value and returns an HTTP 200 response.
If Azure Key Vault returns a 404 response because the secret does not exist, the controller returns HTTP 404.
The example deliberately demonstrates the secret value in the response to make local testing straightforward. Do not expose actual passwords, connection strings, API keys, or other secrets through a public API. In production, use retrieved secrets internally—for example, when configuring a database connection or calling another service.
Common errors and troubleshooting
-
Error:
401 Unauthorized- Possible Cause: Authentication failed, or a valid access token could not be obtained.
- Solution: Check your Azure sign-in and credential configuration.
-
Error:
403 Forbidden- Possible Cause: The authenticated identity lacks permission to read the secret.
- Solution: Verify the vault's access model and assign the appropriate role or access policy.
-
Error:
404 Not Found- Possible Cause: The secret name or Key Vault endpoint is incorrect, or the requested secret is unavailable.
- Solution: Check the secret name and Key Vault URL.
-
Error:
CredentialUnavailableException- Possible Cause: No usable credential was found in the configured credential chain.
- Solution: Sign in through Azure CLI or Visual Studio, or configure the appropriate production identity.
Security best practices
- Use managed identity in Azure: Avoid storing service principal credentials in application code.
- Apply least-privilege access: Grant only the secret permissions the application needs.
- Keep secrets out of source control: Store sensitive configuration in Azure Key Vault rather than committing it to
appsettings.json. - Avoid exposing secret values: Do not return sensitive data in API responses or write it to application logs.
- Handle errors safely: Return appropriate HTTP status codes without exposing internal exception details to clients.
- Plan for secret rotation: Ensure applications can accommodate changes to passwords, keys, and other credentials.
Microsoft recommends managed identities to authenticate applications to Azure services without requiring developers to manage credentials directly.
Summary
In this article, we demonstrated how to retrieve Azure Key Vault secrets in an ASP.NET Core Web API using C#. We installed the required NuGet packages, configured DefaultAzureCredential, registered SecretClient with dependency injection, and implemented a service and controller to retrieve a secret asynchronously.
This approach provides a reusable way to access secrets from application services while keeping secret-management logic separate from API controllers.
For applications that use many secrets as configuration settings, you can also explore the Azure Key Vault configuration provider, which integrates Key Vault with ASP.NET Core's configuration system. Choose the approach that best fits your application's requirements.
Thanks