fix(desktop): support OAuth popups in browser previews - #8413

Closed
MatthewFeroz wants to merge 4 commits into
pingdotgg:mainfrom
MatthewFeroz:fix/browser-preview-popups
Closed

fix(desktop): support OAuth popups in browser previews#8413
MatthewFeroz wants to merge 4 commits into
pingdotgg:mainfrom
MatthewFeroz:fix/browser-preview-popups

Conversation

@MatthewFeroz

@MatthewFerozMatthewFeroz commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Fixes#6561.

Browser previews denied every window.open() request and loaded the requested URL in the opener. OAuth libraries therefore reported the popup as blocked, and the opener/child handshake could never run.

This change permits real child windows for HTTP, HTTPS, and exact about:blank targets. Each child shares the opener session, runs sandboxed without Node or nested webviews, closes with its opener, and cannot create another popup. Unsafe and malformed URLs remain blocked through the shared preview URL validation.

The preview webview now attaches at about:blank and sends its intended URL through the typed registration IPC. The main process installs the popup policy before loading that URL, while preserving any newer navigation already queued for the tab.

This ports the sound parts of #6620 to current main and includes the URL-validation intent from #6156.

Verification:

  • vp test run apps/desktop/src/preview/Manager.test.ts apps/desktop/src/ipc/methods/preview.test.ts
  • vp run --filter @t3tools/desktop typecheck
  • vp run --filter @t3tools/web typecheck
  • vp run --filter @t3tools/contracts typecheck
  • Targeted vp lint and vp fmt --check on all changed files

Made with GPT-5.6 Sol in T3 Code using the Codex harness.


Note

Medium Risk
Changes preview navigation, popup policy, and OAuth-related window behavior in Electron; mis-handled initialUrl could leave previews stuck on about:blank, while popup session sharing affects login flows.

Overview
Desktop browser previews no longer treat every window.open() as navigation in the opener. PreviewManager installs a setWindowOpenHandler that allows sandboxed child windows for validated http/https URLs and exact about:blank, shares the guest session, parents them to the host window when possible, and denies unsafe schemes plus nested popups from auth windows.

Registration bootstrap changes so popups are configured before the first real load: registerWebview gains optional initialUrl end-to-end (contracts IPC schema, preload, IPC handler). The hosted <webview> always mounts at about:blank with allowpopups="true" and passes the intended URL at registration; the main process loads it after listeners are attached, keeps loading state through blank guest events, and strips the placeholder about:blank history entry when appropriate without racing newer navigations or replaced guests.

Reviewed by Cursor Bugbot for commit 4a1d865. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Allow OAuth popups in desktop browser previews via main-process URL loading

  • Webview registration now accepts an initialUrl that the main process loads after installing popup policy and listeners, replacing direct src navigation on the webview element.
  • Popups opened from a preview are restricted to about:blank and normalizable http/https URLs; approved popups open in a separate sandboxed BrowserWindow with no nodeIntegration or webviewTag, sharing the parent session. Nested popups are denied and child windows hide the menu bar.
  • The initial about:blank placeholder entry is removed from navigation history after the bootstrap URL loads; did-stop-loading from about:blank no longer overwrites a pending bootstrap navigation in syncWebContentsState.
  • The PreviewWebview alias forces allowpopups as a string attribute so Electron receives it before guest attach, replacing the previous imperative setAttribute call.
  • Behavioral Change: desktopBridge.preview.registerWebview and the IPC schema in ipc.ts now require a nullable initialUrl argument; any caller not updated will fail type validation.

Macroscope summarized 4a1d865.

request provenance

@coderabbitai

coderabbitaiBot commented Aug 27, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: f55412b5-890c-411c-b009-826f241ab278

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Comment @coderabbitai help to get the list of available commands.

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:L 100-499 changed lines (additions + deletions). labels Aug 27, 2026
Comment threadapps/desktop/src/preview/Manager.ts
Comment threadapps/desktop/src/preview/Manager.ts
@macroscopeapp

macroscopeappBot commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — This PR adds OAuth popup authentication support and changes preview bootstrap navigation, popup window security, and navigation-history behavior across production desktop and web paths. An unresolved failure case can leave Back navigation enabled to return to the blank bootstrap page when loading fails or is superseded.

You can add or adjust custom eligibility rules. Learn more.

Co-authored-by: Matthew Feroz <136640686+MatthewFeroz@users.noreply.github.com>

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One concern with the new about:blank bootstrap in HostedBrowserWebview — see the inline note on the guest's navigation history / Back button state.

Posted via Macroscope — UI Consistency

Comment threadapps/web/src/browser/HostedBrowserWebview.tsx
Co-authored-by: Matthew Feroz <136640686+MatthewFeroz@users.noreply.github.com>

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 76c040d. Configure here.

Comment threadapps/desktop/src/preview/Manager.ts
Remove only the captured about:blank entry after the bootstrap load, and serialize that removal with preview state updates. This keeps newer navigation history intact and prevents detached guests from publishing stale Back state.
Reported-by: Cursor Bugbot

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One finding on the preview guest bootstrap: the about:blank placeholder history entry is only cleaned up when the bootstrap load resolves, so a failed or aborted first load leaves the preview's Back button enabled and pointing at a blank page.

Posted via Macroscope — UI Consistency

key={webviewGeneration}
ref={setWebviewRef}
src={webviewGeneration === 0 ? initialSrc : recoverySrc}
src="about:blank"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pinning src to about:blank and deferring the real navigation to registerWebview makes the blank page a real guest history entry, and the cleanup for it only runs on success: in apps/desktop/src/preview/Manager.tsremoveBootstrapNavigationEntry is wired through Effect.tap on the loadURL promise, so it is skipped whenever that promise rejects (ERR_CONNECTION_REFUSED on a dev server that is not up yet, or ERR_ABORTED when a redirect/subsequent navigate supersedes the bootstrap load). Chromium still commits the error page / next page as entry 1, so syncWebContentsState publishes canGoBack: true and PreviewChromeRow's Back button stays enabled for the life of the tab, sending the preview back to a blank page. Before this change the target URL was the guest's first entry, so Back stayed disabled.

Smallest fix is on the desktop side: run the placeholder removal on both outcomes (e.g. Effect.onExit/ensuring instead of Effect.tap, still guarded by the existing generation/webContents identity checks), or drop the placeholder entry from a did-navigate/did-fail-load observation rather than from the loadURL resolution.

Posted via Macroscope — UI Consistency

@t3dotgg

Copy link
Copy Markdown
Member

Note

🤖 GPT-5.6 Sol responding on behalf of Theo

We're closing this PR as we clean up the T3 Code backlog. Thank you for taking the time to put this together.

We selected #8435 as the active OAuth popup path. Its current head installs allowpopups before guest attach, permits hardened HTTP and HTTPS new-window popups, denies nested popups, and keeps target="_blank" links in the preview. This branch takes a broader IPC and bootstrap approach and explicitly allows about:blank OAuth popups. Those different cases remain useful reference while we keep one popup manager in active review.

If you believe we closed this in error, please reopen the PR and leave a comment explaining what we missed.

@t3dotggt3dotgg closed this Aug 28, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L100-499 changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Integrated browser preview blocks OAuth popup authentication

2 participants

@MatthewFeroz@t3dotgg
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

