From 0eac7501c5dee5d347176e48696b55670c29f87d Mon Sep 17 00:00:00 2001 From: Mathieu Virbel Date: Thu, 28 Aug 2025 10:23:02 -0600 Subject: [PATCH] fix: authentication flow with React Query migration - Fix middleware management in apiClient to properly handle auth tokens - Update ApiAuthProvider to correctly configure base URL and auth - Add missing NextAuth API route handler at app/api/auth/[...nextauth]/route.ts - Remove middleware ejection attempts (not supported by openapi-fetch) - Use global variables to store current auth token and API URL - Setup middleware once on initialization instead of repeatedly adding This fixes the login/logout flow that was broken after migrating from the useApi compatibility layer to native React Query hooks. --- www/app/api/auth/[...nextauth]/route.ts | 6 +++ www/app/lib/ApiAuthProvider.tsx | 57 ++++++++++++++++++------- www/app/lib/apiClient.tsx | 24 +++++++---- 3 files changed, 62 insertions(+), 25 deletions(-) create mode 100644 www/app/api/auth/[...nextauth]/route.ts diff --git a/www/app/api/auth/[...nextauth]/route.ts b/www/app/api/auth/[...nextauth]/route.ts new file mode 100644 index 00000000..8931ab03 --- /dev/null +++ b/www/app/api/auth/[...nextauth]/route.ts @@ -0,0 +1,6 @@ +import NextAuth from "next-auth"; +import { authOptions } from "../../../lib/auth"; + +const handler = NextAuth(authOptions); + +export { handler as GET, handler as POST }; diff --git a/www/app/lib/ApiAuthProvider.tsx b/www/app/lib/ApiAuthProvider.tsx index 33dad5c2..8e27f6b7 100644 --- a/www/app/lib/ApiAuthProvider.tsx +++ b/www/app/lib/ApiAuthProvider.tsx @@ -1,33 +1,58 @@ "use client"; -import { useEffect, useContext } from "react"; +import { useEffect, useContext, useRef } from "react"; import { client, configureApiAuth } from "./apiClient"; import useSessionAccessToken from "./useSessionAccessToken"; import { DomainContext } from "../domainContext"; +// Store the current API URL globally +let currentApiUrl: string | null = null; + +// Set up base URL middleware once +const baseUrlMiddlewareSetup = () => { + client.use({ + onRequest({ request }) { + if (currentApiUrl) { + // Update the base URL for all requests + const url = new URL(request.url); + const apiUrl = new URL(currentApiUrl); + url.protocol = apiUrl.protocol; + url.host = apiUrl.host; + url.port = apiUrl.port; + return new Request(url.toString(), request); + } + return request; + }, + }); +}; + +// Initialize base URL middleware once +if (typeof window !== "undefined") { + baseUrlMiddlewareSetup(); +} + export function ApiAuthProvider({ children }: { children: React.ReactNode }) { const { accessToken } = useSessionAccessToken(); const { api_url } = useContext(DomainContext); + const initialized = useRef(false); + + // Initialize middleware once on client side + useEffect(() => { + if (!initialized.current && typeof window !== "undefined") { + baseUrlMiddlewareSetup(); + initialized.current = true; + } + }, []); useEffect(() => { - // Configure base URL - if (api_url) { - client.use({ - onRequest({ request }) { - // Update the base URL for all requests - const url = new URL(request.url); - const apiUrl = new URL(api_url); - url.protocol = apiUrl.protocol; - url.host = apiUrl.host; - url.port = apiUrl.port; - return new Request(url.toString(), request); - }, - }); - } + // Update the global API URL + currentApiUrl = api_url; + }, [api_url]); + useEffect(() => { // Configure authentication configureApiAuth(accessToken); - }, [accessToken, api_url]); + }, [accessToken]); return <>{children}; } diff --git a/www/app/lib/apiClient.tsx b/www/app/lib/apiClient.tsx index 978f44e6..2b320267 100644 --- a/www/app/lib/apiClient.tsx +++ b/www/app/lib/apiClient.tsx @@ -22,16 +22,22 @@ export const client = createClient({ // Create the React Query client wrapper export const $api = createFetchClient(client); -// Configure authentication +// Store the current auth token +let currentAuthToken: string | null | undefined = null; + +// Set up authentication middleware once +client.use({ + onRequest({ request }) { + if (currentAuthToken) { + request.headers.set("Authorization", `Bearer ${currentAuthToken}`); + } + return request; + }, +}); + +// Configure authentication by updating the token export const configureApiAuth = (token: string | null | undefined) => { - if (token) { - client.use({ - onRequest({ request }) { - request.headers.set("Authorization", `Bearer ${token}`); - return request; - }, - }); - } + currentAuthToken = token; }; // Export typed hooks for convenience