Secrets
Quick Answer
Use this guide to declare secret slots, bind secret values, rotate credentials, and wire secret refs into interfaces and steps.
This guide covers secret slots, secret refs, bindings, rotation, and how secrets
are consumed by webhook interfaces and steps.
Core concepts
| Concept | Meaning |
|---|---|
| Secret ref | Secret value stored under a :secret-ref key. |
| Secret slot | Declared in :requires with :type :secret. |
| Binding contract | Bindings map slot to :secret-ref; secret value is stored separately. |
| Source control rule | Flow definitions must never embed secret values. |
Deploy-key guard secret (release control)
Deploy-key guard uses a separate server-side secret for release protection.
| Aspect | Value |
|---|---|
| What it protects | Guarded flow release/promotion paths (flows release, flows promote, and disabling :deploy-key-required). |
| Where it is defined | Breyta environment secret BREYTA_FLOW_DEPLOY_KEY (configured by platform/admin). |
| How CLI provides it | --deploy-key "<value>" or local/CI env BREYTA_FLOW_DEPLOY_KEY when running release commands. |
| Storage model | Global Breyta deployment secret, not a flow :requires slot, bindings secret, or connection. |
| Flow opt-in switch | :deploy-key-required true in flow definition metadata. |
Notes:
- Enabling
:deploy-key-required truefails unlessBREYTA_FLOW_DEPLOY_KEYis configured for the Breyta environment. - Keep this secret in CI/runtime secret manager and inject it per job/session.
Declare a secret slot
Always set an explicit :secret-ref on secret slots.
{:requires [{:slot :webhook-secret
:type :secret
:secret-ref :webhook-secret
:label "Webhook Secret"}]}
Provide a secret value (configure)
For human-entered secrets, prefer Breyta setup/connection UI secret fields and
do not ask for secrets in chat. Protected setup links should return through
login.
Except for documented control sentinels such as :generate, Breyta treats each
submitted <slot>.secret value as new plaintext. It stores the value under the
slot's declared :secret-ref, replacing any value already stored there. A
secret ID or :secret-ref name is not a reuse instruction. Passing one as the
value stores that literal text as the new secret.
For automation or explicit CLI setup, set the secret on the draft target:
breyta flows configure <slug> --set webhook-secret.secret="YOUR_SECRET_VALUE"
To preserve an already-bound target's current secret value, omit the .secret
field entirely. Omission does not bind an unconfigured draft target, even when
the workspace secret store already contains the declared :secret-ref.
Configure only the other required values, then run
breyta flows configure check <slug>. Do not pass the secret ID as the value.
Generate a new secret value
Use :generate to create a secret value server-side:
{:bindings {:webhook-secret {:secret :generate}}}
Secret Lifecycle (CLI)
| Stage | Command / action | Result |
|---|---|---|
| Human setup | Enter the value in the setup/connection UI secret field | Stores the secret without chat/source exposure |
| Create or replace value | breyta flows configure <slug> --set <slot>.secret="VALUE" | Stores the submitted plaintext under the slot's :secret-ref, replacing the previous value |
| Preserve already-bound value | Omit <slot>.secret | Preserves the target's existing binding and value; does not bind an unconfigured draft target |
| Generate value | breyta flows configure <slug> --set <slot>.secret=:generate | Server generates and stores secret value. |
| Rotate | Re-run flows configure with updated secret value | Replaces value under same :secret-ref. |
After applying generated secrets, inspect the target profile/bindings metadata.
If a live profile still reports no secret bindings, configure the slot
explicitly:
breyta flows configure <slug> --target live --version latest --set webhook-secret.secret=:generate
Re-run breyta flows configure check <slug> --target live --version latest and
a live-shaped smoke test before trusting webhook auth or secret-backed steps.
Configure check reports secret slots alongside connection slots:
requiredSecretSlots, configuredSecretSlots, and missingSecretSlots.
Required secret slots keep ready false until the target has a secret binding
or the declared secret ref passes the current presence check. Optional secret
slots (:optional true or :required false) do not block readiness. A
configured slot proves only that configuration metadata is present. It does not
prove that a referenced secret still exists or that its value is valid. Run a
provider-specific, read-only smoke test to prove the credential works.
Author-provided secrets in installable apps
For a public or installable app, use :provided-by :author for a platform
credential that the app owner supplies once. Breyta resolves it from the
author workspace at runtime and does not show it in installer setup. Keep each
customer's account connection, including OAuth, :provided-by :installer.
For example, a Google Ads app can combine installer OAuth with an author-owned
developer token:
{:requires [{:slot :google-ads
:type :http-api
:provided-by :installer
:base-url "https://googleads.googleapis.com"
:oauth {:provider :google
:scopes {:required
["https://www.googleapis.com/auth/adwords"]}
:requires-refresh-token true}}
{:slot :google-ads-developer-token
:type :secret
:secret-ref :google-ads-developer-token
:provided-by :author}]}
The HTTP step uses the installer connection for OAuth and resolves the
author-owned token in a separate header:
{:connection :google-ads
:headers {"developer-token"
{:secret-ref :google-ads-developer-token}}}
Configure the author-owned secret on the author's live target before release.
Then verify a fresh installation asks for the customer OAuth connection but
does not display the author-owned secret.
Rotate a secret
- Apply the new secret value with
flows configure. - Re-run to store the new value under the same
:secret-ref. - Update external systems to use the new secret.
breyta flows configure <slug> --set webhook-secret.secret="NEW_SECRET_VALUE"
Using secrets in webhook auth
Auth configs reference secrets via :secret-ref:
{:auth {:type :api-key
:header "X-API-Key"
:secret-ref :webhook-secret}}
Service account JSON secrets (Google APIs)
Some integrations need a full JSON service account key (not a single token string). Store the entire JSON payload as a secret value and reference it via :secret-ref.
Declare the slot:
{:requires [{:slot :google-drive-service-account
:type :secret
:secret-ref :google-drive-service-account
:label "Google Drive service account JSON"}]}
Bind the value (prod):
{:bindings {:google-drive-service-account {:secret "<SERVICE_ACCOUNT_JSON>"}}}
Use it in an HTTP step auth block:
{:auth {:type :google-service-account
:secret-ref :google-drive-service-account
:scopes ["https://www.googleapis.com/auth/drive.readonly"
"https://www.googleapis.com/auth/drive.metadata.readonly"]}}
{:auth {:type :hmac-sha256
:header "X-Signature"
:secret-ref :webhook-secret}}
{:auth {:type :basic
:username "webhook-user"
:secret-ref :webhook-basic-password}}
Common mistakes
| Mistake | Consequence |
|---|---|
Omitting :secret-ref on secret slot | Validation/runtime binding failures. |
| Putting secret values in flow definitions | Secret leakage risk in source and review surfaces. |
Passing a secret ID or :secret-ref name to <slot>.secret | Replaces the real value with that literal text while the slot can still appear configured |
Mismatching interface auth :secret-ref and slot :secret-ref | Auth checks fail at runtime. |
| Assuming generated secrets were stored without inspecting target bindings | Live webhook auth or secret-backed steps can fail at runtime. |