fix(desktop): support OAuth popups in browser previews - #8413

Closed
MatthewFeroz wants to merge 4 commits into
pingdotgg:mainfrom
MatthewFeroz:fix/browser-preview-popups
Closed

fix(desktop): support OAuth popups in browser previews#8413
MatthewFeroz wants to merge 4 commits into
pingdotgg:mainfrom
MatthewFeroz:fix/browser-preview-popups

Conversation

@MatthewFeroz

@MatthewFerozMatthewFeroz commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Fixes#6561.

Browser previews denied every window.open() request and loaded the requested URL in the opener. OAuth libraries therefore reported the popup as blocked, and the opener/child handshake could never run.

This change permits real child windows for HTTP, HTTPS, and exact about:blank targets. Each child shares the opener session, runs sandboxed without Node or nested webviews, closes with its opener, and cannot create another popup. Unsafe and malformed URLs remain blocked through the shared preview URL validation.

The preview webview now attaches at about:blank and sends its intended URL through the typed registration IPC. The main process installs the popup policy before loading that URL, while preserving any newer navigation already queued for the tab.

This ports the sound parts of #6620 to current main and includes the URL-validation intent from #6156.

Verification:

  • vp test run apps/desktop/src/preview/Manager.test.ts apps/desktop/src/ipc/methods/preview.test.ts
  • vp run --filter @t3tools/desktop typecheck
  • vp run --filter @t3tools/web typecheck
  • vp run --filter @t3tools/contracts typecheck
  • Targeted vp lint and vp fmt --check on all changed files

Made with GPT-5.6 Sol in T3 Code using the Codex harness.


Note

Medium Risk
Changes preview navigation, popup policy, and OAuth-related window behavior in Electron; mis-handled initialUrl could leave previews stuck on about:blank, while popup session sharing affects login flows.

Overview
Desktop browser previews no longer treat every window.open() as navigation in the opener. PreviewManager installs a setWindowOpenHandler that allows sandboxed child windows for validated http/https URLs and exact about:blank, shares the guest session, parents them to the host window when possible, and denies unsafe schemes plus nested popups from auth windows.

Registration bootstrap changes so popups are configured before the first real load: registerWebview gains optional initialUrl end-to-end (contracts IPC schema, preload, IPC handler). The hosted <webview> always mounts at about:blank with allowpopups="true" and passes the intended URL at registration; the main process loads it after listeners are attached, keeps loading state through blank guest events, and strips the placeholder about:blank history entry when appropriate without racing newer navigations or replaced guests.

Reviewed by Cursor Bugbot for commit 4a1d865. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Allow OAuth popups in desktop browser previews via main-process URL loading

  • Webview registration now accepts an initialUrl that the main process loads after installing popup policy and listeners, replacing direct src navigation on the webview element.
  • Popups opened from a preview are restricted to about:blank and normalizable http/https URLs; approved popups open in a separate sandboxed BrowserWindow with no nodeIntegration or webviewTag, sharing the parent session. Nested popups are denied and child windows hide the menu bar.
  • The initial about:blank placeholder entry is removed from navigation history after the bootstrap URL loads; did-stop-loading from about:blank no longer overwrites a pending bootstrap navigation in syncWebContentsState.
  • The PreviewWebview alias forces allowpopups as a string attribute so Electron receives it before guest attach, replacing the previous imperative setAttribute call.
  • Behavioral Change: desktopBridge.preview.registerWebview and the IPC schema in ipc.ts now require a nullable initialUrl argument; any caller not updated will fail type validation.

Macroscope summarized 4a1d865.

request provenance

@coderabbitai

coderabbitaiBot commented Aug 27, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: f55412b5-890c-411c-b009-826f241ab278

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Comment @coderabbitai help to get the list of available commands.

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:L 100-499 changed lines (additions + deletions). labels Aug 27, 2026
Comment threadapps/desktop/src/preview/Manager.ts
Comment threadapps/desktop/src/preview/Manager.ts
@macroscopeapp

macroscopeappBot commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — This PR adds OAuth popup authentication support and changes preview bootstrap navigation, popup window security, and navigation-history behavior across production desktop and web paths. An unresolved failure case can leave Back navigation enabled to return to the blank bootstrap page when loading fails or is superseded.

You can add or adjust custom eligibility rules. Learn more.

Co-authored-by: Matthew Feroz <136640686+MatthewFeroz@users.noreply.github.com>

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One concern with the new about:blank bootstrap in HostedBrowserWebview — see the inline note on the guest's navigation history / Back button state.

Posted via Macroscope — UI Consistency

Comment threadapps/web/src/browser/HostedBrowserWebview.tsx
Co-authored-by: Matthew Feroz <136640686+MatthewFeroz@users.noreply.github.com>

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 76c040d. Configure here.

Comment threadapps/desktop/src/preview/Manager.ts
Remove only the captured about:blank entry after the bootstrap load, and serialize that removal with preview state updates. This keeps newer navigation history intact and prevents detached guests from publishing stale Back state.
Reported-by: Cursor Bugbot

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One finding on the preview guest bootstrap: the about:blank placeholder history entry is only cleaned up when the bootstrap load resolves, so a failed or aborted first load leaves the preview's Back button enabled and pointing at a blank page.

Posted via Macroscope — UI Consistency

key={webviewGeneration}
ref={setWebviewRef}
src={webviewGeneration === 0 ? initialSrc : recoverySrc}
src="about:blank"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pinning src to about:blank and deferring the real navigation to registerWebview makes the blank page a real guest history entry, and the cleanup for it only runs on success: in apps/desktop/src/preview/Manager.tsremoveBootstrapNavigationEntry is wired through Effect.tap on the loadURL promise, so it is skipped whenever that promise rejects (ERR_CONNECTION_REFUSED on a dev server that is not up yet, or ERR_ABORTED when a redirect/subsequent navigate supersedes the bootstrap load). Chromium still commits the error page / next page as entry 1, so syncWebContentsState publishes canGoBack: true and PreviewChromeRow's Back button stays enabled for the life of the tab, sending the preview back to a blank page. Before this change the target URL was the guest's first entry, so Back stayed disabled.

Smallest fix is on the desktop side: run the placeholder removal on both outcomes (e.g. Effect.onExit/ensuring instead of Effect.tap, still guarded by the existing generation/webContents identity checks), or drop the placeholder entry from a did-navigate/did-fail-load observation rather than from the loadURL resolution.

Posted via Macroscope — UI Consistency

@t3dotgg

Copy link
Copy Markdown
Member

Note

🤖 GPT-5.6 Sol responding on behalf of Theo

We're closing this PR as we clean up the T3 Code backlog. Thank you for taking the time to put this together.

We selected #8435 as the active OAuth popup path. Its current head installs allowpopups before guest attach, permits hardened HTTP and HTTPS new-window popups, denies nested popups, and keeps target="_blank" links in the preview. This branch takes a broader IPC and bootstrap approach and explicitly allows about:blank OAuth popups. Those different cases remain useful reference while we keep one popup manager in active review.

If you believe we closed this in error, please reopen the PR and leave a comment explaining what we missed.

@t3dotggt3dotgg closed this Aug 28, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L100-499 changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Integrated browser preview blocks OAuth popup authentication

2 participants

