▸ Agent Skills
5 min read

Cloudflare Secrets Store provider

Publish SecretSpec values to Cloudflare account-level Secrets Store

New in version 0.20

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

At a glance

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

Quick start

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

$ 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" }
# 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.

Setup

Prerequisites

New in version 0.20

  • 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.

Wrangler authentication

New in version 0.20

With auth=wrangler, SecretSpec runs:

$ 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

New in version 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:

$ 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.

Environment fallback

New in version 0.20

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.

Provider credentials

CredentialEnvironment fallbackAvailable since
api_tokenCLOUDFLARE_API_TOKEN0.20+

In 0.21+, credentials retain their exact bytes during resolution. Interfaces that require text validate UTF-8 when consuming the credential; invalid input returns an error without selecting an environment fallback. Unix CLI environments accept non-UTF-8 bytes, but cannot contain NUL bytes. A configured credential that resolves to an empty value is an error rather than a fall through to the environment.

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

Configuration

URI format

New in version 0.20

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.

URI examples

New in version 0.20

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

Storage model

New in version 0.20

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.

Use existing secrets

New in version 0.20

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.

Discover secret names

New in version 0.20

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

$ 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.

CI/CD

New in version 0.20

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

New in version 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.

Last updated Oct 11, 2026