From 95f11521c32595efecdb568998e1a14816974c0e Mon Sep 17 00:00:00 2001 From: Anish Sarkar <104695310+AnishSarkar22@users.noreply.github.com> Date: Wed, 18 Mar 2026 17:00:54 +0530 Subject: [PATCH] refactor: migrate OAuth result handling from sessionStorage to cookies and update connector callback implementation - Removed the ConnectorCallbackPage component and replaced it with a route handler that sets the OAuth result in a cookie. - Updated the useConnectorDialog hook to read from the cookie instead of sessionStorage, ensuring a more consistent state management approach. --- .../connectors/callback/page.tsx | 34 ------------------- .../connectors/callback/route.ts | 33 ++++++++++++++++++ .../hooks/use-connector-dialog.ts | 23 ++++++++++--- 3 files changed, 52 insertions(+), 38 deletions(-) delete mode 100644 surfsense_web/app/dashboard/[search_space_id]/connectors/callback/page.tsx create mode 100644 surfsense_web/app/dashboard/[search_space_id]/connectors/callback/route.ts diff --git a/surfsense_web/app/dashboard/[search_space_id]/connectors/callback/page.tsx b/surfsense_web/app/dashboard/[search_space_id]/connectors/callback/page.tsx deleted file mode 100644 index ef5be4640..000000000 --- a/surfsense_web/app/dashboard/[search_space_id]/connectors/callback/page.tsx +++ /dev/null @@ -1,34 +0,0 @@ -"use client"; - -import { useEffect } from "react"; -import { useRouter, useSearchParams } from "next/navigation"; -import { Spinner } from "@/components/ui/spinner"; - -const OAUTH_RESULT_KEY = "connector_oauth_result"; - -export default function ConnectorCallbackPage({ - params, -}: { - params: { search_space_id: string }; -}) { - const router = useRouter(); - const searchParams = useSearchParams(); - - useEffect(() => { - const result = { - success: searchParams.get("success"), - error: searchParams.get("error"), - connector: searchParams.get("connector"), - connectorId: searchParams.get("connectorId"), - }; - - sessionStorage.setItem(OAUTH_RESULT_KEY, JSON.stringify(result)); - router.replace(`/dashboard/${params.search_space_id}/new-chat`); - }, [searchParams, router, params.search_space_id]); - - return ( -
- -
- ); -} diff --git a/surfsense_web/app/dashboard/[search_space_id]/connectors/callback/route.ts b/surfsense_web/app/dashboard/[search_space_id]/connectors/callback/route.ts new file mode 100644 index 000000000..ca55913f0 --- /dev/null +++ b/surfsense_web/app/dashboard/[search_space_id]/connectors/callback/route.ts @@ -0,0 +1,33 @@ +import { type NextRequest, NextResponse } from "next/server"; + +const OAUTH_RESULT_COOKIE = "connector_oauth_result"; + +export async function GET( + request: NextRequest, + { params }: { params: Promise<{ search_space_id: string }> } +) { + const { search_space_id } = await params; + const searchParams = request.nextUrl.searchParams; + + const result = JSON.stringify({ + success: searchParams.get("success"), + error: searchParams.get("error"), + connector: searchParams.get("connector"), + connectorId: searchParams.get("connectorId"), + }); + + const redirectUrl = new URL( + `/dashboard/${search_space_id}/new-chat`, + request.url + ); + + const response = NextResponse.redirect(redirectUrl, { status: 302 }); + response.cookies.set(OAUTH_RESULT_COOKIE, result, { + path: "/", + maxAge: 60, + httpOnly: false, + sameSite: "lax", + }); + + return response; +} diff --git a/surfsense_web/components/assistant-ui/connector-popup/hooks/use-connector-dialog.ts b/surfsense_web/components/assistant-ui/connector-popup/hooks/use-connector-dialog.ts index 74cea667c..a79e15c7f 100644 --- a/surfsense_web/components/assistant-ui/connector-popup/hooks/use-connector-dialog.ts +++ b/surfsense_web/components/assistant-ui/connector-popup/hooks/use-connector-dialog.ts @@ -40,7 +40,19 @@ import { validateIndexingConfigState, } from "../constants/connector-popup.schemas"; -const OAUTH_RESULT_KEY = "connector_oauth_result"; +const OAUTH_RESULT_COOKIE = "connector_oauth_result"; + +function readOAuthResultCookie(): string | null { + const match = document.cookie + .split("; ") + .find((row) => row.startsWith(`${OAUTH_RESULT_COOKIE}=`)); + return match ? decodeURIComponent(match.split("=").slice(1).join("=")) : null; +} + +function clearOAuthResultCookie(): void { + // biome-ignore lint: only standard way to expire a cookie + document.cookie = `${OAUTH_RESULT_COOKIE}=; path=/; max-age=0`; +} export const useConnectorDialog = () => { const searchSpaceId = useAtomValue(activeSearchSpaceIdAtom); @@ -188,11 +200,11 @@ export const useConnectorDialog = () => { // Track whether the current indexing config came from an OAuth redirect const [isFromOAuth, setIsFromOAuth] = useState(false); - // Consume OAuth result from sessionStorage (set by /connectors/callback page) + // Consume OAuth result from cookie (set by /connectors/callback route handler) useEffect(() => { - const raw = sessionStorage.getItem(OAUTH_RESULT_KEY); + const raw = readOAuthResultCookie(); if (!raw || !searchSpaceId) return; - sessionStorage.removeItem(OAUTH_RESULT_KEY); + clearOAuthResultCookie(); let result: { success: string | null; @@ -1188,6 +1200,9 @@ export const useConnectorDialog = () => { setConnectorName(null); setConnectorConfig(null); } else { + setEditingConnector(null); + setConnectorName(null); + setConnectorConfig(null); setIsOpen(false); }