@MatthewFeroz@t3dotgg
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(desktop): support OAuth popups in browser previews - #8413

Closed
MatthewFeroz wants to merge 4 commits into
pingdotgg:mainfrom
MatthewFeroz:fix/browser-preview-popups
Closed

fix(desktop): support OAuth popups in browser previews#8413
MatthewFeroz wants to merge 4 commits into
pingdotgg:mainfrom
MatthewFeroz:fix/browser-preview-popups

Conversation

@MatthewFeroz

@MatthewFerozMatthewFeroz commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Fixes#6561.

Browser previews denied every window.open() request and loaded the requested URL in the opener. OAuth libraries therefore reported the popup as blocked, and the opener/child handshake could never run.

This change permits real child windows for HTTP, HTTPS, and exact about:blank targets. Each child shares the opener session, runs sandboxed without Node or nested webviews, closes with its opener, and cannot create another popup. Unsafe and malformed URLs remain blocked through the shared preview URL validation.

The preview webview now attaches at about:blank and sends its intended URL through the typed registration IPC. The main process installs the popup policy before loading that URL, while preserving any newer navigation already queued for the tab.

This ports the sound parts of #6620 to current main and includes the URL-validation intent from #6156.

Verification:

  • vp test run apps/desktop/src/preview/Manager.test.ts apps/desktop/src/ipc/methods/preview.test.ts
  • vp run --filter @t3tools/desktop typecheck
  • vp run --filter @t3tools/web typecheck
  • vp run --filter @t3tools/contracts typecheck
  • Targeted vp lint and vp fmt --check on all changed files

Made with GPT-5.6 Sol in T3 Code using the Codex harness.


Note

Medium Risk
Changes preview navigation, popup policy, and OAuth-related window behavior in Electron; mis-handled initialUrl could leave previews stuck on about:blank, while popup session sharing affects login flows.

Overview
Desktop browser previews no longer treat every window.open() as navigation in the opener. PreviewManager installs a setWindowOpenHandler that allows sandboxed child windows for validated http/https URLs and exact about:blank, shares the guest session, parents them to the host window when possible, and denies unsafe schemes plus nested popups from auth windows.

Registration bootstrap changes so popups are configured before the first real load: registerWebview gains optional initialUrl end-to-end (contracts IPC schema, preload, IPC handler). The hosted <webview> always mounts at about:blank with allowpopups="true" and passes the intended URL at registration; the main process loads it after listeners are attached, keeps loading state through blank guest events, and strips the placeholder about:blank history entry when appropriate without racing newer navigations or replaced guests.

Reviewed by Cursor Bugbot for commit 4a1d865. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Allow OAuth popups in desktop browser previews via main-process URL loading

  • Webview registration now accepts an initialUrl that the main process loads after installing popup policy and listeners, replacing direct src navigation on the webview element.
  • Popups opened from a preview are restricted to about:blank and normalizable http/https URLs; approved popups open in a separate sandboxed BrowserWindow with no nodeIntegration or webviewTag, sharing the parent session. Nested popups are denied and child windows hide the menu bar.
  • The initial about:blank placeholder entry is removed from navigation history after the bootstrap URL loads; did-stop-loading from about:blank no longer overwrites a pending bootstrap navigation in syncWebContentsState.
  • The PreviewWebview alias forces allowpopups as a string attribute so Electron receives it before guest attach, replacing the previous imperative setAttribute call.
  • Behavioral Change: desktopBridge.preview.registerWebview and the IPC schema in ipc.ts now require a nullable initialUrl argument; any caller not updated will fail type validation.

Macroscope summarized 4a1d865.

request provenance

@coderabbitai

coderabbitaiBot commented Aug 27, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: f55412b5-890c-411c-b009-826f241ab278

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Comment @coderabbitai help to get the list of available commands.

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:L 100-499 changed lines (additions + deletions). labels Aug 27, 2026
Comment threadapps/desktop/src/preview/Manager.ts
Comment threadapps/desktop/src/preview/Manager.ts
@macroscopeapp

macroscopeappBot commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — This PR adds OAuth popup authentication support and changes preview bootstrap navigation, popup window security, and navigation-history behavior across production desktop and web paths. An unresolved failure case can leave Back navigation enabled to return to the blank bootstrap page when loading fails or is superseded.

You can add or adjust custom eligibility rules. Learn more.

Co-authored-by: Matthew Feroz <136640686+MatthewFeroz@users.noreply.github.com>

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One concern with the new about:blank bootstrap in HostedBrowserWebview — see the inline note on the guest's navigation history / Back button state.

Posted via Macroscope — UI Consistency

Comment threadapps/web/src/browser/HostedBrowserWebview.tsx
Co-authored-by: Matthew Feroz <136640686+MatthewFeroz@users.noreply.github.com>

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 76c040d. Configure here.

Comment threadapps/desktop/src/preview/Manager.ts
Remove only the captured about:blank entry after the bootstrap load, and serialize that removal with preview state updates. This keeps newer navigation history intact and prevents detached guests from publishing stale Back state.
Reported-by: Cursor Bugbot

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One finding on the preview guest bootstrap: the about:blank placeholder history entry is only cleaned up when the bootstrap load resolves, so a failed or aborted first load leaves the preview's Back button enabled and pointing at a blank page.

Posted via Macroscope — UI Consistency

key={webviewGeneration}
ref={setWebviewRef}
src={webviewGeneration === 0 ? initialSrc : recoverySrc}
src="about:blank"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pinning src to about:blank and deferring the real navigation to registerWebview makes the blank page a real guest history entry, and the cleanup for it only runs on success: in apps/desktop/src/preview/Manager.tsremoveBootstrapNavigationEntry is wired through Effect.tap on the loadURL promise, so it is skipped whenever that promise rejects (ERR_CONNECTION_REFUSED on a dev server that is not up yet, or ERR_ABORTED when a redirect/subsequent navigate supersedes the bootstrap load). Chromium still commits the error page / next page as entry 1, so syncWebContentsState publishes canGoBack: true and PreviewChromeRow's Back button stays enabled for the life of the tab, sending the preview back to a blank page. Before this change the target URL was the guest's first entry, so Back stayed disabled.

Smallest fix is on the desktop side: run the placeholder removal on both outcomes (e.g. Effect.onExit/ensuring instead of Effect.tap, still guarded by the existing generation/webContents identity checks), or drop the placeholder entry from a did-navigate/did-fail-load observation rather than from the loadURL resolution.

Posted via Macroscope — UI Consistency

@t3dotgg

Copy link
Copy Markdown
Member

Note

🤖 GPT-5.6 Sol responding on behalf of Theo

We're closing this PR as we clean up the T3 Code backlog. Thank you for taking the time to put this together.

We selected #8435 as the active OAuth popup path. Its current head installs allowpopups before guest attach, permits hardened HTTP and HTTPS new-window popups, denies nested popups, and keeps target="_blank" links in the preview. This branch takes a broader IPC and bootstrap approach and explicitly allows about:blank OAuth popups. Those different cases remain useful reference while we keep one popup manager in active review.

If you believe we closed this in error, please reopen the PR and leave a comment explaining what we missed.

@t3dotggt3dotgg closed this Aug 28, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L100-499 changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Integrated browser preview blocks OAuth popup authentication

2 participants

