[wrangler] Show OAuth callback errors instead of hanging on wrangler login#14022
Merged
Conversation
🦋 Changeset detectedLatest commit: d8510ee The changes in this PR will be included in the next version bump. This PR includes changesets to release 5 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
Contributor
|
Codeowners approval required for this PR:
Show detailed file reviewers
|
Contributor
|
The review has been posted to PR #14022. I flagged one issue:
|
create-cloudflare
@cloudflare/deploy-helpers
@cloudflare/kv-asset-handler
miniflare
@cloudflare/pages-shared
@cloudflare/unenv-preset
@cloudflare/vite-plugin
@cloudflare/vitest-pool-workers
@cloudflare/workers-auth
@cloudflare/workers-editor-shared
@cloudflare/workers-utils
wrangler
@cloudflare/wrangler-bundler
commit: |
Contributor
Changeset ReviewFile:
|
Member
|
@petebacondarwin Sorry for the late review! It looks like a lot of these changes are now stale as we moved the logic to the new package in #14121. Happy to give it a review right away when you resolve the conflicts 🙏🏼 |
… login` When the OAuth provider redirected to `/oauth/callback` with an `error` other than `access_denied`, Wrangler never wrote a response to the browser. Because `server.close()`'s callback only fires once all open connections have ended, the login command would hang until the 120s OAuth timeout — at which point it printed a generic timeout message rather than the actual OAuth failure. The same gap existed for the no-auth-code case and for failures during the auth-code-to-access-token exchange. The OAuth provider's `error_description` (RFC 6749 §4.1.2.1) is also now surfaced, so the user sees the specific reason rather than just the bare `error` code. The mock HTTP server used in unit tests is tightened to faithfully reproduce the production `server.close()` semantics so regressions are caught instead of papered over.
- Change `throw new Error(json.error)` in `exchangeAuthCodeForAccessToken` to `throw toErrorClass(json.error)` so the 2xx-with-error-body path produces a structured `ErrorOAuth2` like the 4xx path already does. - Make the callback handler's token-exchange catch defensive: only read the structured `code`/`description` fields when the error is actually an `ErrorOAuth2` instance, so JSON parse failures from `getJSONFromResponse` and network errors from `fetchAuthToken` still render with a useful message rather than empty fields. - Add a regression test for the 2xx-with-error-body path.
bb8c1de to
a43628c
Compare
Contributor
|
Codeowners approval required for this PR:
Show detailed file reviewers |
The OAuth callback fix now lives in @cloudflare/workers-auth (since PR #14121 extracted the OAuth flow out of wrangler). Add the package to the changeset so its CHANGELOG reflects the fix too.
edmundhung
reviewed
Jun 3, 2026
edmundhung
approved these changes
Jun 3, 2026
workers-devprod
approved these changes
Jun 3, 2026
workers-devprod
left a comment
Contributor
There was a problem hiding this comment.
Codeowners reviews satisfied
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
When
wrangler loginis rejected by the Cloudflare OAuth provider — for example when the provider doesn't support a scope Wrangler is requesting — the OAuth callback redirects tohttp://localhost:8976/oauth/callback?error=.... Previously, for any error other thanaccess_denied, Wrangler:res.end().server.close(), which only fires its callback once all open connections have ended.server.close()never completed.Net effect: the real OAuth error was silently swallowed and Wrangler hung for two minutes.
This PR:
Always writes an HTTP response on every OAuth callback exit path (a minimal inline HTML error page for non-
access_deniederrors, mirroring howaccess_deniedalready redirects to a hosted "consent denied" page). The same fix covers the previously-broken no-auth-code branch (// render an error page here) and a now-try/catch-wrapped token-exchange branch.Reads
error_descriptionanderror_urifrom the OAuth callback query string (RFC 6749 §4.1.2.1) and includes them in the surfaced error so the user sees the specific reason. For example a misconfigured scope now surfaces as:instead of hanging silently.
Adds a defensive
if (!res.writableEnded) res.end()infinish()so a future code path that forgets to send a response can't reintroduce the hang.Tightens
mock-http-server.tsto faithfully reproduce productionserver.close()semantics (its callback only fires onceres.end()has been observed). Without this, tests for the broken behaviour would pass by accident because the mock'sclose()fired its callback unconditionally.Adds tests for
invalid_scope(with and withouterror_description),access_denied(previously untested), and a token-exchange failure on the success path.