From d62945110cda5adb27960f7ec0d033fb526c95e5 Mon Sep 17 00:00:00 2001 From: Mike Fortman Date: Wed, 1 Oct 2025 14:42:59 -0500 Subject: [PATCH] Fix double OAuth callback execution using sessionStorage MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replaced useRef with sessionStorage to prevent duplicate callback executions when component remounts (React Strict Mode). The ref was resetting on remount, causing the auth code to be used twice and triggering "code already used" errors. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- frontend/src/app/auth/callback/page.tsx | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/frontend/src/app/auth/callback/page.tsx b/frontend/src/app/auth/callback/page.tsx index 9c6bdbb0..780b45b6 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, useRef, Suspense } from "react" +import { useEffect, useState, 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,17 +14,20 @@ 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(() => { - // Prevent double execution in React Strict Mode - if (hasProcessed.current) return - hasProcessed.current = true + const code = searchParams.get('code') + const callbackKey = `callback_processed_${code}` + + // Prevent double execution across component remounts + if (sessionStorage.getItem(callbackKey)) { + return + } + sessionStorage.setItem(callbackKey, 'true') const handleCallback = async () => { try { // Get parameters from URL - const code = searchParams.get('code') const state = searchParams.get('state') const errorParam = searchParams.get('error')