@MatthewFeroz@t3dotgg
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(desktop): support OAuth popups in browser previews - #8413

Closed
MatthewFeroz wants to merge 4 commits into
pingdotgg:mainfrom
MatthewFeroz:fix/browser-preview-popups
Closed

fix(desktop): support OAuth popups in browser previews#8413
MatthewFeroz wants to merge 4 commits into
pingdotgg:mainfrom
MatthewFeroz:fix/browser-preview-popups

Conversation

@MatthewFeroz

@MatthewFerozMatthewFeroz commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Fixes#6561.

Browser previews denied every window.open() request and loaded the requested URL in the opener. OAuth libraries therefore reported the popup as blocked, and the opener/child handshake could never run.

This change permits real child windows for HTTP, HTTPS, and exact about:blank targets. Each child shares the opener session, runs sandboxed without Node or nested webviews, closes with its opener, and cannot create another popup. Unsafe and malformed URLs remain blocked through the shared preview URL validation.

The preview webview now attaches at about:blank and sends its intended URL through the typed registration IPC. The main process installs the popup policy before loading that URL, while preserving any newer navigation already queued for the tab.

This ports the sound parts of #6620 to current main and includes the URL-validation intent from #6156.

Verification:

  • vp test run apps/desktop/src/preview/Manager.test.ts apps/desktop/src/ipc/methods/preview.test.ts
  • vp run --filter @t3tools/desktop typecheck
  • vp run --filter @t3tools/web typecheck
  • vp run --filter @t3tools/contracts typecheck
  • Targeted vp lint and vp fmt --check on all changed files

Made with GPT-5.6 Sol in T3 Code using the Codex harness.


Note

Medium Risk
Changes preview navigation, popup policy, and OAuth-related window behavior in Electron; mis-handled initialUrl could leave previews stuck on about:blank, while popup session sharing affects login flows.

Overview
Desktop browser previews no longer treat every window.open() as navigation in the opener. PreviewManager installs a setWindowOpenHandler that allows sandboxed child windows for validated http/https URLs and exact about:blank, shares the guest session, parents them to the host window when possible, and denies unsafe schemes plus nested popups from auth windows.

Registration bootstrap changes so popups are configured before the first real load: registerWebview gains optional initialUrl end-to-end (contracts IPC schema, preload, IPC handler). The hosted <webview> always mounts at about:blank with allowpopups="true" and passes the intended URL at registration; the main process loads it after listeners are attached, keeps loading state through blank guest events, and strips the placeholder about:blank history entry when appropriate without racing newer navigations or replaced guests.

Reviewed by Cursor Bugbot for commit 4a1d865. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Allow OAuth popups in desktop browser previews via main-process URL loading

  • Webview registration now accepts an initialUrl that the main process loads after installing popup policy and listeners, replacing direct src navigation on the webview element.
  • Popups opened from a preview are restricted to about:blank and normalizable http/https URLs; approved popups open in a separate sandboxed BrowserWindow with no nodeIntegration or webviewTag, sharing the parent session. Nested popups are denied and child windows hide the menu bar.
  • The initial about:blank placeholder entry is removed from navigation history after the bootstrap URL loads; did-stop-loading from about:blank no longer overwrites a pending bootstrap navigation in syncWebContentsState.
  • The PreviewWebview alias forces allowpopups as a string attribute so Electron receives it before guest attach, replacing the previous imperative setAttribute call.
  • Behavioral Change: desktopBridge.preview.registerWebview and the IPC schema in ipc.ts now require a nullable initialUrl argument; any caller not updated will fail type validation.

Macroscope summarized 4a1d865.

request provenance

@coderabbitai

coderabbitaiBot commented Aug 27, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: f55412b5-890c-411c-b009-826f241ab278

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Comment @coderabbitai help to get the list of available commands.

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:L 100-499 changed lines (additions + deletions). labels Aug 27, 2026
Comment threadapps/desktop/src/preview/Manager.ts
Comment threadapps/desktop/src/preview/Manager.ts
@macroscopeapp

macroscopeappBot commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — This PR adds OAuth popup authentication support and changes preview bootstrap navigation, popup window security, and navigation-history behavior across production desktop and web paths. An unresolved failure case can leave Back navigation enabled to return to the blank bootstrap page when loading fails or is superseded.

You can add or adjust custom eligibility rules. Learn more.

Co-authored-by: Matthew Feroz <136640686+MatthewFeroz@users.noreply.github.com>

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One concern with the new about:blank bootstrap in HostedBrowserWebview — see the inline note on the guest's navigation history / Back button state.

Posted via Macroscope — UI Consistency

Comment threadapps/web/src/browser/HostedBrowserWebview.tsx
Co-authored-by: Matthew Feroz <136640686+MatthewFeroz@users.noreply.github.com>

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 76c040d. Configure here.

Comment threadapps/desktop/src/preview/Manager.ts
Remove only the captured about:blank entry after the bootstrap load, and serialize that removal with preview state updates. This keeps newer navigation history intact and prevents detached guests from publishing stale Back state.
Reported-by: Cursor Bugbot

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One finding on the preview guest bootstrap: the about:blank placeholder history entry is only cleaned up when the bootstrap load resolves, so a failed or aborted first load leaves the preview's Back button enabled and pointing at a blank page.

Posted via Macroscope — UI Consistency

key={webviewGeneration}
ref={setWebviewRef}
src={webviewGeneration === 0 ? initialSrc : recoverySrc}
src="about:blank"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pinning src to about:blank and deferring the real navigation to registerWebview makes the blank page a real guest history entry, and the cleanup for it only runs on success: in apps/desktop/src/preview/Manager.tsremoveBootstrapNavigationEntry is wired through Effect.tap on the loadURL promise, so it is skipped whenever that promise rejects (ERR_CONNECTION_REFUSED on a dev server that is not up yet, or ERR_ABORTED when a redirect/subsequent navigate supersedes the bootstrap load). Chromium still commits the error page / next page as entry 1, so syncWebContentsState publishes canGoBack: true and PreviewChromeRow's Back button stays enabled for the life of the tab, sending the preview back to a blank page. Before this change the target URL was the guest's first entry, so Back stayed disabled.

Smallest fix is on the desktop side: run the placeholder removal on both outcomes (e.g. Effect.onExit/ensuring instead of Effect.tap, still guarded by the existing generation/webContents identity checks), or drop the placeholder entry from a did-navigate/did-fail-load observation rather than from the loadURL resolution.

Posted via Macroscope — UI Consistency

@t3dotgg

Copy link
Copy Markdown
Member

Note

🤖 GPT-5.6 Sol responding on behalf of Theo

We're closing this PR as we clean up the T3 Code backlog. Thank you for taking the time to put this together.

We selected #8435 as the active OAuth popup path. Its current head installs allowpopups before guest attach, permits hardened HTTP and HTTPS new-window popups, denies nested popups, and keeps target="_blank" links in the preview. This branch takes a broader IPC and bootstrap approach and explicitly allows about:blank OAuth popups. Those different cases remain useful reference while we keep one popup manager in active review.

If you believe we closed this in error, please reopen the PR and leave a comment explaining what we missed.

@t3dotggt3dotgg closed this Aug 28, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L100-499 changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Integrated browser preview blocks OAuth popup authentication

2 participants

@MatthewFeroz@t3dotgg
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

