feat(webauthn): Touch ID + Google passkey sign-in via patched from-source CEF#25
Merged
Merged
Conversation
…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>
Collaborator
Author
Final audit (5-lens adversarial review) — no merge-blockersTwo highest-risk dimensions came back clean: C++/CEF correctness in 4 low-severity findings, 0 false positives. Fixed 3 in
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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:
openAuthWindowop (protocol v3 → v4) — new IPC op0x39that 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. Plumbedmain.mm→FlutterCefPlugin.swift/CefWebSession.swift/CefProfileHost.swift→cef_web_controller.dart(openAuthWindow(url)).From-source patched CEF —
native/build-cef-from-source.shfetches Chromium+CEF at the pinned rev and applies one 13-line patch (native/patches/campus_webauthn_keychain.patch) that hardcodes theKLAJ5X6PJPteam prefix on the WebAuthn keychain-access-group. Unbranded CEF derives it from an emptyMAC_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=trueis load-bearing three ways — don't downgrade to a baredcheck_always_on=falsebuild:chrome_paths_mac.mmon CEF'sVersions/Alayout);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_VERSIONwould collide with the stock content hash → every consumer silently fetches the unpatched framework.CEF_FRAMEWORK_VARIANT(campus-webauthn-h264) is folded intocef_host_hash.sh's digest so the patched build gets a distinct GCS key, andbuild_cef_host.shhard-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:
Merge / rollout notes
cef_hostprebuilt for its new content hash (make publish-cef-host) so consumers fetch it instead of a ~2 hr local build.work_canvasthen bumps its pin to this merge SHA (make pin-cef) — companion PR.entitlements.browser.plistis a documented hand-apply reference; thework_canvasrelease script derives browser entitlements from the provisioning profile at sign time.🤖 Generated with Claude Code