Every ASP.NET Core application depends on secrets. Database connection strings, API keys, JWT signing keys, OAuth client secrets, SMTP credentials, and cloud service tokens are all essential for application functionality. Unfortunately, these secrets are also among the most common causes of security incidents when they are accidentally committed to source control or exposed through insecure configuration.
Hardcoding secrets in configuration files or source code may seem convenient during development, but it creates significant security risks in production. ASP.NET Core provides a flexible configuration system that enables developers to manage secrets securely across development, testing, and production environments.
In this article, you'll learn how to manage secrets securely using User Secrets during development, Azure Key Vault in production, and configuration best practices that help protect sensitive information throughout the application lifecycle.
Why Secrets Management Matters
The Risks of Hardcoding Secrets
Consider the following configuration:
{
"ConnectionStrings": {
"DefaultConnection": "Server=sql01;Database=SalesDb;User Id=admin;Password=P@ssw0rd!"
}
}
Although this works, storing credentials directly in configuration files introduces several risks:
Accidental commits to Git repositories
Exposure through backups
Shared development credentials
Difficult secret rotation
Increased security audit findings
Sensitive information should never be stored directly in application source code or tracked configuration files.
Understanding ASP.NET Core Configuration
ASP.NET Core loads configuration from multiple providers.
Typical configuration sources include:
appsettings.json
appsettings.{Environment}.json
Environment variables
User Secrets
Azure Key Vault
Command-line arguments
Configuration providers are layered, allowing secure values to override default settings without modifying application code.
Using User Secrets During Development
User Secrets provide a secure location for development-only configuration.
Initialize User Secrets:
dotnet user-secrets init
Store a connection string:
dotnet user-secrets set "ConnectionStrings:DefaultConnection" "Server=localhost;Database=SalesDb;Trusted_Connection=True;"
Read the value normally:
var connectionString =
builder.Configuration
.GetConnectionString("DefaultConnection");
Why Use User Secrets?
User Secrets store sensitive values outside the project directory.
This prevents accidental commits while allowing developers to access configuration through the standard ASP.NET Core configuration system without changing application code.
Using Environment Variables
Production environments often inject secrets through environment variables.
Example:
ConnectionStrings__DefaultConnection
ASP.NET Core automatically maps double underscores (__) to nested configuration keys.
Why Environment Variables?
Environment variables separate configuration from application binaries.
They work well with:
Docker
Kubernetes
Azure App Service
GitHub Actions
Azure DevOps
CI/CD pipelines
This approach simplifies deployment while avoiding sensitive configuration files.
Integrating Azure Key Vault
Azure Key Vault centralizes secret management for production applications.
Register Key Vault during startup.
builder.Configuration.AddAzureKeyVault(
new Uri(builder.Configuration["KeyVault:VaultUri"]!),
new DefaultAzureCredential());
Why Azure Key Vault?
Azure Key Vault provides:
Secure secret storage
Automatic secret rotation
Centralized management
Access policies
Audit logging
Hardware-backed protection options
Instead of distributing secrets across multiple servers, applications retrieve them securely at runtime.
Accessing Secrets
Once configuration providers are registered, consuming secrets remains identical regardless of their source.
var apiKey =
builder.Configuration["PaymentGateway:ApiKey"];
Why Is This Important?
Business code does not need to know where a secret originates.
Whether the value comes from User Secrets, an environment variable, or Azure Key Vault, the application accesses it through the same configuration API.
This keeps application code simple while allowing deployment environments to determine how secrets are supplied.
End-to-End Implementation
Consider a cloud-hosted order management system.
Architecture:
Developer
│
User Secrets
│
▼
ASP.NET Core Application
│
Configuration System
│
▼
Azure Key Vault
│
▼
SQL Database
Payment Gateway
Storage Account
Workflow:
Developers use User Secrets during local development.
The application reads configuration through the standard configuration system.
In production, secrets are retrieved from Azure Key Vault.
Managed identities authenticate the application without storing credentials.
Business services consume secrets without knowing their underlying source.
This approach provides a consistent programming model while significantly improving security across environments.
Secret Rotation
Production secrets should never remain unchanged indefinitely.
A typical rotation process includes:
Join the conversation! Your thoughts help the community grow.