Skip to content

fix(desktop): offer passkeys on Microsoft sign-in in the preview browser - #30047

Closed
juliusmarminge wants to merge 2 commits into
mainfrom
fix/issue-30014
Closed

juliusmarminge wants to merge 2 commits into
mainfrom
fix/issue-30014

Conversation

@juliusmarminge

@juliusmarminge juliusmarminge commented Nov 3, 2026 •

Copy link
Copy Markdown
Member

Problem

Microsoft sign-in (Entra and Microsoft accounts) in the desktop preview browser does not offer passkeys. Microsoft decides this from the User-Agent request header: when it contains Electron/<version>, the server leaves passkeys out of the sign-in page config ($Config.fIsFidoSupported), so "Face, fingerprint, PIN or security key" never appears. On main (cefb544af3), opening the Entra authorize page in a preview tab and clicking "Sign-in options" shows only GitHub and "Sign in to an organization".

Change

Each preview session now registers a webRequest.onBeforeSendHeaders listener for login.microsoftonline.com, login.microsoft.com and login.live.com. It removes only the Electron/<version> token from the outgoing User-Agent header. The session User-Agent and navigator.userAgent stay native, and every other host still gets the native header. A rewritten session User-Agent breaks Cloudflare Turnstile (see the existing "keeps the guest's effective User-Agent equal to Electron's native one" test).

Scope and approval

Fixes #30014

Verification

  • vp test run apps/desktop/src/preview/BrowserSession.test.ts: 9/9 pass. The new test, "drops only the Electron/ token from the User-Agent sent to Microsoft sign-in", fails on main:
    AssertionError: preview sessions send the Electron/ token to Microsoft sign-in (https://login.microsoftonline.com/common/oauth2/v2.0/authorize?client_id=x&response_type=code)
    Expected: "… T3CodeDev/44.10.0 Chrome/152.0.7977.169 Safari/537.36"
    Received: "… T3CodeDev/44.10.0 Chrome/152.0.7977.169 Electron/44.10.0 Safari/537.36"
    
    In the same test, a challenges.cloudflare.com request keeps the native header.
  • Real desktop app, Linux, Electron 44.10.0 / Chromium 152, under Xvfb. Before = cefb544af3, after = 773c709d4a, each run from its own checkout with a fresh database and no account. A preview tab opened the Entra authorize page (public Office client id) and "Sign-in options". The User-Agent that was actually sent was read with a session.webRequest.onSendHeaders observer; nothing was added to the fix's listener.
Build Host Sent User-Agent ends with navigator.userAgent Entra/Live FIDO flag Passkey option in Sign-in options
before cefb544af3 login.microsoftonline.com Chrome/152.0.7977.169 Electron/44.10.0 Safari/537.36 native $Config.fIsFidoSupported absent absent
after 773c709d4a login.microsoftonline.com Chrome/152.0.7977.169 Safari/537.36 native (unchanged) $Config.fIsFidoSupported: true "Face, fingerprint, PIN or security key — Use your device to sign in with a passkey"
before / after login.live.com with / without Electron/44.10.0 native ServerData.fIsFidoSupported false → true not checked
before / after login.microsoft.com (302 → office.com → login.microsoftonline.com) with / without Electron/44.10.0 native n/a n/a
before / after demo.turnstile.workers.dev and the challenges.cloudflare.com frame native on both builds, byte-identical native n/a the Turnstile widget succeeds on both builds

On login.live.com, Microsoft serves a different sign-in layout from request to request (sClientRingId R1/R2/R3 changes across repeated fetches with the same User-Agent). Only fIsFidoSupported follows the Electron/ token. Without the token, the response matches what a plain Chrome User-Agent gets (fIsFidoSupported: true, three fetches each).

Visible difference on Entra's Sign-in options card (Linux): the passkey row is added, the card grows 72 px and re-centres, and initial focus moves to the new first row. Nothing else in the T3 window changes.

Before/after stills, zero-threshold and 2% diff images, and interaction recordings were captured but are not embedded in this body.

Not verified:

  • cannot-verify windows: the reporter's Windows 11 flow with Windows Hello / 1Password and an enrolled work account. No full passkey sign-in was completed; the Linux run proves only that Microsoft now offers passkeys.
  • cannot-verify macos, and Windows again: once the token is gone, the Entra authorize URL with a Windows or macOS User-Agent returns Microsoft's "Redirecting" single-sign-on check page (BssoInterrupt, overallTimeoutMs: 4000) before the sign-in form, just as Chrome on those platforms does. With the token it returns the sign-in form directly. Linux gets the form directly either way. Seen with curl only; how long this hop takes inside the Electron preview has not been measured.
  • Turnstile with a production site key. The demo uses Cloudflare's always-pass test key. The header Cloudflare receives is byte-identical before and after, which is what the Turnstile constraint depends on.
  • Regional and government Microsoft sign-in hosts (login.microsoftonline.us, login.partner.microsoftonline.cn, *.b2clogin.com) are not covered by this change.

Triaged, fixed and verified by Claude Opus 5.5 (Claude Code harness) as lead, with Claude Opus 5.5 and GPT-6.1-sol (Codex) step agents.

🤖 Generated with Claude Code

juliusmarminge and others added 2 commits November 3, 2026 08:14
… sign-in

Microsoft sign-in hosts hide passkeys when the User-Agent request header
carries an Electron/ token. This test fails on main because preview
sessions register no onBeforeSendHeaders listener, so the native UA
(Electron/ included) is sent to login.microsoftonline.com,
login.microsoft.com and login.live.com, while other hosts must keep it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Entra and Microsoft account sign-in hide the passkey option when the
User-Agent request header contains an Electron/ token. The preview
session keeps Electron's native User-Agent because rewriting it breaks
Cloudflare Turnstile (#7110).

Preview sessions now register an onBeforeSendHeaders listener for
login.microsoftonline.com, login.microsoft.com and login.live.com. It
removes only the " Electron/<version>" token from the User-Agent header.
navigator.userAgent and every other host keep the native value.

Fixes #30014

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions github-actions Bot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:S 10-29 changed lines (additions + deletions). labels Nov 3, 2026
@macroscopeapp

macroscopeapp Bot commented Nov 3, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs Human Approval

Macroscope's review found this PR requires human approval — The preview browser will automatically omit Electron identification on three Microsoft sign-in hosts so passkeys become available, while other hosts remain unchanged. A human must confirm the change to the default Microsoft sign-in experience.

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

@coderabbitai

coderabbitai Bot commented Nov 3, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

No actionable comments were generated in the recent review.

Walkthrough

BrowserSession now removes the Electron token from outgoing User-Agent headers for three Microsoft sign-in hosts. Tests cover the matching URLs, an unrelated Cloudflare URL, and the request-header callback.

Changes: Microsoft sign-in User-Agent handling

Layer / File(s) Summary
Register and validate the Microsoft sign-in header rewrite
apps/desktop/src/preview/BrowserSession.ts, apps/desktop/src/preview/BrowserSession.test.ts
BrowserSession registers a before-send-headers handler for Microsoft sign-in URLs. The handler removes the Electron token from a present User-Agent header and forwards other headers unchanged. Tests cover the registration and header behavior.

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Bug fix · Severity of issue fixed: Medium

Possibly related PRs

  • pingdotgg/t3code#30018: Addresses the same Entra passkey issue with the same site-specific Electron token removal.
  • pingdotgg/t3code#26771: Uses the same BrowserSession pattern to remove the Electron token for a specific site.

Suggested labels: bugfix, size:S, vouch:unvouched

Suggested reviewers: maria-rcks, macroscopeapp

Merge Risk: Minimal · up to 773c7

The change targets Microsoft sign-in headers. No merge-blocking issue was established.

Pre-merge checks: Passed 4
Check name Status Explanation
Title check Passed The title clearly and concisely identifies the desktop preview browser fix that enables passkeys on Microsoft sign-in.
Linked Issues check Passed Directly linked issue #30014 requires three things: (1) remove only the Electron/<version> token from the User-Agent request header for login.microsoftonline.com, login.microsoft.com and login.live…
Out of Scope Changes check Passed The whole-PR change set (base cefb544 to head 773c709) has two parts. The BrowserSession.ts change adds the URL-filtered header listener and its constants, which are the issue's requested scope.…
Description check Passed The description follows the required structure and clearly explains the problem, change, scope, tests, manual verification, observed results, and unverified cases. It links issue #30014 and provides d…
Full details: Linked Issues check

Explanation

Directly linked issue #30014 requires three things: (1) remove only the Electron/&lt;version&gt; token from the User-Agent request header for login.microsoftonline.com, login.microsoft.com and login.live.com; (2) leave navigator.userAgent and other sites unchanged; (3) let Entra offer the passkey option in the preview browser. The reviewed head adds a webRequest.onBeforeSendHeaders listener in apps/desktop/src/preview/BrowserSession.ts (inside getSession, where the session is created). It applies only to MICROSOFT_SIGN_IN_URLS (the three hosts, /* paths) and replaces ELECTRON_USER_AGENT_TOKEN (/ Electron/[^ ]+/) with an empty string in requestHeaders["User-Agent"]. No navigator.userAgent or session user-agent code changes. The base file has no prior onBeforeSendHeaders listener, so the new listener does not replace an existing one. The test file adds "drops only the Electron/ token from the User-Agent sent to Microsoft sign-in", which covers the Microsoft URLs and a challenges.cloudflare.com request that keeps the native header. The PR reports a Linux run on Electron 44.10.0 where the sent header lacks the Electron token and Entra shows the passkey option; the reported before/after table supports this. Not verified: a Windows 11 passkey sign-in, which the issue reported. The regional Microsoft hosts are not covered, and the issue does not require them.

Full details: Out of Scope Changes check

Explanation

The whole-PR change set (base cefb544 to head 773c709) has two parts. The BrowserSession.ts change adds the URL-filtered header listener and its constants, which are the issue's requested scope. The BrowserSession.test.ts change adds the mocked listener hook and the test for the Microsoft and Turnstile URLs, which supports that behavior. The PR body describes no other code changes. The change does not alter the session User-Agent, navigator.userAgent, the permission handlers, or any other host. No change is unrelated to #30014.

Full details: Description check

Explanation

The description follows the required structure and clearly explains the problem, change, scope, tests, manual verification, observed results, and unverified cases. It links issue #30014 and provides detailed evidence. Screenshots and recordings are mentioned but not embedded, and explicit maintainer approval is not shown, but the description is otherwise complete.

Finishing Touches
Generate docstrings
  • Commit to this branch
  • Create a new PR
Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

CodeRabbit Verify

  • Run CodeRabbit Verify to test the changes in this pull request.
Recent review info
Run configuration
Commits

Reviewing files that changed from the base of the PR and between cefb544 and 773c709.

Files selected for processing: 2
  • apps/desktop/src/preview/BrowserSession.test.ts
  • apps/desktop/src/preview/BrowserSession.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 2 remain after this review.

Copy link
Copy Markdown
Member Author

Closing as a duplicate of #30018, which makes the same host-scoped change and was opened first.

The verification here applies to that PR too. On Linux at 773c709d (Electron 44.10.0), the sent User-Agent loses only Electron/44.10.0 for the three Microsoft hosts, Entra's fIsFidoSupported goes from absent to true, and Sign-in options shows "Face, fingerprint, PIN or security key". With a Windows or macOS User-Agent and no token, Entra's authorize URL first returns its "Redirecting" single-sign-on check page (BssoInterrupt, overallTimeoutMs: 4000); with the token it returns the sign-in form directly. How long that hop takes inside Electron is unmeasured.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:S 10-29 changed lines (additions + deletions). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Entra sign-in hides passkeys in the preview browser because the User-Agent contains Electron/

1 participant