From 29e2b09f2f5791fb0ce5463b58361e743bef5895 Mon Sep 17 00:00:00 2001 From: Amr Gaber Date: Tue, 26 May 2026 22:56:59 -0500 Subject: [PATCH] fix: navigate directly to Google authorize endpoints MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `handleGoogleLogin` and the Google branch of `handleConnect` both called `api.get('.../authorize').json()` and then navigated to the returned `authorization_url`. In production the authorize endpoint returns a 302 to accounts.google.com, which Ky's fetch follows automatically — and the browser blocks the cross-origin call because accounts.google.com isn't in our CSP connect-src. Switch both to direct navigation (mirroring the existing Steam pattern in c8d1e2d). The browser navigates to the API, the API 302s, the browser follows the redirect — CSP connect-src doesn't apply to navigation. API code (app/routers/auth_providers.py) confirms login_authorize and associate_authorize share the same dev-JSON / prod-302 behavior across both providers, so this aligns Google with how Steam already works. --- src/pages/login/login-page.tsx | 25 +++++++++---------------- src/pages/profile/profile-page.tsx | 27 +++++++-------------------- 2 files changed, 16 insertions(+), 36 deletions(-) diff --git a/src/pages/login/login-page.tsx b/src/pages/login/login-page.tsx index af7e284..91f8ef3 100644 --- a/src/pages/login/login-page.tsx +++ b/src/pages/login/login-page.tsx @@ -44,26 +44,19 @@ export function LoginPage() { } } - async function handleGoogleLogin() { - try { - if (redirect) localStorage.setItem("auth_redirect", redirect) - const res = await api - .get("auth/google/authorize") - .json<{ authorization_url: string }>() - window.location.href = res.authorization_url - } catch (error) { - const message = await getErrorMessage( - error, - "Failed to start Google sign-in" - ) - toast.error(message) - } + function handleGoogleLogin() { + if (redirect) localStorage.setItem("auth_redirect", redirect) + // The authorize endpoint 302s to accounts.google.com in production. + // Fetching it would follow the redirect via fetch, which the browser + // blocks because accounts.google.com isn't in our CSP connect-src. + // Direct navigation sidesteps connect-src entirely. + window.location.href = `${baseUrl}/auth/google/authorize` } function handleSteamLogin() { if (redirect) localStorage.setItem("auth_redirect", redirect) - // In production, the authorize endpoint returns a 307 redirect to Steam, - // so we navigate directly instead of fetching (avoids CSP issues). + // Same reasoning as handleGoogleLogin: the authorize endpoint 307s to + // Steam's OpenID, so we navigate directly to avoid a CSP-blocked fetch. window.location.href = `${baseUrl}/auth/steam/authorize` } diff --git a/src/pages/profile/profile-page.tsx b/src/pages/profile/profile-page.tsx index 973e7c9..5eacfc7 100644 --- a/src/pages/profile/profile-page.tsx +++ b/src/pages/profile/profile-page.tsx @@ -165,27 +165,14 @@ export function ProfilePage() { } } - async function handleConnect(provider: ProviderId) { + function handleConnect(provider: ProviderId) { setConnectingProvider(provider) - try { - if (provider === "steam") { - // Steam's authorize endpoint 307s straight to Steam's OpenID; navigate - // there directly to keep the redirect chain server-driven. - window.location.href = `${baseUrl}/auth/steam/associate/authorize` - return - } - const res = await api - .get(`auth/${provider}/associate/authorize`) - .json<{ authorization_url: string }>() - window.location.href = res.authorization_url - } catch (error) { - const message = await getErrorMessage( - error, - `Failed to start linking ${provider}` - ) - toast.error(message) - setConnectingProvider(null) - } + // Both providers' associate-authorize endpoints 302 to the provider in + // production. Fetching first would let the browser follow the redirect + // via fetch — CSP connect-src blocks the cross-origin call to + // accounts.google.com / steamcommunity.com. Direct navigation + // sidesteps connect-src entirely. + window.location.href = `${baseUrl}/auth/${provider}/associate/authorize` } async function handleDisconnect(provider: ProviderId) {