From 99d735e764dd2e4845e6fcdb9a586aad1e2aa3eb Mon Sep 17 00:00:00 2001 From: Pixel Perfect Date: Tue, 28 Jul 2026 20:03:26 -0700 Subject: [PATCH 1/2] fix(desktop): restore T3 Connect sign-in --- .../src/components/clerk/authRedirect.test.ts | 22 +++++++++++++++++++ apps/web/src/components/clerk/authRedirect.ts | 4 ++++ .../clerk/useT3ConnectAuthPrompt.tsx | 7 +++++- .../cloud/ConnectCliAuthSurface.tsx | 12 ++++++++-- 4 files changed, 42 insertions(+), 3 deletions(-) create mode 100644 apps/web/src/components/clerk/authRedirect.test.ts create mode 100644 apps/web/src/components/clerk/authRedirect.ts diff --git a/apps/web/src/components/clerk/authRedirect.test.ts b/apps/web/src/components/clerk/authRedirect.test.ts new file mode 100644 index 00000000000..5f35481c7a0 --- /dev/null +++ b/apps/web/src/components/clerk/authRedirect.test.ts @@ -0,0 +1,22 @@ +import { describe, expect, it } from "vite-plus/test"; + +import { resolveClerkAuthRedirectUrl } from "./authRedirect"; + +describe("resolveClerkAuthRedirectUrl", () => { + it("preserves the current browser URL", () => { + const href = "https://app.t3.codes/connect?state=state-1#details"; + expect(resolveClerkAuthRedirectUrl(href, false)).toBe(href); + }); + + it("uses the allowlisted packaged desktop callback", () => { + expect(resolveClerkAuthRedirectUrl("t3code://app/continue#/settings/general", true)).toBe( + "t3code://app/", + ); + }); + + it("uses the allowlisted development desktop callback", () => { + expect(resolveClerkAuthRedirectUrl("t3code-dev://app/continue#/settings/general", true)).toBe( + "t3code-dev://app/", + ); + }); +}); diff --git a/apps/web/src/components/clerk/authRedirect.ts b/apps/web/src/components/clerk/authRedirect.ts new file mode 100644 index 00000000000..6e94309db29 --- /dev/null +++ b/apps/web/src/components/clerk/authRedirect.ts @@ -0,0 +1,4 @@ +export function resolveClerkAuthRedirectUrl(href: string, isElectron: boolean): string { + if (!isElectron) return href; + return new URL("/", href).toString(); +} diff --git a/apps/web/src/components/clerk/useT3ConnectAuthPrompt.tsx b/apps/web/src/components/clerk/useT3ConnectAuthPrompt.tsx index 3a62a5a8589..bcfa30100b5 100644 --- a/apps/web/src/components/clerk/useT3ConnectAuthPrompt.tsx +++ b/apps/web/src/components/clerk/useT3ConnectAuthPrompt.tsx @@ -1,9 +1,14 @@ import { useClerk } from "@clerk/react"; +import { isElectron } from "../../env"; +import { resolveClerkAuthRedirectUrl } from "./authRedirect"; + export function useT3ConnectAuthPrompt() { const clerk = useClerk(); const openAuthPrompt = () => { - clerk.openSignIn({ forceRedirectUrl: window.location.href }); + clerk.openSignIn({ + forceRedirectUrl: resolveClerkAuthRedirectUrl(window.location.href, isElectron), + }); }; return { authPrompt: null, openAuthPrompt }; } diff --git a/apps/web/src/components/cloud/ConnectCliAuthSurface.tsx b/apps/web/src/components/cloud/ConnectCliAuthSurface.tsx index 40ddc4c3dd9..caa0433fc50 100644 --- a/apps/web/src/components/cloud/ConnectCliAuthSurface.tsx +++ b/apps/web/src/components/cloud/ConnectCliAuthSurface.tsx @@ -8,8 +8,10 @@ import { readConnectCliCallbackResult, rememberConnectCliAuthState, } from "../../cloud/connectCliAuth"; +import { isElectron } from "../../env"; import { useCopyToClipboard } from "../../hooks/useCopyToClipboard"; import { AuthSurfaceShell } from "../auth/AuthSurfaceShell"; +import { resolveClerkAuthRedirectUrl } from "../clerk/authRedirect"; import { Button } from "../ui/button"; function ConnectCliAuthMessage({ @@ -59,7 +61,9 @@ export function ConnectCliAuthorizeSurface() { if (!isSignedIn) { if (!signInOpened.current) { signInOpened.current = true; - clerk.openSignIn({ forceRedirectUrl: window.location.href }); + clerk.openSignIn({ + forceRedirectUrl: resolveClerkAuthRedirectUrl(window.location.href, isElectron), + }); } return; } @@ -95,7 +99,11 @@ export function ConnectCliAuthorizeSurface() {
From e2dd22bdc0001e5bc494c0f99373201e69de6b78 Mon Sep 17 00:00:00 2001 From: Julius Marminge Date: Wed, 29 Jul 2026 10:51:24 +0200 Subject: [PATCH 2/2] fix(desktop): omit Clerk redirect override on Electron instead of normalizing it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The pre-GA flow signed in with Clerk's default redirects and worked; the GA change broke desktop by forcing window.location.href, whose page-derived URL fails Clerk's native redirect allowlist. Rather than passing a normalized root URL, drop the override entirely on Electron so the sign-in request is identical to the previously working configuration — @clerk/electron's OAuth transport already supplies the allowlisted t3code://app/ callback. Browser flows keep returning to the exact page that started auth. Co-Authored-By: Claude Fable 5 --- .../src/components/clerk/authRedirect.test.ts | 20 ++++++++----------- apps/web/src/components/clerk/authRedirect.ts | 14 ++++++++++--- .../clerk/useT3ConnectAuthPrompt.tsx | 6 ++---- .../cloud/ConnectCliAuthSurface.tsx | 10 +++------- 4 files changed, 24 insertions(+), 26 deletions(-) diff --git a/apps/web/src/components/clerk/authRedirect.test.ts b/apps/web/src/components/clerk/authRedirect.test.ts index 5f35481c7a0..4c4cd72d932 100644 --- a/apps/web/src/components/clerk/authRedirect.test.ts +++ b/apps/web/src/components/clerk/authRedirect.test.ts @@ -1,22 +1,18 @@ import { describe, expect, it } from "vite-plus/test"; -import { resolveClerkAuthRedirectUrl } from "./authRedirect"; +import { resolveClerkSignInProps } from "./authRedirect"; -describe("resolveClerkAuthRedirectUrl", () => { - it("preserves the current browser URL", () => { +describe("resolveClerkSignInProps", () => { + it("returns to the current browser URL on the web", () => { const href = "https://app.t3.codes/connect?state=state-1#details"; - expect(resolveClerkAuthRedirectUrl(href, false)).toBe(href); + expect(resolveClerkSignInProps(href, false)).toEqual({ forceRedirectUrl: href }); }); - it("uses the allowlisted packaged desktop callback", () => { - expect(resolveClerkAuthRedirectUrl("t3code://app/continue#/settings/general", true)).toBe( - "t3code://app/", - ); + it("omits the redirect override on packaged desktop", () => { + expect(resolveClerkSignInProps("t3code://app/#/settings/general", true)).toEqual({}); }); - it("uses the allowlisted development desktop callback", () => { - expect(resolveClerkAuthRedirectUrl("t3code-dev://app/continue#/settings/general", true)).toBe( - "t3code-dev://app/", - ); + it("omits the redirect override on development desktop", () => { + expect(resolveClerkSignInProps("t3code-dev://app/#/settings/general", true)).toEqual({}); }); }); diff --git a/apps/web/src/components/clerk/authRedirect.ts b/apps/web/src/components/clerk/authRedirect.ts index 6e94309db29..13331a27798 100644 --- a/apps/web/src/components/clerk/authRedirect.ts +++ b/apps/web/src/components/clerk/authRedirect.ts @@ -1,4 +1,12 @@ -export function resolveClerkAuthRedirectUrl(href: string, isElectron: boolean): string { - if (!isElectron) return href; - return new URL("/", href).toString(); +export interface ClerkSignInProps { + forceRedirectUrl?: string; +} + +// Clerk's native-app allowlist only authorizes the bare renderer root +// (t3code://app/), which @clerk/electron's OAuth transport already supplies, +// so any page-derived redirect override gets the whole sign-in request +// rejected. On Electron, omit the override and let Clerk use its defaults. +export function resolveClerkSignInProps(href: string, isElectron: boolean): ClerkSignInProps { + if (isElectron) return {}; + return { forceRedirectUrl: href }; } diff --git a/apps/web/src/components/clerk/useT3ConnectAuthPrompt.tsx b/apps/web/src/components/clerk/useT3ConnectAuthPrompt.tsx index bcfa30100b5..859a122ffe4 100644 --- a/apps/web/src/components/clerk/useT3ConnectAuthPrompt.tsx +++ b/apps/web/src/components/clerk/useT3ConnectAuthPrompt.tsx @@ -1,14 +1,12 @@ import { useClerk } from "@clerk/react"; import { isElectron } from "../../env"; -import { resolveClerkAuthRedirectUrl } from "./authRedirect"; +import { resolveClerkSignInProps } from "./authRedirect"; export function useT3ConnectAuthPrompt() { const clerk = useClerk(); const openAuthPrompt = () => { - clerk.openSignIn({ - forceRedirectUrl: resolveClerkAuthRedirectUrl(window.location.href, isElectron), - }); + clerk.openSignIn(resolveClerkSignInProps(window.location.href, isElectron)); }; return { authPrompt: null, openAuthPrompt }; } diff --git a/apps/web/src/components/cloud/ConnectCliAuthSurface.tsx b/apps/web/src/components/cloud/ConnectCliAuthSurface.tsx index caa0433fc50..b216f543316 100644 --- a/apps/web/src/components/cloud/ConnectCliAuthSurface.tsx +++ b/apps/web/src/components/cloud/ConnectCliAuthSurface.tsx @@ -11,7 +11,7 @@ import { import { isElectron } from "../../env"; import { useCopyToClipboard } from "../../hooks/useCopyToClipboard"; import { AuthSurfaceShell } from "../auth/AuthSurfaceShell"; -import { resolveClerkAuthRedirectUrl } from "../clerk/authRedirect"; +import { resolveClerkSignInProps } from "../clerk/authRedirect"; import { Button } from "../ui/button"; function ConnectCliAuthMessage({ @@ -61,9 +61,7 @@ export function ConnectCliAuthorizeSurface() { if (!isSignedIn) { if (!signInOpened.current) { signInOpened.current = true; - clerk.openSignIn({ - forceRedirectUrl: resolveClerkAuthRedirectUrl(window.location.href, isElectron), - }); + clerk.openSignIn(resolveClerkSignInProps(window.location.href, isElectron)); } return; } @@ -100,9 +98,7 @@ export function ConnectCliAuthorizeSurface() {