Skip to content

Secrets vault

Passwords, API keys, and connection strings never belong in a flow's saved configuration. FlowRunner keeps them in a per-workspace, encrypted vault and swaps them in at run time via ${secrets.NAME}.

What the vault is

Each workspace has its own set of secrets — a name and a value. Values are encrypted at rest with AES-256-GCM before they touch the database, using a server key. Reading a secret back requires that same key, so anyone with only database access sees ciphertext, not your credentials.

Secrets are scoped to the workspace, which means a credential set once is available to every project and flow in that workspace, and never leaks to another tenant.

Using a secret: ${secrets.NAME}

Anywhere a flow field takes a string, you can write a reference instead of a literal value:

${secrets.STRIPE_KEY}

At run time the engine resolves it against the workspace's decrypted vault. This works in:

  • Endpoint auth — a Bearer token, Basic password, or API key on a Start node.
  • Node configuration — an HTTP node Authorization header, a MongoDB node connection string, an email node setting, and so on.

The resolved value exists only for the duration of the run. The saved flow always contains the ${secrets.NAME} placeholder, so exporting or sharing a project never exposes a credential.

WARNING

Resolution is fail-closed and secrets are never read from environment variables. If ${secrets.API_TOKEN} names a secret that doesn't exist, it resolves to an empty string — not to a same-named env var. A missing secret can therefore break a request (for example, fail-closed auth rejects everyone) but can never silently substitute the wrong value.

There's a separate reference form for environment variables — ${env.NAME} — which does read from process.env. Keep the two straight: ${secrets.*} is the encrypted vault, ${env.*} is server configuration.

Managing secrets

Secrets are managed at the workspace level and require admin access. You can:

  • List the secret names in a workspace. The API and UI return names only — a stored value is never sent back after it's set.
  • Set a secret with a name and value. Names must start with a letter or underscore and contain only letters, digits, and underscores (^[A-Za-z_][A-Za-z0-9_]*$). Setting an existing name overwrites it.
  • Delete a secret by name.

Every set and delete is recorded in the workspace audit log.

INFO

📸 Screenshot — the workspace secrets panel listing secret names with add and delete controls.

TIP

Because you can never read a value back, treat the vault as write-only. If you forget a value, re-set it rather than trying to recover it.

Turning the vault on

The vault needs a server key, SECRETS_KEY — 32 bytes, base64-encoded. Generate one with:

bash
openssl rand -base64 32

Set it as an environment variable on your deployment. Without it:

  • The encrypted secrets vault is disabled — setting a secret returns an error, and getWorkspaceSecrets returns an empty map, so every ${secrets.NAME} resolves to empty.
  • The app still runs; SECRETS_KEY is an optional variable that toggles this one feature.

NOTE

The key encrypts and decrypts every value. If you rotate SECRETS_KEY, previously stored values can no longer be decrypted — the vault skips any value it can't decrypt rather than erroring, so re-set your secrets after a rotation.

See also

FlowRunner — the no-code platform for small businesses.