fix(desktop): support OAuth popups in browser previews - #8413

Closed
MatthewFeroz wants to merge 4 commits into
pingdotgg:mainfrom
MatthewFeroz:fix/browser-preview-popups
Closed

fix(desktop): support OAuth popups in browser previews#8413
MatthewFeroz wants to merge 4 commits into
pingdotgg:mainfrom
MatthewFeroz:fix/browser-preview-popups

Conversation

@MatthewFeroz

@MatthewFerozMatthewFeroz commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Fixes#6561.

Browser previews denied every window.open() request and loaded the requested URL in the opener. OAuth libraries therefore reported the popup as blocked, and the opener/child handshake could never run.

This change permits real child windows for HTTP, HTTPS, and exact about:blank targets. Each child shares the opener session, runs sandboxed without Node or nested webviews, closes with its opener, and cannot create another popup. Unsafe and malformed URLs remain blocked through the shared preview URL validation.

The preview webview now attaches at about:blank and sends its intended URL through the typed registration IPC. The main process installs the popup policy before loading that URL, while preserving any newer navigation already queued for the tab.

This ports the sound parts of #6620 to current main and includes the URL-validation intent from #6156.

Verification:

  • vp test run apps/desktop/src/preview/Manager.test.ts apps/desktop/src/ipc/methods/preview.test.ts
  • vp run --filter @t3tools/desktop typecheck
  • vp run --filter @t3tools/web typecheck
  • vp run --filter @t3tools/contracts typecheck
  • Targeted vp lint and vp fmt --check on all changed files

Made with GPT-5.6 Sol in T3 Code using the Codex harness.


Note

Medium Risk
Changes preview navigation, popup policy, and OAuth-related window behavior in Electron; mis-handled initialUrl could leave previews stuck on about:blank, while popup session sharing affects login flows.

Overview
Desktop browser previews no longer treat every window.open() as navigation in the opener. PreviewManager installs a setWindowOpenHandler that allows sandboxed child windows for validated http/https URLs and exact about:blank, shares the guest session, parents them to the host window when possible, and denies unsafe schemes plus nested popups from auth windows.

Registration bootstrap changes so popups are configured before the first real load: registerWebview gains optional initialUrl end-to-end (contracts IPC schema, preload, IPC handler). The hosted <webview> always mounts at about:blank with allowpopups="true" and passes the intended URL at registration; the main process loads it after listeners are attached, keeps loading state through blank guest events, and strips the placeholder about:blank history entry when appropriate without racing newer navigations or replaced guests.

Reviewed by Cursor Bugbot for commit 4a1d865. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Allow OAuth popups in desktop browser previews via main-process URL loading

  • Webview registration now accepts an initialUrl that the main process loads after installing popup policy and listeners, replacing direct src navigation on the webview element.
  • Popups opened from a preview are restricted to about:blank and normalizable http/https URLs; approved popups open in a separate sandboxed BrowserWindow with no nodeIntegration or webviewTag, sharing the parent session. Nested popups are denied and child windows hide the menu bar.
  • The initial about:blank placeholder entry is removed from navigation history after the bootstrap URL loads; did-stop-loading from about:blank no longer overwrites a pending bootstrap navigation in syncWebContentsState.
  • The PreviewWebview alias forces allowpopups as a string attribute so Electron receives it before guest attach, replacing the previous imperative setAttribute call.
  • Behavioral Change: desktopBridge.preview.registerWebview and the IPC schema in ipc.ts now require a nullable initialUrl argument; any caller not updated will fail type validation.

Macroscope summarized 4a1d865.

request provenance

@coderabbitai

coderabbitaiBot commented Aug 27, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: f55412b5-890c-411c-b009-826f241ab278

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Comment @coderabbitai help to get the list of available commands.

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:L 100-499 changed lines (additions + deletions). labels Aug 27, 2026
Comment threadapps/desktop/src/preview/Manager.ts
Comment threadapps/desktop/src/preview/Manager.ts
@macroscopeapp

macroscopeappBot commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — This PR adds OAuth popup authentication support and changes preview bootstrap navigation, popup window security, and navigation-history behavior across production desktop and web paths. An unresolved failure case can leave Back navigation enabled to return to the blank bootstrap page when loading fails or is superseded.

You can add or adjust custom eligibility rules. Learn more.

Co-authored-by: Matthew Feroz <136640686+MatthewFeroz@users.noreply.github.com>

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One concern with the new about:blank bootstrap in HostedBrowserWebview — see the inline note on the guest's navigation history / Back button state.

Posted via Macroscope — UI Consistency

Comment threadapps/web/src/browser/HostedBrowserWebview.tsx
Co-authored-by: Matthew Feroz <136640686+MatthewFeroz@users.noreply.github.com>

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 76c040d. Configure here.

Comment threadapps/desktop/src/preview/Manager.ts
Remove only the captured about:blank entry after the bootstrap load, and serialize that removal with preview state updates. This keeps newer navigation history intact and prevents detached guests from publishing stale Back state.
Reported-by: Cursor Bugbot

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One finding on the preview guest bootstrap: the about:blank placeholder history entry is only cleaned up when the bootstrap load resolves, so a failed or aborted first load leaves the preview's Back button enabled and pointing at a blank page.

Posted via Macroscope — UI Consistency

key={webviewGeneration}
ref={setWebviewRef}
src={webviewGeneration === 0 ? initialSrc : recoverySrc}
src="about:blank"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pinning src to about:blank and deferring the real navigation to registerWebview makes the blank page a real guest history entry, and the cleanup for it only runs on success: in apps/desktop/src/preview/Manager.tsremoveBootstrapNavigationEntry is wired through Effect.tap on the loadURL promise, so it is skipped whenever that promise rejects (ERR_CONNECTION_REFUSED on a dev server that is not up yet, or ERR_ABORTED when a redirect/subsequent navigate supersedes the bootstrap load). Chromium still commits the error page / next page as entry 1, so syncWebContentsState publishes canGoBack: true and PreviewChromeRow's Back button stays enabled for the life of the tab, sending the preview back to a blank page. Before this change the target URL was the guest's first entry, so Back stayed disabled.

Smallest fix is on the desktop side: run the placeholder removal on both outcomes (e.g. Effect.onExit/ensuring instead of Effect.tap, still guarded by the existing generation/webContents identity checks), or drop the placeholder entry from a did-navigate/did-fail-load observation rather than from the loadURL resolution.

Posted via Macroscope — UI Consistency

@t3dotgg

Copy link
Copy Markdown
Member

Note

🤖 GPT-5.6 Sol responding on behalf of Theo

We're closing this PR as we clean up the T3 Code backlog. Thank you for taking the time to put this together.

We selected #8435 as the active OAuth popup path. Its current head installs allowpopups before guest attach, permits hardened HTTP and HTTPS new-window popups, denies nested popups, and keeps target="_blank" links in the preview. This branch takes a broader IPC and bootstrap approach and explicitly allows about:blank OAuth popups. Those different cases remain useful reference while we keep one popup manager in active review.

If you believe we closed this in error, please reopen the PR and leave a comment explaining what we missed.

@t3dotggt3dotgg closed this Aug 28, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L100-499 changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Integrated browser preview blocks OAuth popup authentication

2 participants

