Manage credentials
Credentials are reusable authentication secrets: inbound webhooks (Trigger a workflow with a webhook) and exposed agents (Expose an agent as an API) reference them by id — the secret itself never appears in a workflow YAML or an agent file, both of which are versioned in git.
Two kinds
| Kind | Secret | Checked against |
|---|---|---|
basic |
username + password | Authorization: Basic … |
header |
header name + value | the configured header (ex. X-Api-Key), or Authorization: Bearer <value> on the OpenAI surface |
The Credentials module
The console's Credentials rail module creates, renames, replaces and deletes them. Two properties are deliberate:
- Values never come back. The list and the edit form only show a non-sensitive hint (the username, or the header name). Editing a secret means re-entering it entirely; leaving the secret fields empty on save keeps the stored one.
- Verification is server-side only — an inbound request is compared to the stored secret by the API, in constant time; the console never transports it.
The hint is part of the secret, so changing the username or the header name means re-entering the whole secret — the form says so rather than saving a half-change.
Deleting a credential is allowed even while webhooks or agents reference it:
those endpoints then answer 503 (broken auth configuration — distinct from
a caller's 401) until reconfigured. Authentication is closed by default: an
unknown auth mode is a 503 too, never an open endpoint.
Storage
Credentials live in a credentials table in the same database as the run
index (RUN_DB_URL: SQLite locally, Postgres in deployment — see
Run store and
Use the Postgres run index). They follow that
database's backup policy: if you back up the run index, you back up the
credentials.
Secrets are stored in cleartext — the data column is plain JSON, not
encrypted at rest. The confidentiality boundary of every inbound credential is
therefore that database: give it the access control, disk encryption and
backup handling you would give a secret store, and treat a run-index dump as a
secret dump. Choose where RUN_DB_URL points accordingly.
What is redacted from run traces
An inbound webhook's headers are journalled with its event, so before writing
them the API drops Authorization, Proxy-Authorization, Cookie,
Set-Cookie and the header name of every header credential in the
store — not just the one that authenticated this call, because several
integrations often share a single URL, each with its own key.
The corollary: a key sent in a header that no credential registers is not recognised as a secret, and will appear in the run's trace.
Related
- Security posture — where inbound authentication sits in the overall model.
- Environment variables —
RUN_DB_URL.