Skip to content

Cloudflare Secrets Store provider

The Cloudflare provider publishes declared values to an account-level Cloudflare Secrets Store through the Cloudflare REST API.

Providercloudflare (0.20+)
URIcloudflare://STORE_ID[?account_id=ACCOUNT_ID][&OPTIONS]
AccessWrite, delete, and discover names; plaintext values cannot be read back
Best forPublishing secrets to Workers and other Cloudflare services from a separate source of truth
AuthenticationAPI token or credentials from wrangler auth token --json
AvailabilitySecretSpec 0.20+; included in official and default builds (cloudflare feature for custom minimal builds)
Default storageAccount secret named {key} in the selected store

Find the account ID and Secrets Store ID in the Cloudflare dashboard or with Wrangler, then authenticate and configure an alias:

Terminal window
$ wrangler login
$ wrangler secrets-store store list --remote
secretspec.toml
[providers]
cloudflare_prod = "cloudflare://0123456789abcdef0123456789abcdef?account_id=abcdef0123456789abcdef0123456789&auth=wrangler"
[profiles.production]
DATABASE_URL = { description = "Production database URL" }
Terminal window
# Publish or replace the account secret
$ secretspec set DATABASE_URL --profile production --provider cloudflare_prod
# Remove it
$ secretspec delete DATABASE_URL --profile production --provider cloudflare_prod

Cloudflare never returns plaintext through its management API, so secretspec get, check, and run cannot resolve a value from this provider. Keep the authoritative value in a readable provider and select cloudflare_prod explicitly when publishing it.

  • SecretSpec 0.20 or newer
  • A Cloudflare account with a Secrets Store
  • Account Secrets Store Write permission for publishing and deletion
  • The account ID and Secrets Store ID

The official SecretSpec CLI includes this provider. Custom minimal Rust builds enable it with --features cloudflare.

With auth=wrangler, SecretSpec runs:

Terminal window
$ wrangler auth token --json

Wrangler can return an API token, a refreshed OAuth token from wrangler login, or legacy API-key/email credentials. SecretSpec uses the returned credential only in HTTPS request headers. It never passes the account secret value to Wrangler.

Wrangler supports named authentication profiles:

cloudflare://STORE_ID?account_id=ACCOUNT_ID&auth=wrangler&wrangler_profile=production

If the executable has another name or location, set SECRETSPEC_WRANGLER_PATH. SecretSpec never invokes npx automatically.

Authentication with provider credentials (0.20+)

Section titled “Authentication with provider credentials (0.20+)”

For CI or a machine identity, declare the api_token provider credential:

secretspec.toml
[providers]
bootstrap = "keyring://"
[providers.cloudflare_prod]
uri = "cloudflare://0123456789abcdef0123456789abcdef?account_id=abcdef0123456789abcdef0123456789&auth=token"
credentials = { api_token = "bootstrap" }

Store it once:

Terminal window
$ secretspec config provider login cloudflare_prod
Enter api_token for provider 'cloudflare_prod' (source: bootstrap): ****

Use a scoped user or account API token with Secrets Store Write on only the required account. Do not use the full-access Global API Key for new setups.

CLOUDFLARE_API_TOKEN supplies the api_token credential when no explicit provider credential exists. CLOUDFLARE_ACCOUNT_ID supplies the account ID when the URI omits account_id.

The default auth=auto uses the provider credential or CLOUDFLARE_API_TOKEN first, then falls back to Wrangler. Use auth=token to require a token or auth=wrangler to require Wrangler credentials.

Credential Environment fallback Available since
api_token CLOUDFLARE_API_TOKEN 0.20+

See the complete provider credential reference for all supported providers and environment fallbacks.

cloudflare://STORE_ID[?account_id=ACCOUNT_ID][&scopes=LIST][&auth=MODE][&wrangler_profile=NAME]
  • STORE_ID is required and selects the account-level Secrets Store.
  • account_id selects the Cloudflare account and falls back to CLOUDFLARE_ACCOUNT_ID.
  • scopes is a comma-separated list applied when a secret is created or replaced. It defaults to workers. Supported values are workers, ai_gateway, dex, access, containers, and websearch.
  • auth is auto (default), token, or wrangler.
  • wrangler_profile selects a named Wrangler auth profile and requires auth=wrangler.
cloudflare://STORE_ID?account_id=ACCOUNT_ID
cloudflare://STORE_ID?account_id=ACCOUNT_ID&auth=token
cloudflare://STORE_ID?account_id=ACCOUNT_ID&auth=wrangler
cloudflare://STORE_ID?account_id=ACCOUNT_ID&scopes=workers,containers
cloudflare://STORE_ID?account_id=ACCOUNT_ID&auth=wrangler&wrangler_profile=production

The provider maps a declaration key directly to an account-secret name. For example, DATABASE_URL maps to:

account: ACCOUNT_ID
store: STORE_ID
secret: DATABASE_URL

Project and profile names are not added to the secret name. The store selected by the provider alias supplies isolation. Use a different alias and store when two profiles must hold different values for the same key.

Cloudflare Workers can bind that account secret to any binding name; the SecretSpec key does not need to match the Worker’s binding variable.

A ref changes the Cloudflare secret name updated or deleted by SecretSpec:

secretspec.toml
[profiles.production]
DATABASE_URL = {
description = "Production database URL",
ref = { item = "PRIMARY_DATABASE_URL" }
}

The reference remains write-only: it can select an existing name but cannot retrieve its plaintext value.

Cloudflare’s list API exposes names, IDs, scopes, comments, and status without returning values. SecretSpec uses that metadata for declaration discovery:

Terminal window
$ secretspec init \
--from 'cloudflare://STORE_ID?account_id=ACCOUNT_ID&auth=wrangler' \
--project my-app --profile production

The generated manifest contains required declarations for active or pending secret names, not defaults or values.

Use a short-lived or account-owned token scoped to Secrets Store Write:

- run: secretspec set DATABASE_URL --profile production --provider cloudflare_prod
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}

The account ID and store ID are attribution, not credentials, and can stay in the checked-in provider URI.

Security considerations and limitations (0.20+)

Section titled “Security considerations and limitations (0.20+)”
  • Cloudflare’s management API accepts values for creation and replacement but never returns them. Plaintext access exists only inside a Cloudflare service with a Secrets Store binding. This provider therefore cannot support get, check, run, fallback reads, generation-on-miss, prompting-on-miss, or value comparisons.
  • Secret values are serialized directly into an HTTPS request body. They do not appear in the provider URI, command arguments, Wrangler input, or SecretSpec diagnostics.
  • HTTP redirects are rejected so credentials and secret-bearing request bodies remain confined to Cloudflare’s API origin.
  • secretspec set lists metadata to resolve an existing name to the secret ID, then creates or patches it. secretspec delete uses the same metadata lookup and remains idempotent when the name is absent.
  • A replacement applies the scopes configured in the provider URI. Review those scopes because changing them affects which Cloudflare services may bind the secret.
  • Secret values cannot exceed Cloudflare’s 65,536-byte limit.
  • Cloudflare Secrets Store is currently a beta service; API behavior and scope availability may change upstream.