## TL;DR

The token authenticates fine but is not authorized to write workers. Cloudflare API tokens are scoped per resource, and a token created for DNS or zone reads cannot deploy. Create a token with the Workers permissions the operation needs (workers:write for deploy, plus KV/D1/R2 scopes for storage ops), rotate it into the environment, and retry.

## The query

```text
wrangler auth failed: API token missing the workers:write permission
```

## Use this when

- `wrangler whoami` works but `wrangler deploy` fails with a permissions error.
- The token was created for a different purpose (DNS, analytics) and reused.
- CI started failing after someone recreated the token with fewer scopes.

## Not for

- 'authentication error, check your API token' (token invalid, not under-scoped).
- Tokens that expired (rotation problem, separate fix).
- OAuth login failures in interactive sessions.

## Steps

### Step 1: Confirm the token identity and its failure mode

```bash
npx wrangler whoami
npx wrangler deploy --dry-run
```

Expected result: whoami succeeds, deploy fails naming permissions. That split proves auth works and scope is the problem.

### Step 2: Create a correctly scoped token

In the Cloudflare dashboard under API tokens, create a token with Account / Workers Scripts / Write (workers:write), and add KV, D1, R2, or Queue scopes only for the storage the worker uses. Scope it to the specific account, not all accounts.

Expected result: a new token whose permission list covers every wrangler operation the project runs (deploy, secret put, tail, d1 execute).

### Step 3: Rotate the token in the environment

Replace the old token value in CI secrets and in local shell config. Never paste the token into chat, tickets, or the repo.

Expected result: the environment holds only the new token. Old sessions using the previous value keep failing until they pick up the new one.

### Step 4: Verify end to end

```bash
npx wrangler whoami
npx wrangler deploy --dry-run
```

Expected result: both succeed. The dry run passing means the token can read config, resolve the account, and would be allowed to publish.

### Step 5: Deploy

```bash
npx wrangler deploy
```

Expected result: the deploy completes. If a later operation (secret rotation, D1 migration) fails on permissions, add that scope to the token template too.

## Why it happens

Least-privilege token templates are the default recommendation, so teams create minimal tokens and then reuse them for operations outside the original scope. The failure is confusing because login succeeds; only the write path is denied. Rotation events also silently drop scopes when someone recreates the token from memory instead of from the documented template.

## Edge cases

- Document the token template (exact scopes) in the deploy runbook. Every future rotation copies the template instead of improvising.
- Tokens scoped to 'All accounts' are a smell. Scope to the one account the project deploys to.
- `wrangler login` OAuth tokens carry broad permissions and mask this problem locally while CI fails. Always test CI's token, not your own.
- Some operations need zone-level scopes (custom domains, routes) in addition to account-level worker scopes. Add them when route management is part of the deploy.

## Provenance

Resolved from the public thread: https://vectle.com/posts/pst_X567pMmMwLJAYNdcqGyQRg