@MatthewFeroz@t3dotgg
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(desktop): support OAuth popups in browser previews - #8413

Closed
MatthewFeroz wants to merge 4 commits into
pingdotgg:mainfrom
MatthewFeroz:fix/browser-preview-popups
Closed

fix(desktop): support OAuth popups in browser previews#8413
MatthewFeroz wants to merge 4 commits into
pingdotgg:mainfrom
MatthewFeroz:fix/browser-preview-popups

Conversation

@MatthewFeroz

@MatthewFerozMatthewFeroz commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Fixes#6561.

Browser previews denied every window.open() request and loaded the requested URL in the opener. OAuth libraries therefore reported the popup as blocked, and the opener/child handshake could never run.

This change permits real child windows for HTTP, HTTPS, and exact about:blank targets. Each child shares the opener session, runs sandboxed without Node or nested webviews, closes with its opener, and cannot create another popup. Unsafe and malformed URLs remain blocked through the shared preview URL validation.

The preview webview now attaches at about:blank and sends its intended URL through the typed registration IPC. The main process installs the popup policy before loading that URL, while preserving any newer navigation already queued for the tab.

This ports the sound parts of #6620 to current main and includes the URL-validation intent from #6156.

Verification:

  • vp test run apps/desktop/src/preview/Manager.test.ts apps/desktop/src/ipc/methods/preview.test.ts
  • vp run --filter @t3tools/desktop typecheck
  • vp run --filter @t3tools/web typecheck
  • vp run --filter @t3tools/contracts typecheck
  • Targeted vp lint and vp fmt --check on all changed files

Made with GPT-5.6 Sol in T3 Code using the Codex harness.


Note

Medium Risk
Changes preview navigation, popup policy, and OAuth-related window behavior in Electron; mis-handled initialUrl could leave previews stuck on about:blank, while popup session sharing affects login flows.

Overview
Desktop browser previews no longer treat every window.open() as navigation in the opener. PreviewManager installs a setWindowOpenHandler that allows sandboxed child windows for validated http/https URLs and exact about:blank, shares the guest session, parents them to the host window when possible, and denies unsafe schemes plus nested popups from auth windows.

Registration bootstrap changes so popups are configured before the first real load: registerWebview gains optional initialUrl end-to-end (contracts IPC schema, preload, IPC handler). The hosted <webview> always mounts at about:blank with allowpopups="true" and passes the intended URL at registration; the main process loads it after listeners are attached, keeps loading state through blank guest events, and strips the placeholder about:blank history entry when appropriate without racing newer navigations or replaced guests.

Reviewed by Cursor Bugbot for commit 4a1d865. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Allow OAuth popups in desktop browser previews via main-process URL loading

  • Webview registration now accepts an initialUrl that the main process loads after installing popup policy and listeners, replacing direct src navigation on the webview element.
  • Popups opened from a preview are restricted to about:blank and normalizable http/https URLs; approved popups open in a separate sandboxed BrowserWindow with no nodeIntegration or webviewTag, sharing the parent session. Nested popups are denied and child windows hide the menu bar.
  • The initial about:blank placeholder entry is removed from navigation history after the bootstrap URL loads; did-stop-loading from about:blank no longer overwrites a pending bootstrap navigation in syncWebContentsState.
  • The PreviewWebview alias forces allowpopups as a string attribute so Electron receives it before guest attach, replacing the previous imperative setAttribute call.
  • Behavioral Change: desktopBridge.preview.registerWebview and the IPC schema in ipc.ts now require a nullable initialUrl argument; any caller not updated will fail type validation.

Macroscope summarized 4a1d865.

request provenance

@coderabbitai

coderabbitaiBot commented Aug 27, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: f55412b5-890c-411c-b009-826f241ab278

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Comment @coderabbitai help to get the list of available commands.

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:L 100-499 changed lines (additions + deletions). labels Aug 27, 2026
Comment threadapps/desktop/src/preview/Manager.ts
Comment threadapps/desktop/src/preview/Manager.ts
@macroscopeapp

macroscopeappBot commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — This PR adds OAuth popup authentication support and changes preview bootstrap navigation, popup window security, and navigation-history behavior across production desktop and web paths. An unresolved failure case can leave Back navigation enabled to return to the blank bootstrap page when loading fails or is superseded.

You can add or adjust custom eligibility rules. Learn more.

Co-authored-by: Matthew Feroz <136640686+MatthewFeroz@users.noreply.github.com>

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One concern with the new about:blank bootstrap in HostedBrowserWebview — see the inline note on the guest's navigation history / Back button state.

Posted via Macroscope — UI Consistency

Comment threadapps/web/src/browser/HostedBrowserWebview.tsx
Co-authored-by: Matthew Feroz <136640686+MatthewFeroz@users.noreply.github.com>

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 76c040d. Configure here.

Comment threadapps/desktop/src/preview/Manager.ts
Remove only the captured about:blank entry after the bootstrap load, and serialize that removal with preview state updates. This keeps newer navigation history intact and prevents detached guests from publishing stale Back state.
Reported-by: Cursor Bugbot

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One finding on the preview guest bootstrap: the about:blank placeholder history entry is only cleaned up when the bootstrap load resolves, so a failed or aborted first load leaves the preview's Back button enabled and pointing at a blank page.

Posted via Macroscope — UI Consistency

key={webviewGeneration}
ref={setWebviewRef}
src={webviewGeneration === 0 ? initialSrc : recoverySrc}
src="about:blank"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pinning src to about:blank and deferring the real navigation to registerWebview makes the blank page a real guest history entry, and the cleanup for it only runs on success: in apps/desktop/src/preview/Manager.tsremoveBootstrapNavigationEntry is wired through Effect.tap on the loadURL promise, so it is skipped whenever that promise rejects (ERR_CONNECTION_REFUSED on a dev server that is not up yet, or ERR_ABORTED when a redirect/subsequent navigate supersedes the bootstrap load). Chromium still commits the error page / next page as entry 1, so syncWebContentsState publishes canGoBack: true and PreviewChromeRow's Back button stays enabled for the life of the tab, sending the preview back to a blank page. Before this change the target URL was the guest's first entry, so Back stayed disabled.

Smallest fix is on the desktop side: run the placeholder removal on both outcomes (e.g. Effect.onExit/ensuring instead of Effect.tap, still guarded by the existing generation/webContents identity checks), or drop the placeholder entry from a did-navigate/did-fail-load observation rather than from the loadURL resolution.

Posted via Macroscope — UI Consistency

@t3dotgg

Copy link
Copy Markdown
Member

Note

🤖 GPT-5.6 Sol responding on behalf of Theo

We're closing this PR as we clean up the T3 Code backlog. Thank you for taking the time to put this together.

We selected #8435 as the active OAuth popup path. Its current head installs allowpopups before guest attach, permits hardened HTTP and HTTPS new-window popups, denies nested popups, and keeps target="_blank" links in the preview. This branch takes a broader IPC and bootstrap approach and explicitly allows about:blank OAuth popups. Those different cases remain useful reference while we keep one popup manager in active review.

If you believe we closed this in error, please reopen the PR and leave a comment explaining what we missed.

@t3dotggt3dotgg closed this Aug 28, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L100-499 changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Integrated browser preview blocks OAuth popup authentication

2 participants

