From 850f713310132dd26acadbec67434d36bfe23124 Mon Sep 17 00:00:00 2001 From: Eric Gullickson <16152721+ericgullickson@users.noreply.github.com> Date: Sun, 15 Feb 2026 09:24:56 -0600 Subject: [PATCH] fix: prevent URL sync effects from stripping Auth0 callback params (refs #188) Root cause: React fires child effects before parent effects. App's URL sync effect called history.replaceState() on /callback, stripping the ?code= and &state= query params before Auth0Provider's useEffect could read them via hasAuthParams(). The SDK fell through to checkSession() instead of handleRedirectCallback(), silently failing with no error. Guard both URL sync effects to skip on /callback, /signup, /verify-email. Co-Authored-By: Claude Opus 4.6 --- frontend/src/App.tsx | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index fb95ed8..fbbd914 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -365,17 +365,24 @@ function App() { const [showAddVehicle, setShowAddVehicle] = useState(false); // Sync browser URL to Zustand screen state on mount (enables direct URL navigation on mobile) + // Skip on auth routes -- their query params must survive until Auth0 SDK processes them useEffect(() => { - const screen = routeToScreen[window.location.pathname]; + const path = window.location.pathname; + if (path === '/callback' || path === '/signup' || path === '/verify-email') return; + const screen = routeToScreen[path]; if (screen && screen !== activeScreen) { navigateToScreen(screen, { source: 'url-sync' }); } }, []); // eslint-disable-line react-hooks/exhaustive-deps -- intentionally runs once on mount // Sync Zustand screen changes back to browser URL (enables bookmarks and URL sharing) + // Skip on auth routes -- replaceState would strip ?code= and &state= params that + // Auth0 SDK needs for handleRedirectCallback (child effects fire before parent effects) useEffect(() => { + const path = window.location.pathname; + if (path === '/callback' || path === '/signup' || path === '/verify-email') return; const targetPath = screenToRoute[activeScreen]; - if (targetPath && window.location.pathname !== targetPath) { + if (targetPath && path !== targetPath) { window.history.replaceState(null, '', targetPath); } }, [activeScreen]);