Master Guides

Secrets

Development secrets that never touch your repository.

master secrets is the dotnet user-secrets equivalent: it stores per-project development secrets in a JSON file outsidethe repo, and MasterController’s layered configuration reads them automatically — so Auth:JwtSecret works on your laptop without ever being committed.

The commands#

terminal
$ master secrets set Auth:JwtSecret "$(openssl rand -hex 32)" # write (creates the file)
$ master secrets get Auth:JwtSecret # print the raw value (exit 1 if unset)
$ master secrets list # every key, values masked
$ master secrets list --reveal # ... values shown
$ master secrets remove Auth:JwtSecret # delete one key
$ master secrets clear # delete the whole file
$ master secrets path # where the file lives
ActionWhat it does
set <Section:Key> <value>Create or update a key. Nested sections are written as nested JSON; existing keys match case-insensitively.
get <Section:Key>Write the value to stdout (script-friendly). Exits with code 1 when the key is not set.
list [--reveal]Flatten every key to Section:Key = value. Values are masked unless --reveal is passed.
remove <Section:Key>Delete one key (warns if it was not set).
clearDelete the secrets file for this project.
pathPrint the absolute path of the secrets file.

Keys use : to separate sections — exactly the keys you read with master.configuration.get('Auth:JwtSecret'), and the same keys you set as Auth__JwtSecret environment variables in production.

Where the file lives#

Secrets are stored in ~/.master/usersecrets/<id>/secrets.json, created with 0700/0600 permissions. The id is the backend package name (backend/package.jsonname, e.g. my-app-backend), falling back to the root package name, then the folder name.

~/.master/usersecrets/my-app-backend/secrets.json
{
  "Auth": {
    "JwtSecret": "2f6c9d7e...a1b4"
  }
}
  • --id <id> targets a different secrets id (useful when several apps share one file).
  • MASTER_USER_SECRETS_PATH overrides the base directory (~/.master/usersecrets).

How the backend reads them#

The scaffolded backend/server.js sets master.userSecretsId to the backend package name before building the server, so MasterController adds the secrets file as a configuration source — no extra code in your controllers:

backend/server.js (excerpt)
const pkg = JSON.parse(readFileSync(join(__dirname, 'package.json'), 'utf8'));

process.env.NODE_ENV ??= 'development';
master.root = __dirname;
master.environmentType = process.env.NODE_ENV;
master.userSecretsId = pkg.name;   // -> ~/.master/usersecrets/<pkg.name>/secrets.json

const server = master.setupServer('http');
const config = master.configuration;

// Opt-in JWT auth: present only when the secret is configured.
const jwtSecret = config.get('Auth:JwtSecret') || process.env.JWT_SECRET;
if (jwtSecret) {
  master.auth.addJwtBearer('bearer', {
    secret: jwtSecret,
    issuer: config.get('Auth:Issuer', pkg.name),
    expiresIn: config.get('Auth:ExpiresIn', '1h'),
  });
  master.auth.addPolicy('AdminOnly', { roles: ['admin'] });
}

Inside a controller the same values are available as this.configuration.get('Auth:Issuer') or, through the options pattern, this.options.<Name>.

Configuration precedence#

Later sources win. User secrets sit above every file in the repo and below real environment variables:

  1. backend/config/appsettings.json
  2. backend/config/appsettings.<NODE_ENV>.json
  3. backend/config/environments/env.<NODE_ENV>.json (the MasterRecord database config)
  4. User secrets~/.master/usersecrets/<id>/secrets.json
  5. Environment variables — Section__Key (__ becomes :)
  6. Command line — --Section:Key=value

See Configuration for the whole picture.

Production: environment variables#

The secrets file exists only on developer machines. On a server, set the same keys as environment variables with __ in place of : — they land on the same configuration keys, so application code never changes:

production environment
NODE_ENV=production
Auth__JwtSecret=<a long random value, 32+ characters>
Auth__Issuer=my-app
Logging__LogLevel__Default=warn
Secrets are for development
master secrets stores values in plain JSON protected only by file permissions. It keeps secrets out of git and out of .envfiles — it is not a vault. In production use environment variables or your platform’s secret store.
JWT secret length
Auth:JwtSecret must be at least 32 characters. openssl rand -hex 32 produces 64 — plenty.