@MatthewFeroz@t3dotgg
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(desktop): support OAuth popups in browser previews - #8413

Closed
MatthewFeroz wants to merge 4 commits into
pingdotgg:mainfrom
MatthewFeroz:fix/browser-preview-popups
Closed

fix(desktop): support OAuth popups in browser previews#8413
MatthewFeroz wants to merge 4 commits into
pingdotgg:mainfrom
MatthewFeroz:fix/browser-preview-popups

Conversation

@MatthewFeroz

@MatthewFerozMatthewFeroz commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Fixes#6561.

Browser previews denied every window.open() request and loaded the requested URL in the opener. OAuth libraries therefore reported the popup as blocked, and the opener/child handshake could never run.

This change permits real child windows for HTTP, HTTPS, and exact about:blank targets. Each child shares the opener session, runs sandboxed without Node or nested webviews, closes with its opener, and cannot create another popup. Unsafe and malformed URLs remain blocked through the shared preview URL validation.

The preview webview now attaches at about:blank and sends its intended URL through the typed registration IPC. The main process installs the popup policy before loading that URL, while preserving any newer navigation already queued for the tab.

This ports the sound parts of #6620 to current main and includes the URL-validation intent from #6156.

Verification:

  • vp test run apps/desktop/src/preview/Manager.test.ts apps/desktop/src/ipc/methods/preview.test.ts
  • vp run --filter @t3tools/desktop typecheck
  • vp run --filter @t3tools/web typecheck
  • vp run --filter @t3tools/contracts typecheck
  • Targeted vp lint and vp fmt --check on all changed files

Made with GPT-5.6 Sol in T3 Code using the Codex harness.


Note

Medium Risk
Changes preview navigation, popup policy, and OAuth-related window behavior in Electron; mis-handled initialUrl could leave previews stuck on about:blank, while popup session sharing affects login flows.

Overview
Desktop browser previews no longer treat every window.open() as navigation in the opener. PreviewManager installs a setWindowOpenHandler that allows sandboxed child windows for validated http/https URLs and exact about:blank, shares the guest session, parents them to the host window when possible, and denies unsafe schemes plus nested popups from auth windows.

Registration bootstrap changes so popups are configured before the first real load: registerWebview gains optional initialUrl end-to-end (contracts IPC schema, preload, IPC handler). The hosted <webview> always mounts at about:blank with allowpopups="true" and passes the intended URL at registration; the main process loads it after listeners are attached, keeps loading state through blank guest events, and strips the placeholder about:blank history entry when appropriate without racing newer navigations or replaced guests.

Reviewed by Cursor Bugbot for commit 4a1d865. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Allow OAuth popups in desktop browser previews via main-process URL loading

  • Webview registration now accepts an initialUrl that the main process loads after installing popup policy and listeners, replacing direct src navigation on the webview element.
  • Popups opened from a preview are restricted to about:blank and normalizable http/https URLs; approved popups open in a separate sandboxed BrowserWindow with no nodeIntegration or webviewTag, sharing the parent session. Nested popups are denied and child windows hide the menu bar.
  • The initial about:blank placeholder entry is removed from navigation history after the bootstrap URL loads; did-stop-loading from about:blank no longer overwrites a pending bootstrap navigation in syncWebContentsState.
  • The PreviewWebview alias forces allowpopups as a string attribute so Electron receives it before guest attach, replacing the previous imperative setAttribute call.
  • Behavioral Change: desktopBridge.preview.registerWebview and the IPC schema in ipc.ts now require a nullable initialUrl argument; any caller not updated will fail type validation.

Macroscope summarized 4a1d865.

request provenance

@coderabbitai

coderabbitaiBot commented Aug 27, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: f55412b5-890c-411c-b009-826f241ab278

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Comment @coderabbitai help to get the list of available commands.

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:L 100-499 changed lines (additions + deletions). labels Aug 27, 2026
Comment threadapps/desktop/src/preview/Manager.ts
Comment threadapps/desktop/src/preview/Manager.ts
@macroscopeapp

macroscopeappBot commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — This PR adds OAuth popup authentication support and changes preview bootstrap navigation, popup window security, and navigation-history behavior across production desktop and web paths. An unresolved failure case can leave Back navigation enabled to return to the blank bootstrap page when loading fails or is superseded.

You can add or adjust custom eligibility rules. Learn more.

Co-authored-by: Matthew Feroz <136640686+MatthewFeroz@users.noreply.github.com>

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One concern with the new about:blank bootstrap in HostedBrowserWebview — see the inline note on the guest's navigation history / Back button state.

Posted via Macroscope — UI Consistency

Comment threadapps/web/src/browser/HostedBrowserWebview.tsx
Co-authored-by: Matthew Feroz <136640686+MatthewFeroz@users.noreply.github.com>

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 76c040d. Configure here.

Comment threadapps/desktop/src/preview/Manager.ts
Remove only the captured about:blank entry after the bootstrap load, and serialize that removal with preview state updates. This keeps newer navigation history intact and prevents detached guests from publishing stale Back state.
Reported-by: Cursor Bugbot

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One finding on the preview guest bootstrap: the about:blank placeholder history entry is only cleaned up when the bootstrap load resolves, so a failed or aborted first load leaves the preview's Back button enabled and pointing at a blank page.

Posted via Macroscope — UI Consistency

key={webviewGeneration}
ref={setWebviewRef}
src={webviewGeneration === 0 ? initialSrc : recoverySrc}
src="about:blank"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pinning src to about:blank and deferring the real navigation to registerWebview makes the blank page a real guest history entry, and the cleanup for it only runs on success: in apps/desktop/src/preview/Manager.tsremoveBootstrapNavigationEntry is wired through Effect.tap on the loadURL promise, so it is skipped whenever that promise rejects (ERR_CONNECTION_REFUSED on a dev server that is not up yet, or ERR_ABORTED when a redirect/subsequent navigate supersedes the bootstrap load). Chromium still commits the error page / next page as entry 1, so syncWebContentsState publishes canGoBack: true and PreviewChromeRow's Back button stays enabled for the life of the tab, sending the preview back to a blank page. Before this change the target URL was the guest's first entry, so Back stayed disabled.

Smallest fix is on the desktop side: run the placeholder removal on both outcomes (e.g. Effect.onExit/ensuring instead of Effect.tap, still guarded by the existing generation/webContents identity checks), or drop the placeholder entry from a did-navigate/did-fail-load observation rather than from the loadURL resolution.

Posted via Macroscope — UI Consistency

@t3dotgg

Copy link
Copy Markdown
Member

Note

🤖 GPT-5.6 Sol responding on behalf of Theo

We're closing this PR as we clean up the T3 Code backlog. Thank you for taking the time to put this together.

We selected #8435 as the active OAuth popup path. Its current head installs allowpopups before guest attach, permits hardened HTTP and HTTPS new-window popups, denies nested popups, and keeps target="_blank" links in the preview. This branch takes a broader IPC and bootstrap approach and explicitly allows about:blank OAuth popups. Those different cases remain useful reference while we keep one popup manager in active review.

If you believe we closed this in error, please reopen the PR and leave a comment explaining what we missed.

@t3dotggt3dotgg closed this Aug 28, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L100-499 changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Integrated browser preview blocks OAuth popup authentication

2 participants

@MatthewFeroz@t3dotgg
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

