agentleFS
okayusokayus/okayus-skills/skills/cloudflare-api-token-permissions/SKILL.md

cloudflare-api-token-permissions

Skill0 starsChanged 5 days agoMITView on GitHub

Map a Cloudflare CI deploy auth error (code 10000 / 7403 / 9106) to the missing API token permission, and show how to extend the token in-place without regenerating its value (so the GitHub Secret stays untouched). Use when `wrangler deploy` or `wrangler d1 migrations apply` fails in GitHub Actions with `Authentication error`, or when adding a new binding (`r2_buckets` / `kv_namespaces` / `queues` / `vectorize` / `hyperdrive`) to `wrangler.jsonc` and the deploy starts failing in CI even though it works locally. Covers the permission matrix per binding, the "Edit Cloudflare Workers" template's silent omission of D1 / Queues / Vectorize, and the diagnostic flow when multiple permissions are missing.

The file

We split this skill into the rules it gives an agent

11 rules. About 0 are common, 4 are distinctive, and 7 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈4

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 7

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    When wrangler deploy (or wrangler d1 migrations apply) fails in CI with code: 10000, code: 7403, or code: 9106, the cause is almost always: …

    line 13
  2. Distinctive:

    Add the missing permission row → Continue to summary → Update Token

    line 99
  3. Very specific:

    If you have multiple tokens in your account and aren't sure which value lives in CLOUDFLARE_API_TOKEN:

    line 105
  4. Very specific:

    If you can't tell, rotate: create a fresh token with the full matrix, gh secret set CLOUDFLARE_API_TOKEN, delete the old one.

    line 110
  5. Distinctive:

    Look up the code in the *Error code → missing permission* table above

    line 115
  6. Very specific:

    If a new code: <different number> appears, repeat from step 2 (cumulative permissions across the deploy stages — e.g.

    line 118
  7. Very specific:

    If the same code persists, check that the token you edited is actually the one in CLOUDFLARE_API_TOKEN (see *Identifying which token is the …

    line 119
  8. Distinctive:

    Create a new token with the full permission matrix above (Custom Token, not the template)

    line 130
  9. Very specific:

    Update the GitHub Secret: gh secret set CLOUDFLARE_API_TOKEN -R <owner>/<repo> and paste the value

    line 132
  10. Distinctive:

    Delete the old token in the Cloudflare dashboard (avoids accumulation of stale tokens)

    line 133
  11. Very specific:

    Deploying via wrangler deploy --account-id <id>: instead of via secret: same permission requirements, just authenticated differently.

    line 140

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Cloudflare API Token Permissions

When wrangler deploy (or wrangler d1 migrations apply) fails in CI with code: 10000, code: 7403, or code: 9106, the cause is almost always: the GitHub Secret CLOUDFLARE_API_TOKEN is missing a permission for a binding or operation that wrangler.jsonc references.

Adding a binding to wrangler.jsonc doesn't fail locally (your wrangler login session has full account access), but CI's narrow API token does. The error surfaces only when CI runs — typically after the PR is already merged.

When to use this skill

  • A CI wrangler deploy job that previously succeeded now fails with Authentication error [code: 10000] / [code: 7403] / [code: 9106]
  • You're about to add a binding (r2_buckets, kv_namespaces, queues, vectorize, hyperdrive, ai, browser) to wrangler.jsonc and want to predict whether the token needs an extension
  • Token rotation: the secret value leaked or expired and needs replacement
  • You used the Edit Cloudflare Workers template to create a token and need to verify what's actually included (it omits D1 / Queues / Vectorize — see below)

Error code → missing permission

First error in deploy logCloudflare API path that failedMissing permission
Authentication error [code: 10000]/accounts/<id>/r2/buckets/<name>Account / Workers R2 Storage / Edit
not authorized [code: 7403]/accounts/<id>/d1/database/<id>/queryAccount / D1 / Edit
Authentication failed [code: 9106]/membershipsNot a missing permission — see the 9106 note below this table
Authentication error [code: 10000]/accounts/<id>/workers/scripts/<name>Account / Workers Scripts / Edit
Authentication error [code: 10000]/accounts/<id>/storage/kv/namespaces/<id>Account / Workers KV Storage / Edit
Authentication error [code: 10000]/accounts/<id>/queues/<id>Account / Queues / Edit

The first error in the log is the actionable one; subsequent errors are usually consequences of the first failed auth call. Fix the first one and the rest disappear.

The 9106-on-/memberships special case (verified 2026-08-08): 9106 is not a permission-missing code. It means a user-level endpoint was called without a user identity — either the token is an Account owned token (which structurally cannot call /memberships; wrangler ≥ 4.90 auto-falls back to /accounts), or the credential env var itself is broken. A user token that merely lacks the scope fails with code: 10000 instead, and that one is fixed by User / Memberships / Read (User scope — Account Settings / Read covers /accounts, not /memberships). The durable fix either way: set account_id in wrangler.jsonc (or CLOUDFLARE_ACCOUNT_ID in CI) so wrangler skips the account-resolution endpoints entirely.

Permission matrix (binding / command → required permission)

Binding or wrangler commandRequired token permission
wrangler deploy core (Worker upload)Account / Workers Scripts / Edit
wrangler d1 migrations apply --remoteAccount / D1 / Edit
wrangler d1 export --remote (backup)Account / D1 / Edit (Read may suffice; Edit is the safe pick)
r2_buckets binding (existence check on deploy)Account / Workers R2 Storage / Edit
kv_namespaces bindingAccount / Workers KV Storage / Edit
queues.producers / queues.consumers bindingAccount / Queues / Edit
vectorize bindingAccount / Vectorize / Edit
hyperdrive bindingAccount / Hyperdrive / Edit
ai (Workers AI) bindingAccount / Workers AI / Read
browser (Browser Rendering) bindingAccount / Browser Rendering / Edit
Memberships lookup (only fires when account_id is not set)User / Memberships / Read (User scope) — or set account_id so the call never happens

For the typical small-app stack (SPA + API + D1 + R2 served from one Worker), the minimum token permission set is:

  • Account / Workers Scripts / Edit
  • Account / D1 / Edit
  • Account / Workers R2 Storage / Edit
  • Account Resources: <your specific account> (don't grant All accounts unless you have a reason)

…plus account_id set in wrangler.jsonc (or CLOUDFLARE_ACCOUNT_ID in CI). With it, wrangler never calls the account-resolution endpoints (/accounts, /memberships) that would otherwise drag in Account Settings / Read / User / Memberships / Read.

The "Edit Cloudflare Workers" template trap

Cloudflare offers a one-click template named Edit Cloudflare Workers. It looks complete but silently omits D1, Queues, and Vectorize — products added after the template was originally set. (The template does get occasional refreshes — R2 is included nowadays — so re-verify against the template reference when in doubt.)

What the template includes (verified 2026-08-07):

  • Workers Scripts / Edit
  • Workers KV Storage / Edit
  • Workers R2 Storage / Edit
  • Workers Tail / Read
  • Workers Routes / Edit
  • Account Settings / Read
  • User Details / Read (User scope)
  • Memberships / Read (User scope)

What you must add manually if your wrangler.jsonc uses them:

  • D1 / Edit
  • Queues / Edit
  • Vectorize / Edit
  • Hyperdrive / Edit

Recommendation: skip the template. Use Create Custom Token and pick exactly what you need from the matrix above. Faster than auditing the template's gaps.

In-place permission edit (keeps the token value)

A common misconception: editing a Cloudflare API Token's permissions regenerates its value, requiring a GitHub Secret update.

It doesn't. Cloudflare keeps the same token value when you edit permissions; only rotating (deleting + recreating) generates a new value.

Workflow:

  1. https://dash.cloudflare.com/profile/api-tokens
  2. Locate the token used by GitHub Actions (sort by Last Used — CI tokens are touched on every main push)
  3. Click Edit (not "Roll")
  4. Add the missing permission row → Continue to summary → Update Token
  5. Token value unchanged → no GitHub Secret update needed
  6. Re-run the failed CI: gh run rerun <run-id> --failed

Identifying which token is the CI token

If you have multiple tokens in your account and aren't sure which value lives in CLOUDFLARE_API_TOKEN:

  • The GitHub Secret value is one-way encrypted — not retrievable
  • gh secret list -R <owner>/<repo> only shows the updatedAt timestamp; correlate with the Cloudflare token's Created / Last Used timestamps
  • Cloudflare dashboard sorts tokens by Last Used. The most-recently-used should be the CI token (Actions runs on every main push)
  • If you can't tell, rotate: create a fresh token with the full matrix, gh secret set CLOUDFLARE_API_TOKEN, delete the old one. Avoids a long bisect.

Diagnostic flow when CI deploy fails

  1. gh run view <run-id> --log-failed → find the first [ERROR] code: <number> line
  2. Look up the code in the Error code → missing permission table above
  3. Edit the token's permissions in-place (value stays the same)
  4. gh run rerun <run-id> --failed
  5. If a new code: <different number> appears, repeat from step 2 (cumulative permissions across the deploy stages — e.g. R2 binding check fails first → fix R2 → D1 migrations apply fails next → fix D1)
  6. If the same code persists, check that the token you edited is actually the one in CLOUDFLARE_API_TOKEN (see Identifying which token is the CI token above) — most common cause of "I added the permission but it still fails"

When you do need to rotate (regenerate)

  • The secret value leaked publicly
  • Cloudflare flagged the token as compromised
  • The token expired (if you set a TTL when creating)
  • You can't tell which token the CI uses (rotate to break the ambiguity)

In that case:

  1. Create a new token with the full permission matrix above (Custom Token, not the template)
  2. Copy the new value (shown once)
  3. Update the GitHub Secret: gh secret set CLOUDFLARE_API_TOKEN -R <owner>/<repo> and paste the value
  4. Delete the old token in the Cloudflare dashboard (avoids accumulation of stale tokens)
  5. Re-run the failed CI

What this skill does NOT cover

  • Local wrangler login session permissions — wrangler login uses OAuth and grants full account access; it never has the narrow-permission problem. Only CI tokens hit this.
  • R2 bucket-scoped object access tokens (S3-compatible API): those are a different token type (created under R2 → Manage R2 API Tokens) and unrelated to CI deploy. Workers R2 Storage binding uses the account API token, not the bucket-scoped one.
  • Deploying via wrangler deploy --account-id <id> instead of via secret: same permission requirements, just authenticated differently.

Related skills

  • cloudflare-workers-deploy-skeleton — initial project setup. The token created during that skill should already follow this matrix from day 1; consult this skill when adding new bindings later.
  • cloudflare-d1-drizzle-migration — D1 migration pitfalls (PRAGMA foreign_keys=OFF ignored). Needs D1 / Edit.
  • cloudflare-d1-weekly-backup-via-pr — weekly D1 backup workflow. Reuses the same CLOUDFLARE_API_TOKEN (no new token needed if the matrix is met).
  • cloudflare-workers-builds-keyless-deploy — the alternative that removes this whole problem class: deploy via Workers Builds with no Cloudflare token in GitHub at all. Its default build token has the same flavor of trap (D1 Edit missing).

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.