10.6 Secrets handling (write-only config fields)

Some config values are secrets — the JWT signing key, API credentials for custom services. RS2 treats designated fields as write-only: you can set and rotate them, but you can't read them back. This makes the normal config edit loop safe by default.

What's a secret

  • auth.jwtSecret — the token signing key.
  • Everything under a top-level secrets block in the tenant config.

Write-only behavior

Operation Behavior
GET /services/raw Secret fields read back as the literal marker "<secret>" — the real value is never returned
PUT /services/raw with "<secret>" left in place The marker is replaced with the stored value — the secret is preserved
PUT /services/raw with a real value Rotates the secret to that value
PUT with a "<secret>" marker that has no stored counterpart 400 — you can't mark a field secret without supplying a value

Why this matters

The everyday edit loop is read → modify → write (10.4). Because secrets read back as markers and markers are re-expanded to stored values on write, that loop never destroys a secret — you can edit any other part of the config and PUT it back without having to know, or re-enter, the JWT key. It's safe to hand a GET /services/raw payload to a tool or a person without leaking credentials.

Rotating a secret

To change a secret, replace its marker with the new real value and PUT:

// GET returns:
"auth": { "jwtSecret": "<secret>", … }

// To rotate, PUT with:
"auth": { "jwtSecret": "a-new-strong-key", … }

Rotating auth.jwtSecret invalidates existing tokens (they were signed with the old key), so users re-authenticate — plan rotations accordingly.

Operator hygiene

  • Seed auth.jwtSecret out of band — the runtime and the migrator (Part 11) won't invent one for you; a tenant with auth needs a strong key set before it's useful.
  • Keep secrets in the secrets block for custom-service credentials, and grant only the named secrets a mount needs. Prefer host-side credential injection, so a secret never enters a sandbox or an outbound request spec.
  • Keep operator-owned credentials in infras.json, not tenant config. A tenant can reference an infra: and discover its provided field names, but never read the values (10.7).
  • Don't put secrets in logs or client-visible responses — and note RS2 won't surface them through GET /services/raw, which is the most likely accidental leak path.

The final operator section covers those infras, bootstrap, and production boundaries. Part 11 then brings an existing v1 Restspace configuration across.


Previous: 10.5 Deploying & rotating code · Manual home · Next: 10.7 Infras, bootstrap, production →