fix(desktop): support OAuth popups in browser previews - #8413

Closed
MatthewFeroz wants to merge 4 commits into
pingdotgg:mainfrom
MatthewFeroz:fix/browser-preview-popups
Closed

fix(desktop): support OAuth popups in browser previews#8413
MatthewFeroz wants to merge 4 commits into
pingdotgg:mainfrom
MatthewFeroz:fix/browser-preview-popups

Conversation

@MatthewFeroz

@MatthewFerozMatthewFeroz commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Fixes#6561.

Browser previews denied every window.open() request and loaded the requested URL in the opener. OAuth libraries therefore reported the popup as blocked, and the opener/child handshake could never run.

This change permits real child windows for HTTP, HTTPS, and exact about:blank targets. Each child shares the opener session, runs sandboxed without Node or nested webviews, closes with its opener, and cannot create another popup. Unsafe and malformed URLs remain blocked through the shared preview URL validation.

The preview webview now attaches at about:blank and sends its intended URL through the typed registration IPC. The main process installs the popup policy before loading that URL, while preserving any newer navigation already queued for the tab.

This ports the sound parts of #6620 to current main and includes the URL-validation intent from #6156.

Verification:

  • vp test run apps/desktop/src/preview/Manager.test.ts apps/desktop/src/ipc/methods/preview.test.ts
  • vp run --filter @t3tools/desktop typecheck
  • vp run --filter @t3tools/web typecheck
  • vp run --filter @t3tools/contracts typecheck
  • Targeted vp lint and vp fmt --check on all changed files

Made with GPT-5.6 Sol in T3 Code using the Codex harness.


Note

Medium Risk
Changes preview navigation, popup policy, and OAuth-related window behavior in Electron; mis-handled initialUrl could leave previews stuck on about:blank, while popup session sharing affects login flows.

Overview
Desktop browser previews no longer treat every window.open() as navigation in the opener. PreviewManager installs a setWindowOpenHandler that allows sandboxed child windows for validated http/https URLs and exact about:blank, shares the guest session, parents them to the host window when possible, and denies unsafe schemes plus nested popups from auth windows.

Registration bootstrap changes so popups are configured before the first real load: registerWebview gains optional initialUrl end-to-end (contracts IPC schema, preload, IPC handler). The hosted <webview> always mounts at about:blank with allowpopups="true" and passes the intended URL at registration; the main process loads it after listeners are attached, keeps loading state through blank guest events, and strips the placeholder about:blank history entry when appropriate without racing newer navigations or replaced guests.

Reviewed by Cursor Bugbot for commit 4a1d865. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Allow OAuth popups in desktop browser previews via main-process URL loading

  • Webview registration now accepts an initialUrl that the main process loads after installing popup policy and listeners, replacing direct src navigation on the webview element.
  • Popups opened from a preview are restricted to about:blank and normalizable http/https URLs; approved popups open in a separate sandboxed BrowserWindow with no nodeIntegration or webviewTag, sharing the parent session. Nested popups are denied and child windows hide the menu bar.
  • The initial about:blank placeholder entry is removed from navigation history after the bootstrap URL loads; did-stop-loading from about:blank no longer overwrites a pending bootstrap navigation in syncWebContentsState.
  • The PreviewWebview alias forces allowpopups as a string attribute so Electron receives it before guest attach, replacing the previous imperative setAttribute call.
  • Behavioral Change: desktopBridge.preview.registerWebview and the IPC schema in ipc.ts now require a nullable initialUrl argument; any caller not updated will fail type validation.

Macroscope summarized 4a1d865.

request provenance

@coderabbitai

coderabbitaiBot commented Aug 27, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: f55412b5-890c-411c-b009-826f241ab278

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Comment @coderabbitai help to get the list of available commands.

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:L 100-499 changed lines (additions + deletions). labels Aug 27, 2026
Comment threadapps/desktop/src/preview/Manager.ts
Comment threadapps/desktop/src/preview/Manager.ts
@macroscopeapp

macroscopeappBot commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — This PR adds OAuth popup authentication support and changes preview bootstrap navigation, popup window security, and navigation-history behavior across production desktop and web paths. An unresolved failure case can leave Back navigation enabled to return to the blank bootstrap page when loading fails or is superseded.

You can add or adjust custom eligibility rules. Learn more.

Co-authored-by: Matthew Feroz <136640686+MatthewFeroz@users.noreply.github.com>

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One concern with the new about:blank bootstrap in HostedBrowserWebview — see the inline note on the guest's navigation history / Back button state.

Posted via Macroscope — UI Consistency

Comment threadapps/web/src/browser/HostedBrowserWebview.tsx
Co-authored-by: Matthew Feroz <136640686+MatthewFeroz@users.noreply.github.com>

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 76c040d. Configure here.

Comment threadapps/desktop/src/preview/Manager.ts
Remove only the captured about:blank entry after the bootstrap load, and serialize that removal with preview state updates. This keeps newer navigation history intact and prevents detached guests from publishing stale Back state.
Reported-by: Cursor Bugbot

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One finding on the preview guest bootstrap: the about:blank placeholder history entry is only cleaned up when the bootstrap load resolves, so a failed or aborted first load leaves the preview's Back button enabled and pointing at a blank page.

Posted via Macroscope — UI Consistency

key={webviewGeneration}
ref={setWebviewRef}
src={webviewGeneration === 0 ? initialSrc : recoverySrc}
src="about:blank"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pinning src to about:blank and deferring the real navigation to registerWebview makes the blank page a real guest history entry, and the cleanup for it only runs on success: in apps/desktop/src/preview/Manager.tsremoveBootstrapNavigationEntry is wired through Effect.tap on the loadURL promise, so it is skipped whenever that promise rejects (ERR_CONNECTION_REFUSED on a dev server that is not up yet, or ERR_ABORTED when a redirect/subsequent navigate supersedes the bootstrap load). Chromium still commits the error page / next page as entry 1, so syncWebContentsState publishes canGoBack: true and PreviewChromeRow's Back button stays enabled for the life of the tab, sending the preview back to a blank page. Before this change the target URL was the guest's first entry, so Back stayed disabled.

Smallest fix is on the desktop side: run the placeholder removal on both outcomes (e.g. Effect.onExit/ensuring instead of Effect.tap, still guarded by the existing generation/webContents identity checks), or drop the placeholder entry from a did-navigate/did-fail-load observation rather than from the loadURL resolution.

Posted via Macroscope — UI Consistency

@t3dotgg

Copy link
Copy Markdown
Member

Note

🤖 GPT-5.6 Sol responding on behalf of Theo

We're closing this PR as we clean up the T3 Code backlog. Thank you for taking the time to put this together.

We selected #8435 as the active OAuth popup path. Its current head installs allowpopups before guest attach, permits hardened HTTP and HTTPS new-window popups, denies nested popups, and keeps target="_blank" links in the preview. This branch takes a broader IPC and bootstrap approach and explicitly allows about:blank OAuth popups. Those different cases remain useful reference while we keep one popup manager in active review.

If you believe we closed this in error, please reopen the PR and leave a comment explaining what we missed.

@t3dotggt3dotgg closed this Aug 28, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L100-499 changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Integrated browser preview blocks OAuth popup authentication

2 participants

@MatthewFeroz@t3dotgg