Skip to content

feat(cef): open OAuth popups as native windows (fixes Google/Firebase sign-in)#22

Merged
wenkaifan0720 merged 1 commit into
mainfrom
feat/native-auth-popup
Jul 15, 2026
Merged

feat(cef): open OAuth popups as native windows (fixes Google/Firebase sign-in)#22
wenkaifan0720 merged 1 commit into
mainfrom
feat/native-auth-popup

Conversation

@wenkaifan0720

Copy link
Copy Markdown
Collaborator

Problem

Signing into a site with Google inside a CEF webview hangs — e.g. stuck at https://accounts.google.com/gsi/transform. Logging into google.com/YouTube directly works.

Root cause: the OSR host's OnBeforePopup cancels every popup (return true) and forwards the URL to the host to load in the same view. That's fine for target=_blank links, but popup-based OAuth (Google Identity / Firebase signInWithPopup) opens a real popup that authenticates, then postMessages the credential back to window.opener and closes. Loaded in-place, there's no opener and the original page is gone → the transform/handler page has nothing to message → hang.

Confirmed via CDP with a synthetic user gesture: window.open(...) returned null (popup cancelled), the URL was diverted to the host, and no popup window was ever created.

Fix

For a sized popup (WOD_NEW_POPUP — the shape OAuth uses), let CEF create a real popup browser hosted windowed in a transient NSWindow (SetAsChild). window.opener / postMessage / window.close all work natively, and it shares the parent's request context (cookie jar) so an existing Google session is recognized. Plain target=_blank / new-tab dispositions keep the existing in-place behavior.

  • PopupClient — dedicated client (no OSR render handler → CEF renders natively), owns the NSWindow lifecycle. Deliberately not the parent's HostClient: sharing it would run OnBeforeClose against the parent's slot on popup close and unroute the tile.
  • FCPopupWindowDelegate — routes a user window-close through CloseBrowser; an alive gate (cleared in DoClose, before CEF destroys the browser) prevents a synthesized close-button press from dereferencing a dangling browser.
  • OnBeforeClose defers the window close/release off CEF's teardown stack.

Native-only; no wire-protocol change.

Validation (example app + CDP)

before after
window.open(popup) returns null (cancelled) a Window
native popup window none opens, renders the page
window.opener on popup n/a present, postMessage-capable
window.close() n/a closes cleanly, cef_host survives

🤖 Generated with Claude Code

… sign-in)

The OSR host cancels ordinary popups and loads their URL in-place. That's fine
for target=_blank links, but it BREAKS popup-based sign-in (Google Identity /
Firebase signInWithPopup): those open a real popup that authenticates, then
postMessages the credential back to window.opener and closes. An in-place
navigation has no opener and destroys the page waiting for the message — the
flow hangs (e.g. stuck at accounts.google.com/gsi/transform).

For a SIZED popup (WOD_NEW_POPUP — the shape OAuth uses), let CEF create a REAL
popup browser hosted windowed in a transient NSWindow (SetAsChild). window.opener
/ postMessage / window.close all work natively, and it shares the parent's request
context (cookie jar), so an existing Google session is recognized. Plain
target=_blank / new-tab dispositions keep the in-place behavior.

- PopupClient: dedicated client (no OSR render handler → CEF renders natively),
  owns the NSWindow lifecycle. NOT the parent's HostClient — sharing it would run
  OnBeforeClose against the parent's slot on popup close and unroute the tile.
- FCPopupWindowDelegate: routes a user window-close through CloseBrowser; an
  `alive` gate (cleared in DoClose, before CEF destroys the browser) keeps a
  synthesized close-button press from dereferencing a dangling browser.
- OnBeforeClose defers the window close/release off CEF's teardown stack.

Validated (example app + CDP, synthetic user gesture): a popup-disposition
window.open now opens a native window (was: window.open()===null, diverted
in-place); window.opener is present + postMessage-capable; window.close() tears
the window down cleanly with cef_host surviving.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@wenkaifan0720
wenkaifan0720 merged commit c549fb5 into main Jul 15, 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