Skip to content

Documentation

Secrets

Store a credential once, reference it from actions and polled providers, and keep it out of every configuration that reads it back.

Anything RunDis calls on your behalf needs a credential — a bearer token for an API, a key for a webhook, a password for a mailbox. A secret is where that value lives, so the configuration that uses it holds a name instead of the credential.

Two things follow from that, and they are the reason to bother:

  • A configuration is safe to read. Anyone who can see a workflow can see how it is wired without seeing what it authenticates with.
  • One value, one place. A token used by three actions is rotated once.

Adding a secret

Open Secrets and choose Add Secret. A secret has a name, the value, and an optional description so the list means something later.

The name is how you refer to it, so name it after what it opens rather than where it is used — STRIPE_API_KEY rather than BILLING_STEP_TOKEN. Names are unique within your organisation; two organisations can both have a STRIPE_API_KEY and they are different secrets.

The value cannot be read back. Not through the interface, not through the API, not by you. The list shows names and descriptions only. If you need to know a value again, get it from wherever it came from originally.

You can replace a value at any time with Replace value. Anything referencing the secret picks up the new value on its next run — there is nothing to redeploy.

Referencing a secret

Write ${secret.NAME} wherever the credential would have gone:

${secret.STRIPE_API_KEY}

It can sit inside a longer string, so an action URL that carries a key works too:

https://api.example.com/v1/charges?key=${secret.STRIPE_API_KEY}

References resolve at the moment of the request, and only in memory. The stored configuration keeps the reference; the value never gets written back into it.

Where references work

Place Where a reference is substituted
Any action, all five types Every text value in the configuration — auth_token, a headers value, a URL, a body
Provider — outgoing_request The Auth Token field, and any headers value
Provider — run_script The Command, resolved when the script runs
Provider — incoming_webhook in a signature mode The Signing secret, resolved on each post the signature is checked on; the whole value must be one reference

Actions are the broad case: a reference is substituted anywhere text appears in the configuration, so it is not limited to the fields named like credentials.

Polled providers are narrower on purpose — the token and the headers only. The endpoint URL is not substituted, so a key that has to sit in a provider's URL still has to be written there directly. A script provider's command is text a shell runs, so a reference anywhere in it works, the way it does in an action. An inbound webhook's signing secret is a key, not text: the value is exactly one reference, and the stored value is what GitHub, Stripe or Slack signs with.

Triggers and steps have no credentials of their own; a step authenticates through the action it runs.

When a reference cannot be resolved

A reference to a secret that does not exist is an error, and the run fails with the name that was missing. It is deliberately not a passthrough: sending the literal text ${secret.STRIPE_API_KEY} as a bearer token would look like a working action and fail somewhere you cannot see.

So deleting a secret breaks whatever still references it, on purpose and visibly. The confirmation prompt says as much.

Credentials already written into a configuration

A configuration can hold a credential directly — older ones often do, and nothing stops you typing one in today.

Those values are redacted when read. The interface and the API return __redacted__ in their place, so a credential someone pasted in last year is no longer readable by everyone who can see the action. Saving the form back leaves the stored value alone, so editing a URL does not destroy the token beside it.

A reference is not redacted, because ${secret.STRIPE_API_KEY} is a name, not a credential. That asymmetry is the point: a configuration built on references stays completely readable.

Redaction hides those values but does not move them. To move them into the store, replace the field with a ${secret.NAME} reference and add the secret.

What secrets are not

Worth stating plainly, so nothing here is read as more than it is.

  • Values are encrypted before they are stored, so a copy of the database does not hand over your credentials. The key is held by the RunDis service, not by a hardware module, and not in a way that makes the values unreadable to the service itself — it has to decrypt them to use them.
  • There is no rotation schedule, no versioning, and no expiry. A value can be replaced. That is the whole lifecycle.
  • There is no audit trail of secret access. Runs record which action ran, not which secret it read.
  • Only admins can add, replace and delete secrets. Members and viewers can see which secrets exist, never their values. Roles are organisation-wide; there is no per-secret permission.