user secretsyml
User Secrets and Symlinks in .NET: The Complete Developer Guide
Managing sensitive configuration like API keys and database passwords should never involve committing credentials to source control. .NET User Secrets solve this problem elegantlyโuntil you hit symlink-related issues. This guide resolves every common pain point developers face when working with user secrets and symbolic links.
Key Takeaways
- User Secrets store JSON configuration files outside your project in
%APPDATA%\Microsoft\UserSecretson Windows, ensuring secrets never enter version control. - Symlink errors occur when the secrets file path cannot be resolved, often after moving projects, using junction points, or deploying to Linux containers.
- dotnet user-secrets set requires the
<UserSecretsId>to be defined in your.csprojfile. - Cross-platform compatibility varies: macOS and Linux use
$HOME/.microsoft/usersecrets, while Windows uses the AppData folder. - Alternative approaches such as environment variables, Azure Key Vault, and HashiCorp Vault eliminate symlink concerns entirely in production.
What Are .NET User Secrets?
ASP.NET Core User Secrets is a development-time tool that stores sensitive configuration values in a separate JSON file outside your project directory. The data is managed through the dotnet user-secrets CLI and integrated into the Configuration system via UserSecretsConfigurationSource.
The secrets file is a plain JSON structure. Here is what a typical secrets store looks like:
{
"ConnectionStrings": {
"DefaultConnection": "Server=localhost;Database=MyApp;Trusted_Connection=True;"
},
"AzureAd": {
"ClientId": "your-client-id",
"TenantId": "your-tenant-id"
},
"ApiKey": "sk-proj-abc123xyz"
}
Because this file lives outside your project tree, it is automatically excluded from source control and from deployment pipelines.
How Do Symlinks Affect User Secrets?
Symlink issues arise in three primary scenarios:
1. Project Moved or Cloned With Broken Symlinks
If you share a secrets file across multiple machines or projects using a symbolic link, moving the project without recreating the symlink will cause UserSecretsException at runtime. The Configuration system will fail to locate the secrets JSON and throw a FileNotFoundException.
2. Docker Containers and Linux Deployments
Running user secrets inside a container is unsupported by design. The secrets file path resolves to a location that may not exist in the container filesystem, especially when paths are mounted or linked differently than the host machine.
3. Junction Points on Windows
Windows junction points (directory symlinks) behave differently from file symlinks. If your project directory is a junction pointing to another volume, the User Secrets system may resolve paths incorrectly and fail to read or write the secrets file.
| Platform | Secrets Path | Symlink Risk | Typical Failure Mode |
|---|---|---|---|
| Windows | %APPDATA%\Microsoft\UserSecrets\<id>\secrets.json |
Low | Project moved without regenerating secrets reference |
| macOS | $HOME/.microsoft/usersecrets/<id>/secrets.json |
Medium | Home directory symlinked to external volume |
| Linux | $HOME/.microsoft/usersecrets/<id>/secrets.json |
High | Container env, missing directory, or $HOME not set |
| Docker | Not recommended | Critical | Secrets file inaccessible at runtime; build fails silently |
Common Problems and Solutions
Problem: UserSecretsId Not Found
The most frequent error is forgetting to set the UserSecretsId in your project file. Without it, the CLI cannot identify which secrets group belongs to your project.
Solution: Add the following to your .csproj:
<PropertyGroup>
<UserSecretsId>your-unique-guid-here</UserSecretsId>
</PropertyGroup>
Problem: Secrets File Returns Null at Runtime
Values appear set in the CLI but return null when read through IConfiguration. This typically means the secrets are stored under a different UserSecretsId than the one your project declares.
Solution: Run dotnet user-secrets list from the project directory and confirm the UserSecretsId matches your .csproj value exactly.
Problem: Broken Symlink After Project Relocation
When you move a project folder and the secrets path contains relative components, the link breaks. The application throws an exception on startup before any middleware executes.
Solution: Regenerate the secrets reference in the new location:
cd /path/to/new/project/location
dotnet user-secrets init --id "your-unique-guid-here"
dotnet user-secrets set "ApiKey" "your-value"
Problem: Symlink Permission Denied on Linux
Linux systems enforce strict permissions on symlinks. If the secrets directory is owned by another user or lacks read permissions, the Configuration system cannot access it.
Solution: Check and repair permissions:
ls -la ~/.microsoft/usersecrets/
chmod 700 ~/.microsoft/usersecrets/<id>
chown -R $USER:$USER ~/.microsoft/usersecrets/<id>
Best Practices Checklist
| Task | Priority | Status |
|---|---|---|
Define UserSecretsId in .csproj | Required | โ |
Exclude secrets.json from .gitignore | Required | โ |
| Never commit real secret values to any branch | Required | โ |
Use dotnet user-secrets list to verify entries | Required | โ |
| Avoid symlinks for the secrets directory in production | High | โ |
| Test secrets loading in a clean environment before deploy | High | โ |
| Switch to environment variables or a secrets manager in production | High | โ |
| Rotate secrets periodically and update all environments | Medium | โ |
Document the |