diff --git a/frontend/src/app/auth/callback/page.tsx b/frontend/src/app/auth/callback/page.tsx index 23c1972a..9c6bdbb0 100644 --- a/frontend/src/app/auth/callback/page.tsx +++ b/frontend/src/app/auth/callback/page.tsx @@ -1,6 +1,6 @@ "use client" -import { useEffect, useState, Suspense } from "react" +import { useEffect, useState, useRef, Suspense } from "react" import { useRouter, useSearchParams } from "next/navigation" import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card" import { Button } from "@/components/ui/button" @@ -14,21 +14,17 @@ function AuthCallbackContent() { const [status, setStatus] = useState<"processing" | "success" | "error">("processing") const [error, setError] = useState(null) const [purpose, setPurpose] = useState("app_auth") + const hasProcessed = useRef(false) useEffect(() => { - const code = searchParams.get('code') - const callbackKey = `callback_processed_${code}` - - // Prevent double execution across component remounts - if (sessionStorage.getItem(callbackKey)) { - console.log('Callback already processed, skipping') - return - } - sessionStorage.setItem(callbackKey, 'true') + // Prevent double execution in React Strict Mode + if (hasProcessed.current) return + hasProcessed.current = true const handleCallback = async () => { try { // Get parameters from URL + const code = searchParams.get('code') const state = searchParams.get('state') const errorParam = searchParams.get('error') @@ -41,6 +37,14 @@ function AuthCallbackContent() { const detectedPurpose = authPurpose || (storedConnectorType?.includes('drive') ? 'data_source' : 'app_auth') setPurpose(detectedPurpose) + // Debug logging + console.log('OAuth Callback Debug:', { + urlParams: { code: !!code, state: !!state, error: errorParam }, + localStorage: { connectorId, storedConnectorType, authPurpose }, + detectedPurpose, + fullUrl: window.location.href + }) + // Use state parameter as connection_id if localStorage is missing const finalConnectorId = connectorId || state