Every ASP.NET Core application depends on secrets such as database connection strings, API keys, JWT signing keys, SMTP credentials, and cloud service tokens. If these secrets are stored in source code or committed to a Git repository, they become a serious security risk that can lead to data breaches and unauthorized access.
ASP.NET Core provides a flexible configuration system that supports multiple secret providers, including User Secrets for local development, Environment Variables for deployment, and Azure Key Vault for production environments. Choosing the appropriate secret storage mechanism is essential for building secure, maintainable applications.
Rather than hardcoding sensitive values, this article explains how to manage secrets securely throughout the application lifecycle.
Note: Secrets should never be committed to source control. Assume that any secret stored in a Git repository is eventually compromised.
Why Secrets Management Matters
Poor secret management can lead to:
Database credential exposure
Unauthorized API access
Cloud account compromise
Service outages
Compliance violations
Costly security incidents
Protecting secrets is one of the most fundamental application security practices.
Common Application Secrets
Production applications typically store:
Database connection strings
API keys
JWT signing keys
SMTP credentials
Storage account keys
OAuth client secrets
Third-party service tokens
Encryption keys
Each should be stored outside the application codebase.
Secret Storage Options
| Storage Method | Development | Production | Recommended |
|---|---|---|---|
| appsettings.json | Limited | ❌ | No |
| User Secrets | ✅ | ❌ | Development Only |
| Environment Variables | ✅ | ✅ | Yes |
| Azure Key Vault | ❌ | ✅ | Best for Azure |
| HashiCorp Vault | ❌ | ✅ | Enterprise |
The best storage option depends on the deployment environment and security requirements.
Understanding the Configuration Pipeline
ASP.NET Core loads configuration from multiple providers.
flowchart LR
A[appsettings.json]
B[Environment Variables]
C[User Secrets]
D[Azure Key Vault]
A --> E[Configuration]
B --> E
C --> E
D --> E
Later providers override earlier ones, allowing sensitive values to replace development defaults.
Using User Secrets
Initialize User Secrets for a project.
dotnet user-secrets init
Store a secret.
dotnet user-secrets set "ConnectionStrings:Default" "Server=.;Database=StoreDb;"
User Secrets are stored outside the project directory and should only be used during local development.
Reading Configuration
Retrieve secrets through the configuration system.
var connectionString =
builder.Configuration
.GetConnectionString("Default");
The application doesn't need to know whether the value came from User Secrets, Azure Key Vault, or an environment variable.
Using Environment Variables
Environment variables are commonly used in containers and cloud platforms.
Windows:
setx ConnectionStrings__Default "Server=prod-db;Database=StoreDb;"
Linux:
export ConnectionStrings__Default="Server=prod-db;Database=StoreDb;"
ASP.NET Core automatically maps double underscores (__) to configuration sections.
Using Azure Key Vault
Install the required package.
dotnet add package Azure.Extensions.AspNetCore.Configuration.Secrets
Register Azure Key Vault.
builder.Configuration.AddAzureKeyVault(
new Uri("https://myvault.vault.azure.net/"),
new DefaultAzureCredential());
Secrets stored in Azure Key Vault become available through the standard configuration API.
Configuration Priority
Configuration providers are loaded in a defined order.
| Priority | Provider |
|---|---|
| Highest | Command-Line Arguments |
| High | Environment Variables |
| Medium | Azure Key Vault |
| Low | User Secrets |
| Lowest | appsettings.json |
Higher-priority providers override values from lower-priority providers.
Accessing Secrets with Options Pattern
Bind configuration to strongly typed settings.
builder.Services.Configure<EmailOptions>(
builder.Configuration.GetSection("Email"));
Consume the settings.
public class EmailService
{
private readonly EmailOptions _options;
public EmailService(
IOptions<EmailOptions> options)
{
_options = options.Value;
}
}
The Options pattern improves maintainability and avoids scattered configuration lookups.
Secret Rotation
Secrets should be rotated regularly.
Typical rotation process:
Generate a new secret.
Store it in the secret provider.
Update the application configuration.
Verify successful deployment.
Remove the old secret.
Regular rotation reduces the impact of credential exposure.
Common Production Mistakes
| Problem | Root Cause |
|---|---|
| Secrets committed to Git | Stored in appsettings.json |
| API keys leaked | Hardcoded in source code |
| Shared development credentials | Same secrets across environments |
| Deployment failures | Missing environment variables |
| Manual secret updates | No centralized secret management |
| Expired credentials | No rotation policy |
Most secret-related incidents are caused by poor operational practices rather than framework limitations.
Best Practices
Store secrets outside the application codebase.
Use User Secrets only during local development.
Prefer Environment Variables or Azure Key Vault in production.
Rotate secrets regularly.
Grant applications the minimum required permissions.
Audit access to secret stores.
Remove unused or expired credentials promptly.
Common Anti-Patterns
Avoid these common mistakes:
Hardcoding secrets in source code.
Sharing production credentials with development environments.
Logging sensitive configuration values.
Reusing the same API keys across multiple applications.
Storing secrets in client-side applications.
Disabling access controls for convenience.
FAQ
Should connection strings be stored in appsettings.json?
Only for local development using non-sensitive values. Production connection strings should come from Environment Variables, Azure Key Vault, or another secure secret store.
What are User Secrets?
User Secrets are a development feature that stores sensitive configuration outside the project directory. They are not encrypted and should never be used in production.
Why use Azure Key Vault?
Azure Key Vault centralizes secret management, provides access control, supports secret rotation, and integrates seamlessly with ASP.NET Core configuration.
Can Environment Variables replace Azure Key Vault?
Yes, for many applications. However, Azure Key Vault provides additional security features such as centralized management, auditing, versioning, and controlled access, making it more suitable for production workloads.
Conclusion
Secure secret management is a critical component of every ASP.NET Core application. By keeping sensitive values out of source code, leveraging the built-in configuration system, and using appropriate secret providers for each environment, you can significantly reduce the risk of credential exposure and simplify application maintenance.
Whether you're developing locally with User Secrets, deploying containers with Environment Variables, or managing enterprise applications with Azure Key Vault, adopting a consistent secrets management strategy helps build secure, scalable, and production-ready .NET applications.

Jasen FiciPosted Aug 3, 2026, 2:03 PM
Great article! We featured it in DotNetNews here: https://dotnetnews.co/archive/the-net-news-daily-issue-510/