authorgravatar for me@t3.ggTheo Browne <me@t3.gg> 2026-08-19 06:59:26-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-08-19 03:59:26-07:00
logf2d5fc91e3030e5c3956fdadc13e1eaa25bcabe3
tree73cf06dd171b24cd61e96bc37001f795eb6d671b
parent24c4ba68f536d56e8482a1e4d7070a6771da551d
signature Signed by PGP key B5690EEEBB952194

fix(desktop): stop automatic passkey prompts (#7522)


4 files changed, 105 insertions(+), 44 deletions(-)

apps/web/src/components/clerk/electronPasskeys.test.ts created+60
......@@ -0,0 +1,60 @@
1import { createPasskeys } from "@clerk/electron/passkeys";
2import { afterEach, describe, expect, it, vi } from "vite-plus/test";
3
4const publicKeyOptions = {
5 allowCredentials: [],
6 challenge: new Uint8Array([1]),
7 rpId: "clerk.t3.codes",
8 timeout: 60_000,
9 userVerification: "preferred" as const,
10};
11
12const stubNativePasskeys = () => {
13 const get = vi.fn().mockResolvedValue({
14 ok: false,
15 error: { code: "cancelled", message: "user cancelled" },
16 });
17
18 vi.stubGlobal("location", { protocol: "t3code:", hostname: "app" });
19 vi.stubGlobal("window", {
20 PublicKeyCredential: vi.fn(),
21 __clerk_internal_electron_passkeys: {
22 platform: "darwin",
23 electronMajor: 41,
24 get,
25 },
26 });
27
28 return get;
29};
30
31describe("Electron passkeys", () => {
32 afterEach(() => {
33 vi.unstubAllGlobals();
34 });
35
36 it("does not send an autofill request to the native bridge", async () => {
37 const get = stubNativePasskeys();
38 const passkeys = createPasskeys();
39
40 const result = await passkeys.get({
41 publicKeyOptions,
42 conditionalUI: true,
43 });
44
45 expect(get).not.toHaveBeenCalled();
46 expect(result.error).toMatchObject({ code: "passkey_operation_aborted" });
47 });
48
49 it("sends an explicit passkey request to the native bridge", async () => {
50 const get = stubNativePasskeys();
51 const passkeys = createPasskeys();
52
53 await passkeys.get({
54 publicKeyOptions,
55 conditionalUI: false,
56 });
57
58 expect(get).toHaveBeenCalledOnce();
59 });
60});
apps/web/src/main.tsx+5-9
......@@ -1,7 +1,7 @@
11import React from "react";
22import ReactDOM from "react-dom/client";
33import { ClerkProvider } from "@clerk/react";
4import { passkeys as electronPasskeys } from "@clerk/electron/passkeys";
4import { passkeys } from "@clerk/electron/passkeys";
55import { ClerkProvider as ElectronClerkProvider } from "@clerk/electron/react";
66import { createHashHistory, createBrowserHistory } from "@tanstack/react-router";
77
......@@ -30,14 +30,9 @@ if (isElectron) {
3030
3131const clerkPublishableKey = import.meta.env.VITE_CLERK_PUBLISHABLE_KEY as string | undefined;
3232
33// @clerk/electron reports passkey autofill as supported but executes the
34// "quiet" autofill request as a modal prompt, so Clerk's sign-in form pops an
35// OS passkey dialog the moment it mounts. Report autofill as unsupported; the
36// explicit "Use passkey" button keeps working.
37// Upstream: https://github.com/clerk/javascript/issues/9496
38const passkeys = {
39 ...electronPasskeys,
40 isAutoFillSupported: () => Promise.resolve(false),
33// First Clerk UI build containing https://github.com/clerk/javascript/pull/9500.
34const electronClerkUI = {
35 __internal_clerkUIVersion: "1.30.5-canary.v20260819050620",
4136};
4237
4338const app = <AppRoot router={router} />;
......@@ -47,6 +42,7 @@ ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
4742 {clerkPublishableKey && hasCloudPublicConfig() ? (
4843 isElectron ? (
4944 <ElectronClerkProvider
45 {...electronClerkUI}
5046 appearance={clerkAppearance}
5147 publishableKey={clerkPublishableKey}
5248 passkeys={passkeys}
pnpm-lock.yaml+32-32
......@@ -46,8 +46,8 @@ overrides:
4646 '@clerk/clerk-js>@solana/wallet-adapter-react': '-'
4747 '@clerk/clerk-js>@solana/wallet-standard': '-'
4848 '@clerk/clerk-js>@wallet-standard/core': '-'
49 '@clerk/electron': 0.0.33
50 '@clerk/electron-passkeys': 0.0.3
49 '@clerk/electron': 0.0.34-canary.v20260819050620
50 '@clerk/electron-passkeys': 0.0.4-canary.v20260819050620
5151 '@clerk/expo': 4.2.0
5252 '@clerk/react': 6.14.4
5353 '@clerk/shared': 4.29.2
......@@ -114,11 +114,11 @@ importers:
114114 apps/desktop:
115115 dependencies:
116116 '@clerk/electron':
117 specifier: 0.0.33
118 version: 0.0.33(@clerk/electron-passkeys@0.0.3)(electron-store@8.2.0)(electron@41.5.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
117 specifier: 0.0.34-canary.v20260819050620
118 version: 0.0.34-canary.v20260819050620(@clerk/electron-passkeys@0.0.4-canary.v20260819050620)(electron-store@8.2.0)(electron@41.5.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
119119 '@clerk/electron-passkeys':
120 specifier: 0.0.3
121 version: 0.0.3
120 specifier: 0.0.4-canary.v20260819050620
121 version: 0.0.4-canary.v20260819050620
122122 '@effect/platform-node':
123123 specifier: 4.0.0-beta.103
124124 version: 4.0.0-beta.103(bufferutil@4.1.0)(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6))(ioredis@5.11.0)(utf-8-validate@6.0.6)
......@@ -520,8 +520,8 @@ importers:
520520 specifier: ^1.4.1
521521 version: 1.5.0(@types/react@19.2.16)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
522522 '@clerk/electron':
523 specifier: 0.0.33
524 version: 0.0.33(@clerk/electron-passkeys@0.0.3)(electron-store@8.2.0)(electron@41.5.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
523 specifier: 0.0.34-canary.v20260819050620
524 version: 0.0.34-canary.v20260819050620(@clerk/electron-passkeys@0.0.4-canary.v20260819050620)(electron-store@8.2.0)(electron@41.5.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
525525 '@clerk/react':
526526 specifier: 6.14.4
527527 version: 6.14.4(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
......@@ -1721,35 +1721,35 @@ packages:
17211721 resolution: {integrity: sha512-4i4RE+ZQ0hKDDFSRKCISQPBy07SfFeFAhBUhNj2j01Nx2n4pqV+5iyg2Vf27+NKFNkgq7kdmZGvtug24D++8WQ==}
17221722 engines: {node: '>=20.9.0'}
17231723
1724 '@clerk/electron-passkeys-darwin-arm64@0.0.3':
1725 resolution: {integrity: sha512-oAlrd+GLqP0oREP3hNRc6yNZhXGaQgJss9iCWRQqXjpw1yZD1ZU+L+E2Gfg84vMj/NSUhxbU0Djy0RXhmeUwgg==}
1724 '@clerk/electron-passkeys-darwin-arm64@0.0.4-canary.v20260819050620':
1725 resolution: {integrity: sha512-avxygtEfWBD3YPkxws4lB5mL/75SQvVBMQCg+b1gjFsQInnVOgAqAv4wHR8wgUsEbXY2zEkvqaYjFSnEveC0VA==}
17261726 cpu: [arm64]
17271727 os: [darwin]
17281728
1729 '@clerk/electron-passkeys-darwin-x64@0.0.3':
1730 resolution: {integrity: sha512-0UPAWQEni7o8gjWwd2sP97fPshJmT2w5b8eV/jOPVSP8NqIcFCm5yIFSEx1SfB53LGfzB01A4iEGi2pxiCHqyQ==}
1729 '@clerk/electron-passkeys-darwin-x64@0.0.4-canary.v20260819050620':
1730 resolution: {integrity: sha512-clShldbwDcC2ek6gJT85QKsMfaPyOhEgfz61u2n3YKivbeui33XjJu261d+LO20mqDjXZy3flLGPTIh/Kii80g==}
17311731 cpu: [x64]
17321732 os: [darwin]
17331733
1734 '@clerk/electron-passkeys-win32-arm64-msvc@0.0.3':
1735 resolution: {integrity: sha512-bbRvifm9A/gfPkwC1UyMyF9sYGEs0aen7J2kCcaOIW3K0PXcAbHtsR/gnx4dT0bjFdd21vSa2zlIdERvHc1BiA==}
1734 '@clerk/electron-passkeys-win32-arm64-msvc@0.0.4-canary.v20260819050620':
1735 resolution: {integrity: sha512-alIfXJSxyeulnNeHoT4X7+qO0o9/EBhiRWMhCXwKJIbWfwzqnnVrRH1P7HfYRnDepKhqRzsUaBuYTqQzisHG+A==}
17361736 cpu: [arm64]
17371737 os: [win32]
17381738
1739 '@clerk/electron-passkeys-win32-x64-msvc@0.0.3':
1740 resolution: {integrity: sha512-gFaVqKlOKTF2SJ3lMwkZ0oonycQn93p1qSrp5kzzeZBeQ+tGB3gQnjXecrhQy21AzDUyWqVJJ8KrP2HRAwifWg==}
1739 '@clerk/electron-passkeys-win32-x64-msvc@0.0.4-canary.v20260819050620':
1740 resolution: {integrity: sha512-QSKKMCdV9AhOt74ls8ExdwR+2ikoLGgN2LdWIjBgNk6epJVs2L1FXVZOM0ZqfVHFSl5y7vLmlOACR6WyJ2eoLg==}
17411741 cpu: [x64]
17421742 os: [win32]
17431743
1744 '@clerk/electron-passkeys@0.0.3':
1745 resolution: {integrity: sha512-OHhIe88qDL+FxyBalXdXNHAS5eEramr6Rerp+6iNkfkjqT8rx4hHNmfpmjg5/T1/am8QfknbOBZkqoXZlCrjPg==}
1744 '@clerk/electron-passkeys@0.0.4-canary.v20260819050620':
1745 resolution: {integrity: sha512-zOoFEsvOrArv7p4ERNAdkGbYoD86ragDhysLG1NdxJm2jnfw+AfwxUv0FkOPZ7iNuQ0rbJaR/urxdvEwVcuKRA==}
17461746 engines: {node: '>=20.9.0'}
17471747
1748 '@clerk/electron@0.0.33':
1749 resolution: {integrity: sha512-lP2B7wGHwKWrCAh4zPWPfRUIHoxQ1rwG8iiFeLmI8jBjSGcSoPX1N9bIKUCWL+Z9POmC2aRn6yXvL7e9yzfEVw==}
1748 '@clerk/electron@0.0.34-canary.v20260819050620':
1749 resolution: {integrity: sha512-sfKWkH2SigKcxtR+h36G1NGnmMI5xOlwvqHpr3JYcacS/uokQbeAjCCQzEeV/9zqWYtRL4et5wCD13+gWv4b6w==}
17501750 engines: {node: '>=20.9.0'}
17511751 peerDependencies:
1752 '@clerk/electron-passkeys': 0.0.3
1752 '@clerk/electron-passkeys': 0.0.4-canary.v20260819050620
17531753 electron: '>=28'
17541754 electron-store: ^8.2.0
17551755 react: ^18.0.0 || ~19.0.3 || ~19.1.4 || ~19.2.3 || ~19.3.0-0
......@@ -11580,26 +11580,26 @@ snapshots:
1158011580 - react
1158111581 - react-dom
1158211582
11583 '@clerk/electron-passkeys-darwin-arm64@0.0.3':
11583 '@clerk/electron-passkeys-darwin-arm64@0.0.4-canary.v20260819050620':
1158411584 optional: true
1158511585
11586 '@clerk/electron-passkeys-darwin-x64@0.0.3':
11586 '@clerk/electron-passkeys-darwin-x64@0.0.4-canary.v20260819050620':
1158711587 optional: true
1158811588
11589 '@clerk/electron-passkeys-win32-arm64-msvc@0.0.3':
11589 '@clerk/electron-passkeys-win32-arm64-msvc@0.0.4-canary.v20260819050620':
1159011590 optional: true
1159111591
11592 '@clerk/electron-passkeys-win32-x64-msvc@0.0.3':
11592 '@clerk/electron-passkeys-win32-x64-msvc@0.0.4-canary.v20260819050620':
1159311593 optional: true
1159411594
11595 '@clerk/electron-passkeys@0.0.3':
11595 '@clerk/electron-passkeys@0.0.4-canary.v20260819050620':
1159611596 optionalDependencies:
11597 '@clerk/electron-passkeys-darwin-arm64': 0.0.3
11598 '@clerk/electron-passkeys-darwin-x64': 0.0.3
11599 '@clerk/electron-passkeys-win32-arm64-msvc': 0.0.3
11600 '@clerk/electron-passkeys-win32-x64-msvc': 0.0.3
11597 '@clerk/electron-passkeys-darwin-arm64': 0.0.4-canary.v20260819050620
11598 '@clerk/electron-passkeys-darwin-x64': 0.0.4-canary.v20260819050620
11599 '@clerk/electron-passkeys-win32-arm64-msvc': 0.0.4-canary.v20260819050620
11600 '@clerk/electron-passkeys-win32-x64-msvc': 0.0.4-canary.v20260819050620
1160111601
11602 '@clerk/electron@0.0.33(@clerk/electron-passkeys@0.0.3)(electron-store@8.2.0)(electron@41.5.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)':
11602 '@clerk/electron@0.0.34-canary.v20260819050620(@clerk/electron-passkeys@0.0.4-canary.v20260819050620)(electron-store@8.2.0)(electron@41.5.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)':
1160311603 dependencies:
1160411604 '@clerk/clerk-js': 6.29.2(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
1160511605 '@clerk/react': 6.14.4(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
......@@ -11608,7 +11608,7 @@ snapshots:
1160811608 react: 19.2.6
1160911609 tslib: 2.8.1
1161011610 optionalDependencies:
11611 '@clerk/electron-passkeys': 0.0.3
11611 '@clerk/electron-passkeys': 0.0.4-canary.v20260819050620
1161211612 electron-store: 8.2.0
1161311613 react-dom: 19.2.6(react@19.2.6)
1161411614
pnpm-workspace.yaml+8-3
......@@ -25,8 +25,8 @@ allowBuilds:
2525catalog:
2626 "@clerk/backend": 3.14.0
2727 "@clerk/clerk-js": 6.29.2
28 "@clerk/electron": 0.0.33
29 "@clerk/electron-passkeys": 0.0.3
28 "@clerk/electron": 0.0.34-canary.v20260819050620
29 "@clerk/electron-passkeys": 0.0.4-canary.v20260819050620
3030 "@clerk/expo": 4.2.0
3131 "@clerk/react": 6.14.4
3232 "@clerk/shared": 4.29.2
......@@ -55,7 +55,8 @@ catalog:
5555minimumReleaseAgeExclude:
5656 - "@clerk/backend@3.14.0"
5757 - "@clerk/clerk-js@6.29.2"
58 - "@clerk/electron@0.0.33"
58 - "@clerk/electron@0.0.34-canary.v20260819050620"
59 - "@clerk/electron-passkeys@0.0.4-canary.v20260819050620"
5960 - "@clerk/expo@4.2.0"
6061 - "@clerk/react@6.14.4"
6162 - "@clerk/shared@4.29.2"
......@@ -76,6 +77,10 @@ minimumReleaseAgeExclude:
7677 - alchemy@2.0.0-beta.65
7778 - effect@4.0.0-beta.103
7879 - "@legendapp/list@3.3.5"
80 - "@clerk/electron-passkeys-darwin-arm64@0.0.4-canary.v20260819050620"
81 - "@clerk/electron-passkeys-darwin-x64@0.0.4-canary.v20260819050620"
82 - "@clerk/electron-passkeys-win32-arm64-msvc@0.0.4-canary.v20260819050620"
83 - "@clerk/electron-passkeys-win32-x64-msvc@0.0.4-canary.v20260819050620"
7984
8085overrides:
8186 "@clerk/backend": "catalog:"