
We run into the same headache every time—how do we keep secrets like API keys and passwords safe in our .NET Core projects? It’s easy to slip up and leave something sensitive in source control, especially when we’re moving fast. We lean on secure configuration management to draw a hard line between our code and our secrets.
For local development, we use tools that keep secrets outside the project folder, while in production we switch to environment variables or external vaults. We focus on practical steps and habits that actually work, not just theory, so our apps stay locked down.
Key Takeaway
- Use the Secret Manager tool for local development secrets to avoid storing sensitive data in source control.
- In production, rely on environment variables or centralized secret management services for secure secret storage and access.
- Follow best practices like secret rotation, environment segregation, and layered configuration to minimize risk.
What Is Secure Configuration Management in .NET Core?
Secure configuration management means separating secrets from code. We don’t just shove passwords or access tokens into files like appsettings.json or even straight into the codebase. Instead, we store them where they won’t leak if someone clones our repo or scrolls through a commit log. (1)
.NET Core makes that easier for us. It gives us a structure that pulls configuration from many places—files, environment variables, secret stores—and merges it together. During development, we lean on the Secret Manager tool. It lets us tuck away API keys and tokens in a local JSON file tied to our user profile. Not our repo. Not our code.
When we push our apps to production, we step things up. Environment variables, secure vaults, locked-down servers. These are the tools that let us sleep better at night. Our job is to use ’em right—and to keep our hands off the risky shortcuts.
How the Secret Manager Tool Works for Development
Starting Off
We kick things off by typing dotnet user-secrets init. Simple. That command stamps a UserSecretsId right into our .csproj file. That ID links our project to a secret store that’s local to us. On Windows, it’s under %APPDATA%\Microsoft\UserSecrets\. On Linux or macOS, it’s in a hidden .microsoft folder under our home directory.
It doesn’t show up in Git. It doesn’t travel. It’s ours.
Adding Secrets
Now we want to add something like an API key. We run:
bash
CopyEdit
dotnet user-secrets set “ApiKey” “abc123-super-secret”
Behind the scenes, that gets written to a JSON file named after the UserSecretsId. The file lives outside our project folder—far from appsettings.json or anything tracked by Git.
Getting Secrets in Our App
We don’t need to do anything fancy in our code. Just call CreateDefaultBuilder in Program.cs. That method automatically pulls in user secrets during development.
So later, in our service or controller, we just do:
csharp
CopyEdit
var apiKey = Configuration[“ApiKey”];
And we’re set. Clean. Secure. No one peeks unless they’re on our machine and know where to look.
Some Boundaries
But we’ve got to remember: this tool’s for development. Secrets aren’t encrypted. They’re local. They’re meant for quick, safe testing—not shared staging environments, not production servers, not even other devs. We keep it on our side of the wall.
Managing Secrets in Production
Using Environment Variables
Environment variables give us a dead-simple way to plug secrets into our app without storing them in files. We set them on the host OS, in our container config, or inside the deployment pipeline.
.NET Core’s config system checks for environment variables automatically. It merges them right in with everything else—like appsettings.json, command-line args, and user secrets.
Example? Say we’re in Linux:
bash
CopyEdit
export ConnectionStrings__DefaultConnection=”Server=prod-db;User Id=admin;Password=secret;”
Double underscore __ means nested keys. It works like a charm.
Going Beyond: Secret Management Services
For production apps—especially ones that handle personal data, financial info, or just anything worth stealing—we need vaults. Tools made just for secrets. Here’s how we usually break it down:
- Secure Storage: Secrets are encrypted at rest using cloud-native or customer-managed keys.
- Access Control: We assign who (or what) can read secrets, and we lock out everything else.
- Audit logs: Every read and write gets logged, so if something smells fishy, we can trace it.
- Rotation Support: Some tools even rotate secrets for us, either on a schedule or by trigger.
We wire these tools into our app using a config provider. In Program.cs, we might have something like:
csharp
CopyEdit
builder.Configuration.AddKeyVault(
new Uri(“https://myvault.vault.net/”),
new DefaultAzureCredential()
);
From there, accessing secrets feels no different. Configuration[“ApiKey”] still works. But this time, it’s coming from a fortified vault.
Best Practices for .NET Core Secret Safety
We’ve learned the hard way that small mistakes can snowball (2). So we’ve built habits that help keep secrets secret:
1. Never Commit Secrets
Even by accident. We double-check .gitignore files. We review PRs. We automate scans for exposed secrets (sometimes our CI/CD tools help catch that). If a secret slips into version control, we rotate it. Immediately.
2. Split Secrets by Environment
What works in development shouldn’t exist in production. We create separate vaults or config files for dev, test, staging, and prod. That way, if one gets exposed, the others stay safe.
3. Rotate Often
Nothing lasts forever. Especially not tokens or keys. We change secrets every few weeks—or sooner if something changes, like an employee leaving or a service being upgraded. Many secret stores support auto-rotation too. We use it when we can.
4. Use Config Layers
.NET Core merges configs in order. Here’s how we stack ’em:
- appsettings.json → base config
- appsettings.Development.json → overrides for local
- User secrets → sensitive dev values
- Environment variables → dynamic values
- Secret vaults → secure production secrets
Each one builds on the last, overriding as needed.
5. Secure the Pipeline
Build servers and CI/CD tools often touch secrets. We treat them like production systems:
- No hardcoded secrets in scripts
- Use secret variables or vaults
- Limit access by role
- Audit everything
6. Watch Access Logs
If someone (or something) pulls a secret, we want to know. Most vaults track access. We check those logs regularly, especially after big changes.
Handling Secrets in Containers

Containers give us speed and consistency—but they also come with risks. Secrets don’t belong in Dockerfiles or baked into images. They shouldn’t live in appsettings.json, either.
Here’s how we deal with it:
- Use Docker Secrets: These mount secret files into the container at runtime. They live in RAM and vanish when the container stops.
- Inject Environment Variables: We use docker run -e or orchestrator settings.
- Access Vaults at Runtime: Our app can fetch secrets during startup if needed.
This way, we avoid keeping secrets in plain sight—or frozen into a Docker layer.
Common Mistakes We Avoid
Here are the big ones. The ones that sting most.
- Hardcoding Secrets: Never. Ever. No exceptions.
- Leaking via Logs: We’ve accidentally logged full connection strings before. Now we sanitize outputs.
- Over-permissive Access: Every vault has access policies. We review them. We restrict by least privilege.
- Reusing Secrets Across Apps: Different apps = different secrets. Always.
- Skipping Rotation: It’s easy to forget. But stale secrets are weak secrets.
Real-World Walkthrough: Adding User Secrets
Let’s say we’re starting a new project. Here’s what we’d do:
- Run dotnet user-secrets init in our project folder.
- Check that our .csproj has a UserSecretsId.
- Add a secret with:
bash
CopyEdit
dotnet user-secrets set “ApiKey” “test-123-key”
- Open Program.cs and make sure we’re using CreateDefaultBuilder.
That’s it. From here on, we can call Configuration[“ApiKey”] anywhere we want.
For local development, it’s quick and safe. If someone clones our repo, they get the code—but none of our secrets.
Checklist: Secure Configuration Setup
Before we ship anything, we ask ourselves:
- Are all secrets out of source control?
- No passwords, tokens, or keys left in code. If we spot one, we pull the brakes.
- Are vaults or environment variables used for production?
- Secrets don’t belong in files or emails. They go in vaults or env vars, period.
- Do secrets rotate on a schedule?
- Not just when we remember—there’s a real schedule, and we stick to it.
- Is each environment fully separated?
- Dev, test, and production don’t mix. No shared credentials, no shortcuts.
- Are pipelines secure and locked down?
- Only the right people get access, and we keep it tight.
- Is access logged and reviewed?
- Every access is tracked. We actually look at the logs, not just collect them.
If the answer to any of those is “no,” we hold the release. No exceptions. That’s how we keep our projects and users safe, even when the pressure’s on.
FAQ
What are .NET Core secrets and why do I need them?
.NET Core secrets are special settings that your app needs to work, like passwords and connection strings. You need them because regular config files can be seen by anyone who gets your code. Secrets keep your private information safe from prying eyes.
How do I set up secure configuration management in my .NET Core app?
Start by adding the configuration packages to your project. Then create a secrets file that stays on your computer only. Use the built-in tools to manage these secrets without putting them in your main code files.
Where should I store my .NET Core secrets during development?
Store them in the user secrets folder on your local machine. This folder is separate from your project files, so secrets won’t accidentally get shared when you send your code to others or upload it online.
What’s the difference between user secrets and environment variables for .NET Core?
User secrets work great for development on your computer, but environment variables are better for production servers. User secrets are easier to manage locally, while environment variables give you more control when your app runs live.
How do I keep my .NET Core secrets safe in production?
Use your hosting platform’s secret management tools or environment variables. Never put real secrets in config files that get deployed. Always use secure vaults or your cloud provider’s secret storage when your app goes live.
Can I accidentally share my .NET Core secrets with my team?
Yes, if you put secrets in regular config files or commit them to your code repository. Always use the proper secrets management tools and never include secret files in your version control system to avoid this problem.
What happens if someone gets access to my .NET Core application secrets?
They could access your databases, external services, or other protected resources. This is why you need to rotate your secrets regularly and use proper access controls. Think of secrets like house keys that need changing when lost.
How do I migrate from storing secrets in config files to proper secret management?
Move your sensitive values to the secrets system one by one. Update your code to read from the new secret locations. Test everything works before removing the old config values. Take your time to avoid breaking your app.
Conclusion
Start early. Build the habits now. Once we wrap secret management into our workflow, we don’t really think about it anymore. It becomes like locking the door before leaving the house.
Use the Secret Manager tool for development. Move to environment variables or vaults for production. Rotate secrets often. Don’t hardcode. And always—always—keep an eye on what your app knows.
We don’t need to be perfect. Just cautious. Just consistent. Just a little paranoid, in a good way. Because the truth is, our secrets aren’t really secrets if we’re careless. They’re risks. And we’ve got enough of those already.
👉 Want to level up your secure coding skills? Join the Secure Coding Practices Bootcamp for hands-on training that helps you ship safer code—fast, practical, and built for real developers.
Related Articles
- https://securecodingpractices.com/secure-coding-in-c-net/
- https://securecodingpractices.com/secure-data-handling-c-sharp-cryptography-api/
- https://securecodingpractices.com/secure-express-js-application-development-guide/
References
- https://en.wikipedia.org/wiki/Software_configuration_management
- https://programmers.io/blog/building-web-application-with-asp-net-core/