Skip to content

fix(react-wallet-kit): open OAuth popup before async work - #1472

Open
blockgroot wants to merge 1 commit into
tkhq:mainfrom
blockgroot:fix/1451-oauth-popup-safari
Open

fix(react-wallet-kit): open OAuth popup before async work#1472
blockgroot wants to merge 1 commit into
tkhq:mainfrom
blockgroot:fix/1451-oauth-popup-safari

Conversation

@blockgroot

Copy link
Copy Markdown

Summary & Motivation

Fixes #1451.

OAuth popup login (Discord, X, Google, Apple, Facebook) is silently blocked by Safari's
popup blocker. In all five handlers in
Provider.tsx,
window.open() was called only after await createApiKeyPair() (and, for Discord/X/Facebook,
await generateChallengePair()). Safari revokes a click's user-activation flag as soon as any
await runs after the click handler starts, so by the time window.open() ran, it was no
longer inside a "trusted" user gesture and Safari blocked it — the popup call returned null
and the flow threw Failed to open <Provider> login window. even though the user did click
the login button.

Chrome/Firefox are more lenient about this timing, which is presumably why this shipped
unnoticed.

Fix

Added openOAuthPopupAndNavigate in
utils/oauth/url.ts: it opens the popup
synchronously, then runs the async work needed to build the auth URL (key-pair creation,
nonce, PKCE), and only then navigates the already-open popup to that URL. If the async work
throws, the popup is closed instead of being left open on a blank page (a related rough edge
mentioned in the issue).

Each of the five handlers in Provider.tsx now wraps its key/nonce/PKCE/URL-building logic in
a buildAuthUrl closure and passes it to openOAuthPopupAndNavigate, so the popup opens before
any await in the popup-flow branch. The openInPage (redirect) branch is behaviorally
unchanged — it still awaits buildAuthUrl() and then redirects.

Out of scope

  • Two pre-existing, unrelated issues found while verifying the baseline (left untouched, per
    scope discipline): src/tests/timers-test.ts fails to run because jest-environment-jsdom
    isn't declared as a devDependency of this package, and src/components/auth/wallet/QRCodeDisplay.tsx
    has a stale @ts-expect-error that now fails tsc --noEmit. Both are present on main
    before this change (confirmed via git stash).
  • The issue's optional suggestion of auto-retrying via redirect flow when the popup is blocked
    is left for a follow-up/maintainer decision — it's a UX change beyond fixing the ordering bug.

How I Tested These Changes

Added src/tests/oauth-popup-test.ts covering openOAuthPopupAndNavigate directly (popup
opener and auth-URL builder are injected, so no jsdom/real window is needed):

  • popup opens before buildAuthUrl runs, even when buildAuthUrl resolves after a real
    setTimeout tick (not just a microtask) — proves the ordering fix isn't an artifact of how
    fast the async work happens to resolve.
  • the standard Failed to open <Provider> login window. error is thrown, and buildAuthUrl is
    never called, when the popup is blocked.
  • the popup is closed (not left open on a blank page) when buildAuthUrl rejects.

All three fail with the pre-fix code (openOAuthPopupAndNavigate didn't exist) and pass after.

pnpm --filter @turnkey/react-wallet-kit test
...
PASS src/tests/captcha-test.ts
PASS src/tests/oauth-popup-test.ts
PASS src/tests/oauth-test.ts
PASS src/tests/utils-test.ts
FAIL src/tests/timers-test.ts   (pre-existing, unrelated — see "Out of scope")

Test Suites: 1 failed, 4 passed, 5 total
Tests:       40 passed, 40 total

Also ran (both clean aside from the pre-existing, unrelated issue noted above):

pnpm --filter @turnkey/react-wallet-kit typecheck
pnpm --filter @turnkey/react-wallet-kit build
pnpm prettier --check <changed files>

Did you add a changeset?

Yes — .changeset/quiet-otters-safari-popup.md, @turnkey/react-wallet-kit patch.

Safari revokes a click's user-activation flag as soon as an `await`
runs, so `window.open` gets silently blocked. All five OAuth popup
handlers (Discord, X, Google, Apple, Facebook) opened the popup only
after awaiting key-pair creation and PKCE challenge generation, so
login via popup was broken in Safari.

Add `openOAuthPopupAndNavigate`, which opens the popup synchronously
and only then runs the async work to build the auth URL, closing the
popup instead of leaving it blank if that work throws. Wire it into
all five handlers.

Fixes tkhq#1451
@codesandbox-ci

codesandbox-ci Bot commented Aug 5, 2026

Copy link
Copy Markdown

This pull request is automatically built and testable in CodeSandbox.

To see build info of the built libraries, click here or the icon next to each commit SHA.

Latest deployment of this branch, based on commit dfc1e44:

Sandbox Source
@turnkey/example-react-components Configuration

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.

OAuth popup opened after async work is blocked by Safari popup blocker (window.open after await)

1 participant