GM.Secrets 2.0.0

dotnet add package GM.Secrets --version 2.0.0
                    
NuGet\Install-Package GM.Secrets -Version 2.0.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="GM.Secrets" Version="2.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="GM.Secrets" Version="2.0.0" />
                    
Directory.Packages.props
<PackageReference Include="GM.Secrets" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add GM.Secrets --version 2.0.0
                    
#r "nuget: GM.Secrets, 2.0.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package GM.Secrets@2.0.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=GM.Secrets&version=2.0.0
                    
Install as a Cake Addin
#tool nuget:?package=GM.Secrets&version=2.0.0
                    
Install as a Cake Tool

GM.Secrets

Layers an app's secrets into IConfiguration, so code reads them like any other setting — IConfiguration["ApiKey"], IOptions<T> / IOptionsMonitor<T>, connection strings — without knowing whether a value came from appsettings, a local file, or a secret store. Which store (Doppler, AWS Secrets Manager, Azure Key Vault, HashiCorp Vault) is picked per environment with one environment variable, SECRETS_PROVIDER.

  • GM.Secrets — builder.AddGMSecrets(...): the local appsecrets.json layer, store selection, and loading the store into configuration (with optional reload for rotation).
  • GM.Secrets.Doppler — a Doppler config, via its REST API and a service token.
  • GM.Secrets.AwsSecretsManager — AWS Secrets Manager, via AWSSDK.SecretsManager.
  • GM.Secrets.AzureKeyVault — Azure Key Vault, via Azure.Security.KeyVault.Secrets + DefaultAzureCredential.
  • GM.Secrets.Vault — HashiCorp Vault KV v2, via its HTTP API (token or AppRole).

Install

dotnet add package GM.Secrets
dotnet add package GM.Secrets.Doppler            # and/or the store(s) you deploy with
dotnet add package GM.Secrets.AwsSecretsManager
dotnet add package GM.Secrets.AzureKeyVault
dotnet add package GM.Secrets.Vault

Register

builder.AddGMSecrets();

That's all the code. The store is chosen by environment variables: SECRETS_PROVIDER=AzureKeyVault loads the referenced GM.Secrets.AzureKeyVault package and configures it from its own variables (AZURE_KEYVAULT_URI, ...). Only that package is loaded; the others are never touched. Reference the store packages the app can be deployed with — an app that only runs on Azure needs just GM.Secrets.AzureKeyVault.

To set a store's options in code instead, register it; that registration wins over the package's defaults:

builder.AddGMSecrets(secrets => secrets.AddVault(o => o.MountPoint = "kv"));

Then read secrets the usual way:

var apiKey = builder.Configuration["Payments:ApiKey"];
builder.Services.Configure<DbCredentials>(builder.Configuration.GetSection("DbCredentials"));

public sealed class PaymentClient(IOptionsMonitor<DbCredentials> db) { /* db.CurrentValue */ }

Never log a secret value; error messages from the stores carry names and status codes only.

Configuration layers

Lowest to highest precedence:

appsettings.json → appsettings.{Environment}.json
  → appsecrets.json → appsecrets.{Environment}.json   (AddGMSecrets — any environment, when present)
  → the store SECRETS_PROVIDER selects                 (AddGMSecrets — none when unset)
  → environment variables → command line
  • appsecrets.json holds local secret values. Keep it gitignored; the package also keeps appsecrets*.json out of dotnet publish. A JSON object there ("Db": { "User": "..." }) is a section like any other. SECRETS_FILE points the layer at a file elsewhere; turn it off with secrets.AppSecretsFile.Enabled = false.
  • The store overrides the files: a key it has wins, a key it lacks falls back to appsecrets and appsettings. It is loaded at startup (a failure stops startup) and, with SECRETS_RELOAD_INTERVAL, re-fetched on that interval — IConfiguration and IOptionsMonitor<T> see the new values without a restart (IOptions<T> doesn't; it is read once). A failed refresh keeps the last values. Stores that aren't selected are never created.

Environment variables

The settings that decide where secrets come from are read from process environment variables only — never appsettings, appsecrets.json, the command line or a store — so a store's credentials never sit next to the secrets they unlock.

Variable Default Does
SECRETS_PROVIDER none the store to load: Doppler, AwsSecretsManager, AzureKeyVault or Vault; unset loads none
SECRETS_RELOAD_INTERVAL off re-fetch the store this often, e.g. 00:05:00
SECRETS_FILE appsecrets.json in the content root the local secrets file, anywhere: absolute or relative to the content root, e.g. D:\secrets\myapp.json (must exist; myapp.{Environment}.json beside it is loaded too)

A SECRETS_PROVIDER whose package isn't referenced, a malformed value, or a store missing its settings fails at startup with the variable's name (never its value).

Security

What the library does:

  • Credentials only from the environment. SECRETS_PROVIDER and every store's address and credentials are read from process environment variables — never from appsettings, appsecrets.json, the command line or a store — so the place secrets come from is never set by those secrets.
  • No secret values in errors. Failures name the variable, the path or the HTTP status; a malformed variable's value is left out of its error, and a store's token never appears in one.
  • Tokens only over TLS. Vault and Doppler refuse a plain http address unless it is on this machine (a dev server), since their tokens travel in request headers. Vault mounts and paths are checked so a value can't step to another endpoint (.., ?, #).
  • Only the selected store is loaded. SECRETS_PROVIDER must be a plain name; only GM.Secrets.{name} is loaded, and unselected stores are never created.
  • Local secrets stay local. appsecrets*.json in the project is excluded from dotnet publish.

What you do:

  • Keep credentials (DOPPLER_TOKEN, VAULT_TOKEN, AWS_SECRET_ACCESS_KEY, AZURE_CLIENT_SECRET) in environment variables — user variables locally, the platform's secret settings when deployed — and out of committed files such as launchSettings.json. In Azure and AWS prefer a managed identity / IAM role, which needs no credential at all.
  • Gitignore appsecrets*.json, and never put a real secret in appsettings*.json.
  • Give each app's identity read access to its own secrets only (Key Vault Secrets User, secretsmanager:GetSecretValue on one ARN, a Vault policy on one path, a Doppler service token per config). Rotate anything that was committed or shared.
  • Never log configuration values; secrets are ordinary configuration once loaded.

Secret stores

Store SECRETS_PROVIDER Variables Secret names → configuration keys
Doppler Doppler DOPPLER_TOKEN, optional DOPPLER_PROJECT, DOPPLER_CONFIG (with a personal or CLI token it defaults from the app environment: Development → dev, Staging → stg, Production → prd), DOPPLER_API_URL SAMPLE__USER → SAMPLE:USER (keys are case-insensitive)
AWS Secrets Manager AwsSecretsManager AWS_SECRETS_MANAGER_SECRET_IDS (comma-separated), AWS_REGION, AWS_ENDPOINT_URL_SECRETS_MANAGER (emulators); credentials from the AWS default chain (IAM role, AWS_ACCESS_KEY_ID + AWS_SECRET_ACCESS_KEY, AWS_PROFILE) a JSON secret is flattened (__ and nesting → sections); a plain secret is keyed by its name (/ → :)
Azure Key Vault AzureKeyVault AZURE_KEYVAULT_URI, optional AZURE_KEYVAULT_PREFIX; credentials from DefaultAzureCredential (managed identity, az login, Visual Studio, or an app registration: AZURE_TENANT_ID, AZURE_CLIENT_ID, AZURE_CLIENT_SECRET) Sample--User → Sample:User; enabled, unexpired secrets only
HashiCorp Vault Vault VAULT_ADDR (https; plain http only for this machine); VAULT_TOKEN, or VAULT_ROLE_ID + VAULT_SECRET_ID (AppRole), else the vault login token in ~/.vault-token; VAULT_PATHS (comma-separated), VAULT_MOUNT (secret), VAULT_NAMESPACE KV v2 data flattened (nesting and __ → sections)

Lists are comma-separated: VAULT_PATHS=myapp/shared,myapp/production (later ones win). Every store's options can also be set in code: .AddVault(o => ...). On a developer machine the stores' own logins work as-is: vault login, aws sso login / AWS_PROFILE, az login, a Doppler token — the samples repo shows each.

Add a store

Implement ISecretsStore — one method, LoadAllAsync, returning every secret keyed in configuration form (ConfigurationSecrets.FlattenJson / NormalizeKey help). To make SECRETS_PROVIDER=MyStore find it, ship it in a package named GM.Secrets.MyStore that declares a factory reading its settings from environment variables:

[assembly: SecretsStore("MyStore", typeof(MyStoreFactory))]

internal sealed class MyStoreFactory : ISecretsStoreFactory
{
    public ISecretsStore Create(SecretsVariables variables, IHostEnvironment environment) =>
        new MyStore(new MyStoreOptions { Url = variables.GetUri("MYSTORE_URL") });
}

A store in any other assembly can be registered in code instead: builder.AddGMSecrets(s => s.AddProvider("MyStore", variables => new MyStore(...))).

Samples

GM.Secrets.Samples — a runnable API that reads its secrets through configuration, locally and from each store.

License

MIT — see LICENSE.

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (8)

Showing the top 5 NuGet packages that depend on GM.Secrets:

Package Downloads
GM.API

An opinionated ASP.NET Core Web API starter for .NET. A single AddGMAPI/UseGMAPI pair wires up controllers, CORS, API versioning, Swagger docs, FluentValidation, Serilog, and middlewares for exception handling, request logging (with sensitive-data masking) and request localization. Loads secrets into configuration from a local appsecrets.json or the store the SECRETS_PROVIDER environment variable names (Doppler, AWS Secrets Manager, Azure Key Vault, HashiCorp Vault). Bundles the GM.API.* companion packages.

GM.Secrets.AzureKeyVault

Azure Key Vault secrets provider for GM.Secrets — loads a vault's enabled secrets into IConfiguration at startup with DefaultAzureCredential (managed identity in Azure, az login / Visual Studio locally), with optional periodic reload. Db--Password maps to Db:Password. Register with builder.AddGMSecrets(s => s.AddAzureKeyVault()) and select via Secrets:Provider = "AzureKeyVault".

GM.Secrets.AwsSecretsManager

AWS Secrets Manager provider for GM.Secrets — reads the configured secrets (a JSON secret is flattened into keys, a plain one is keyed by its name) with the AWS SDK's default credential chain, and loads them into IConfiguration at startup, with optional periodic reload. Works with LocalStack/moto via ServiceUrl. Register with builder.AddGMSecrets(s => s.AddAwsSecretsManager()) and select via Secrets:Provider = "AwsSecretsManager".

GM.Secrets.Doppler

Doppler store for GM.Secrets — downloads a Doppler config's secrets (REST API, no SDK dependency) and loads them into IConfiguration at startup, with optional periodic reload. DB__PASSWORD maps to Db:Password. With a personal or CLI token the app environment picks the config (Development → dev, Staging → stg, Production → prd). Register with builder.AddGMSecrets(s => s.AddDoppler()) and select with the SECRETS_PROVIDER=Doppler environment variable.

GM.Secrets.Vault

HashiCorp Vault secrets provider for GM.Secrets — reads KV v2 paths over Vault's HTTP API (token or AppRole auth, no SDK dependency) and loads them into IConfiguration at startup, with optional periodic reload. Nested values become sections. Register with builder.AddGMSecrets(s => s.AddVault()) and select via Secrets:Provider = "Vault".

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
2.0.0 668 10/30/2026
1.0.1 238 8/31/2026
1.0.0 178 8/5/2026