The secrets module lets automations securely store and retrieve sensitive values (API keys, tokens, credentials) at runtime. Values are encrypted at rest and never exposed as plaintext in automation outputs or logs.
How it works
secrets.set and secrets.get return an opaque secret reference (a $secret:... string), not the actual value.
- When this reference is used inside a
fetch instruction (in the URL, headers, body, query, or auth fields), the platform automatically resolves it to the real value just before the HTTP call.
- The resolved value is redacted from all logs and events.
Secret references are short-lived (a few minutes). Always call secrets.get right before using the reference — do not store it for later reuse.
Scopes
| Scope | Description |
|---|
workspace | Shared across all users in the workspace. Any workspace editor can read/update it. |
user | Private to the current user. Only accessible by automations running in that user’s context. Not available in cron/schedule triggers (no user context). |
Functions
set — Store or update a secret
- run:
module: secrets
function: set
parameters:
name: myApiKey
value: "sk-live-abc123"
scope: workspace
output: secretRef
| Parameter | Type | Required | Description |
|---|
name | string | yes | Unique name for the secret (within its scope) |
value | any | yes | The value to encrypt and store |
scope | user | workspace | yes | Storage scope |
ttl | number | no | Time-to-live in seconds. The secret expires and becomes unreadable after this duration. |
Returns a $secret:... reference string. If a secret with the same name and scope already exists, it is updated.
get — Retrieve a secret reference
- run:
module: secrets
function: get
parameters:
name: myApiKey
scope: workspace
output: secretRef
| Parameter | Type | Required | Description |
|---|
name | string | yes | Name of the secret to retrieve |
scope | user | workspace | yes | Storage scope |
Returns a $secret:... reference string, or { error: "not_found" } if the secret does not exist (or has expired).
delete — Remove a secret
- run:
module: secrets
function: delete
parameters:
name: myApiKey
scope: workspace
output: result
| Parameter | Type | Required | Description |
|---|
name | string | yes | Name of the secret to delete |
scope | user | workspace | yes | Storage scope |
Returns { deleted: true } on success, or { error: "not_found" }.
Using secret references in fetch
Pass the reference returned by set or get wherever a sensitive value is needed in a fetch instruction. The platform resolves it transparently:
do:
# 1. Retrieve the secret reference
- run:
module: secrets
function: get
parameters:
name: myApiKey
scope: workspace
output: secretRef
# 2. Use it in a fetch — the platform injects the real value at execution time
- fetch:
url: https://api.example.com/data
method: GET
headers:
Authorization: "Bearer {{secretRef}}"
output: apiResponse
Resolution is supported in these fetch fields: url, headers, body, query, and auth (including auth.awsv4).
Secret references expire after a few minutes. Always retrieve the reference (secrets.get) in the same automation run where you use it.
Complete example — storing and using an OAuth token
slug: call-with-oauth
name: Call API with OAuth token
do:
# Authenticate and get a token
- fetch:
url: https://auth.example.com/oauth/token
method: POST
body:
grant_type: client_credentials
client_id: "{{config.clientId}}"
client_secret: "{{secret.clientSecret}}"
output: authResponse
# Store the token as a workspace secret with a 1-hour TTL
- run:
module: secrets
function: set
parameters:
name: oauthToken
value: "{{authResponse.access_token}}"
scope: workspace
ttl: 3600
output: tokenRef
# Use the token in subsequent API calls
- fetch:
url: https://api.example.com/resources
method: GET
headers:
Authorization: "Bearer {{tokenRef}}"
output: resources
Error handling
All three functions return an error object instead of throwing when the error is actionable:
| Error | Returned by | Meaning |
|---|
{ error: "not_found" } | get, delete | No secret with that name/scope exists (or it has expired) |
{ error: "user_required" } | set, get, delete | scope: user was used but there is no user context (e.g. cron trigger) |
Use onError or a conditions block to handle these:
- run:
module: secrets
function: get
parameters:
name: myApiKey
scope: workspace
onError: continue
output: result
- conditions:
'{{result.error}}':
- emit:
event: secret-missing
payload:
message: "Secret myApiKey not found"