Secrets & credentials

Secrets & credentials

Never put a password, API key, or token literally in a job file — job YAML is the source of truth and is synced to git. Instead, Cronable keeps sensitive values in encrypted stores and you reference them by name. There are three kinds of stored values:

StoreForReference asEncrypted?
Variablesnon-secret config (a region, a base URL){{ $vars.region }}no
Secretsanything that grants access (keys, tokens, PWs){{ $secrets.api_key }}yes
Credentialstyped, reusable connections for a job type{{ $credentials.myapi.token }}yes

All three are managed from Settings → Secrets. See Expressions & data flow for how {{ }} resolves them at run time.

Secrets

A secret is a single named value — an API key, a bearer token, a webhook URL, a password. Reference it anywhere expressions are allowed as {{ $secrets.NAME }}.

  • Encrypted at rest with AES-256-GCM (a key derived from your CRONABLE_ENCRYPTION_KEY), and masked to *** in run logs, stored output, and the live stream. The UI and API only ever return a secret’s name and scope — never its value.
  • Scope: a secret is either global (visible to every job) or job-scoped (visible only to one job). When a job runs, it sees the global set plus its own — a job-scoped secret can override a global one of the same name.

Credentials

A credential is a typed, reusable connection — the set of fields a job type needs to talk to a service, stored once and referenced by name. Each has a kind that fixes its fields; the sensitive field(s) are encrypted and masked exactly like a secret, while identifying fields (a username, a header name) are not. Credentials are global — any job can reference any credential by name.

Most job types that talk to a service take a credential field naming the credential to use; you can also read a field directly with {{ $credentials.NAME.field }}. The kinds:

GroupKinds
HTTP authapi_key, bearer, basic, header — for an http job’s authScheme
Databasespostgres, mysql, mssql — one connection string each, for the database job
Messaging / SaaSslack, telegram, twilio (SMS), imap (the inbox trigger), google_service_account (Sheets/Calendar jobs + watchers)
Object storagesftp, s3 — for a file job’s remote transfers
AIanthropic, openai — optional; blank falls back to the daemon’s ANTHROPIC_API_KEY / OPENAI_API_KEY

The full field list per kind (and which field is the secret) is in the app’s Add credential form.

Back up your encryption key

Your CRONABLE_ENCRYPTION_KEY protects every stored secret and credential. Back it up separately from the database. Lose it and those values are unrecoverable by design — there is no recovery path. Keep it in the environment only, never in the jobs repo. See Security.

Masking is best-effort

Resolved secret values are redacted from logs, output, and the stream. But masking can only catch the literal value — a command that transforms a secret (base64, slicing) before printing it can still leak it. Don’t print secrets.