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:

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:

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:

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:

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:

  1. Developers use User Secrets during local development.

  2. The application reads configuration through the standard configuration system.

  3. In production, secrets are retrieved from Azure Key Vault.

  4. Managed identities authenticate the application without storing credentials.

  5. 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:

  1. Create a new secret.

  2. Update the secure secret store.

  3. Restart or refresh application configuration if required.

  4. Validate application functionality.

  5. Remove the old secret.

Planning for secret rotation reduces operational risk and supports security compliance requirements.

Configuration Source Comparison

Configuration SourceDevelopmentProductionRecommended
appsettings.jsonYes (non-sensitive settings)LimitedYes
User SecretsYesNoYes
Environment VariablesYesYesYes
Azure Key VaultOptionalYesYes
Hardcoded ValuesNoNoNever

Each configuration provider serves a specific purpose, but sensitive production credentials should always be stored in a secure secret management solution.

Best Practices

Common Mistakes

One common mistake is storing production credentials in appsettings.json. Even private repositories can become compromised, making tracked configuration files an unsuitable location for secrets.

Another issue is sharing the same credentials across development, testing, and production environments. Each environment should use separate credentials to reduce the impact of accidental exposure.

Developers also sometimes hardcode API keys directly into application code during testing and forget to remove them before deployment.

Testing and Validation

Before deploying an application, validate the following:

Automated deployment validation helps identify configuration issues before applications reach production.

Performance Considerations

Secret retrieval generally occurs during application startup or configuration loading, resulting in minimal runtime overhead.

To maintain good performance:

Security should never be sacrificed for marginal performance gains.

Security Considerations

Secrets management is only one part of an application's overall security posture.

Follow these recommendations:

Strong operational practices are just as important as secure storage.

Troubleshooting

Secret Value Is Missing

Verify that the correct configuration provider is registered and that the expected configuration key exists in the current environment.

Azure Key Vault Access Fails

Confirm that the application's managed identity or service principal has permission to read secrets from the vault.

Incorrect Configuration Is Loaded

Review the configuration provider order. Later providers override earlier ones, so provider registration order directly affects which values are returned.

Development Configuration Works but Production Fails

Ensure production secrets exist in the secure secret store and that environment-specific configuration is correctly deployed.

Conclusion

Managing secrets securely is a fundamental requirement for production ASP.NET Core applications. User Secrets provide a safe development experience, environment variables simplify cloud deployments, and Azure Key Vault offers centralized, enterprise-grade secret management for production environments. By separating secrets from application code, planning for secret rotation, and following secure configuration practices, developers can build applications that are easier to manage, more secure, and better prepared for modern deployment environments.