Skip to content

feat: support wrangler OAuth credentials for deploy --remote - #3

Merged
jonasnobile merged 2 commits into
mainfrom
feat/oauth-deploy
Jun 21, 2026
Merged

jonasnobile merged 2 commits into
mainfrom
feat/oauth-deploy

Conversation

@jonasnobile

@jonasnobile jonasnobile commented Jun 21, 2026 •

Copy link
Copy Markdown
Member

Previously deploy --remote required a CLOUDFLARE_API_TOKEN. Cloudflare's
REST API accepts an OAuth access token as a Bearer token identically to an
API token, so we can authenticate with the credentials wrangler login
already stores on disk.

  • CloudflareClient now takes a getToken() provider instead of a static
    token, fetched per request so a refreshed token is picked up mid-run.
  • New src/auth.ts reads wrangler's default.toml (mirroring its config-path
    resolution), returns the access token while valid, and refreshes via the
    OAuth token endpoint when expired — persisting the rotated token back to
    the same file so wrangler stays in sync.
  • deploy.ts prefers an explicit --api-token / CLOUDFLARE_API_TOKEN and falls
    back to OAuth; run.ts accepts either for the --remote credential check.

API-token and CI behavior are unchanged. account_id is still required.

Verification (live, throwaway env)

Ran self-cleaning create→delete probes using real wrangler login OAuth creds
against the nobile account to settle whether the login scopes cover resources
oblaka provisions (the open question was D1/R2/Vectorize, which have no dedicated
scope in wranglerʼs login set):

Resource Create Cleanup
D1 200 200
Queues 200 200
Vectorize 201 200
R2 403 (product not enabled on this account) —
  • D1 and Vectorize are authorized under OAuth despite having no dedicated scope —
    Cloudflare authorizes them via account membership.
  • The R2 403 was a product-not-enabled message, not an auth rejection, so it is
    not conclusive; indirect evidence (a product-level error rather than a 9109-style
    auth error) suggests the token is scope-accepted. Not retested on an R2-enabled
    account.
  • GET /accounts → 200 confirms the token-provider path end-to-end; cleanup left
    0 leftover resources.

jonasnobile and others added 2 commits June 21, 2026 14:40
Previously `deploy --remote` required a CLOUDFLARE_API_TOKEN. Cloudflare's
REST API accepts an OAuth access token as a Bearer token identically to an
API token, so we can authenticate with the credentials `wrangler login`
already stores on disk.

- CloudflareClient now takes a `getToken()` provider instead of a static
  token, fetched per request so a refreshed token is picked up mid-run.
- New src/auth.ts reads wrangler's default.toml (mirroring its config-path
  resolution), returns the access token while valid, and refreshes via the
  OAuth token endpoint when expired — persisting the rotated token back to
  the same file so wrangler stays in sync.
- deploy.ts prefers an explicit --api-token / CLOUDFLARE_API_TOKEN and falls
  back to OAuth; run.ts accepts either for the --remote credential check.

API-token and CI behavior are unchanged. account_id is still required.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Addresses review feedback on the wrangler OAuth support:

- Guard against a malformed token-endpoint response: a 200 missing
  access_token/expires_in now throws a clear "wrangler login" error
  instead of crashing on `new Date(NaN).toISOString()` or emitting a
  `Bearer undefined` header.
- Persist refreshed tokens via in-place line replacement so comments,
  the scopes line, and any future wrangler fields survive the rewrite
  (the previous serializer reconstructed the file from known keys only).
- Add `--no-persist-token` to opt out of writing the refreshed token
  back to wrangler's config (e.g. read-only credential dirs).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@jonasnobile
jonasnobile merged commit 535f877 into main Jun 21, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant