Skip to content

feat(webauthn): Touch ID + Google passkey sign-in via patched from-source CEF#25

Merged
wenkaifan0720 merged 2 commits into
mainfrom
feat/webauthn-passkey-auth-window
Jul 22, 2026
Merged

feat(webauthn): Touch ID + Google passkey sign-in via patched from-source CEF#25
wenkaifan0720 merged 2 commits into
mainfrom
feat/webauthn-passkey-auth-window

Conversation

@wenkaifan0720

Copy link
Copy Markdown
Collaborator

What

Adds on-device Touch ID passkeys and Google-account QR/phone-passkey sign-in to the CEF webview, via a patched from-source CEF — Tier-2 (build libcef with a 13-line patch), not a Chromium fork.

Two independent pieces:

  1. openAuthWindow op (protocol v3 → v4) — new IPC op 0x39 that opens a windowed Chrome-runtime browser (CEF_RUNTIME_STYLE_CHROME) sharing the OSR tile's cookie jar. The OSR/windowless tile can't host WebAuthn UI; this runs the ceremony in a window that can. Plumbed main.mmFlutterCefPlugin.swift / CefWebSession.swift / CefProfileHost.swiftcef_web_controller.dart (openAuthWindow(url)).

  2. From-source patched CEFnative/build-cef-from-source.sh fetches Chromium+CEF at the pinned rev and applies one 13-line patch (native/patches/campus_webauthn_keychain.patch) that hardcodes the KLAJ5X6PJP team prefix on the WebAuthn keychain-access-group. Unbranded CEF derives it from an empty MAC_TEAM_IDENTIFIER_STRING.org.chromium.Chromium.webauthn, which no entitlement can match, so Touch ID is unreachable without this.

Why the build config matters

is_official_build=true is load-bearing three ways — don't downgrade to a bare dcheck_always_on=false build:

  • matches how the stock Spotify prebuilt is built;
  • strips DCHECKs (a plain build crashes at chrome_paths_mac.mm on CEF's Versions/A layout);
  • fixes Google-account caBLE/QR passkey sign-in — a non-official build breaks it ("Something went wrong" after the email step); the official build completes the flow.

proprietary_codecs=true ffmpeg_branding="Chrome" add H.264/AAC — royalty-bearing (MPEG-LA / Via-LA). Gate prod distribution on legal sign-off.

No-drift

A patched framework under the same CEF_VERSION would collide with the stock content hash → every consumer silently fetches the unpatched framework. CEF_FRAMEWORK_VARIANT (campus-webauthn-h264) is folded into cef_host_hash.sh's digest so the patched build gets a distinct GCS key, and build_cef_host.sh hard-fails if the marker is non-stock but the framework lacks the patch. The stock digest is byte-identical to before (no republish of the existing stock host).

Testing

Notarized Campus dev build, user-confirmed:

  • ✅ webauthn.io Touch ID registration/auth
  • ✅ Google-account QR / phone-passkey sign-in completes (reaches Google's "add a passkey" enrollment page)

Note: the -67030 process_requirement.cc log line is a benign red herring — present in the working build too. Ignore it; watch the actual login flow.

Merge / rollout notes

  • After merge, publish the patched cef_host prebuilt for its new content hash (make publish-cef-host) so consumers fetch it instead of a ~2 hr local build.
  • work_canvas then bumps its pin to this merge SHA (make pin-cef) — companion PR.
  • entitlements.browser.plist is a documented hand-apply reference; the work_canvas release script derives browser entitlements from the provisioning profile at sign time.

🤖 Generated with Claude Code

wenkaifan0720 and others added 2 commits July 21, 2026 21:13
…ed from-source CEF

OSR/windowless browsers can't host the WebAuthn UI, and unbranded CEF can't
reach the macOS platform authenticator (Touch ID / Secure Enclave) at all --
its keychain-access-group derives from an empty MAC_TEAM_IDENTIFIER_STRING, so
it asks for ".org.chromium.Chromium.webauthn", which no entitlement can match.

This adds first-class passkey support in two independent pieces:

1. openAuthWindow op (protocol v3 -> v4): a new IPC op (0x39) that opens a
   windowed Chrome-runtime browser (CEF_RUNTIME_STYLE_CHROME) sharing the OSR
   tile's cookie jar, so the sign-in ceremony runs somewhere that can host the
   WebAuthn UI the off-screen tile cannot. Plumbed through main.mm ->
   FlutterCefPlugin.swift / CefWebSession.swift / CefProfileHost.swift ->
   cef_web_controller.dart (openAuthWindow(url)).

2. From-source patched CEF build: native/build-cef-from-source.sh fetches
   Chromium+CEF at the pinned rev and applies ONE 13-line patch
   (native/patches/campus_webauthn_keychain.patch) hardcoding the KLAJ5X6PJP
   team prefix on the keychain group. This is Tier-2 (build libcef from source
   with a patch), NOT a Chromium fork -- the patch is a single entry in CEF's
   own patch.cfg pipeline.

   Build config is load-bearing: is_official_build=true (matches the stock
   Spotify prebuilt, strips DCHECKs, and -- critically -- fixes Google-account
   caBLE/QR passkey sign-in that a non-official build breaks). H.264/AAC via
   proprietary_codecs + ffmpeg_branding="Chrome" (royalty-bearing; gate prod
   distribution on legal sign-off).

No-drift: a patched framework built under the same CEF_VERSION would otherwise
collide with the stock content hash and every consumer would silently fetch the
UNPATCHED framework. CEF_FRAMEWORK_VARIANT ("campus-webauthn-h264") is folded
into cef_host_hash.sh's digest so the patched build gets a DISTINCT GCS key, and
build_cef_host.sh hard-fails if the marker is non-stock but the framework lacks
the patch.

Signing: the passkey keychain group needs the browser (top-level cef_host)
process entitled + an embedded Developer-ID provisioning profile blessing that
group; helpers keep the minimal entitlements. entitlements.browser.plist
documents the browser-process superset (the work_canvas release script derives
it from the profile at sign time).

Tested: webauthn.io Touch ID and Google-account QR/phone-passkey sign-in both
complete end-to-end in a notarized Campus dev build (reaches Google's passkey
enrollment page). The -67030 process_requirement log line is a benign red
herring -- present in the working build too.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…-in, doc)

Adversarial audit follow-ups (all low-severity, none blocking):

- security: validate URL scheme (http/https only) at the openAuthWindow entry in
  both the Swift session (authoritative chokepoint) and the Dart controller, so
  the cookie-bearing Chrome-runtime window can't be opened at a javascript:/
  data:/file:/about: URL -- mirrors the scheme gate the OSR tile's navigate has.
- build: fold native/patches/** + build-cef-from-source.sh into cef_host_hash.sh
  (non-stock variants ONLY, so the stock digest stays byte-identical -- no
  republish). Without it, editing a patch hunk or a gn-arg without hand-bumping
  CEF_FRAMEWORK_VARIANT yields an identical content hash -> publish
  idempotent-skips -> consumers silently fetch the STALE patched framework.
  Verified: patched digest moves on patch change, stock digest unchanged,
  patched != stock.
- docs: drop the inaccurate "registered condition-gated in cef/patch/patch.cfg"
  claim from build-cef-from-source.sh -- no such registration exists; the patch
  is applied unconditionally via git apply and stock isolation rests entirely on
  the hash + variant-marker machinery.

Deferred (tracked follow-up): the build_cef_host.sh variant guard hard-fails
opt-in from-source builds lacking the patched framework (x86_64 / offline /
FLUTTER_CEF_FROM_SOURCE co-dev); the normal fetch-or-skip pod-install path is
unaffected. Needs a design call on gating the guard to release builds only.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@wenkaifan0720

Copy link
Copy Markdown
Collaborator Author

Final audit (5-lens adversarial review) — no merge-blockers

Two highest-risk dimensions came back clean: C++/CEF correctness in main.mm (op handling, AuthWindowClient lifetime, threading, URL bounds) and the protocol v3→v4 plumbing (every op-byte/version site agrees across native/Swift/Dart — no silent-frozen-tile risk).

4 low-severity findings, 0 false positives. Fixed 3 in 238b49d:

Finding Severity Status
openAuthWindow opens its URL with no scheme check (vs navigate's gate) low ✅ fixed — http(s)-only guard at the Swift + Dart entry
cef_host_hash.sh omits patches/** + build-cef-from-source.sh → patched-v1↔v2 drift undetected low ✅ fixed — folded in (non-stock only; stock digest byte-stable; verified)
Comment claims patch.cfg gating that doesn't exist low ✅ fixed — corrected
Variant guard hard-fails opt-in from-source builds (x86_64/offline/co-dev) low ⏭️ deferred → #26 (normal fetch-or-skip path unaffected; needs a design call)

@wenkaifan0720
wenkaifan0720 merged commit 9cd3f3a into main Jul 22, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant