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.
This commit is contained in:
2025-08-28 10:23:02 -06:00
parent fbeeff4c4d
commit 0eac7501c5
3 changed files with 62 additions and 25 deletions

View File

@@ -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 };

View File

@@ -1,33 +1,58 @@
"use client"; "use client";
import { useEffect, useContext } from "react"; import { useEffect, useContext, useRef } from "react";
import { client, configureApiAuth } from "./apiClient"; import { client, configureApiAuth } from "./apiClient";
import useSessionAccessToken from "./useSessionAccessToken"; import useSessionAccessToken from "./useSessionAccessToken";
import { DomainContext } from "../domainContext"; import { DomainContext } from "../domainContext";
export function ApiAuthProvider({ children }: { children: React.ReactNode }) { // Store the current API URL globally
const { accessToken } = useSessionAccessToken(); let currentApiUrl: string | null = null;
const { api_url } = useContext(DomainContext);
useEffect(() => { // Set up base URL middleware once
// Configure base URL const baseUrlMiddlewareSetup = () => {
if (api_url) {
client.use({ client.use({
onRequest({ request }) { onRequest({ request }) {
if (currentApiUrl) {
// Update the base URL for all requests // Update the base URL for all requests
const url = new URL(request.url); const url = new URL(request.url);
const apiUrl = new URL(api_url); const apiUrl = new URL(currentApiUrl);
url.protocol = apiUrl.protocol; url.protocol = apiUrl.protocol;
url.host = apiUrl.host; url.host = apiUrl.host;
url.port = apiUrl.port; url.port = apiUrl.port;
return new Request(url.toString(), request); 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(() => {
// Update the global API URL
currentApiUrl = api_url;
}, [api_url]);
useEffect(() => {
// Configure authentication // Configure authentication
configureApiAuth(accessToken); configureApiAuth(accessToken);
}, [accessToken, api_url]); }, [accessToken]);
return <>{children}</>; return <>{children}</>;
} }

View File

@@ -22,16 +22,22 @@ export const client = createClient<paths>({
// Create the React Query client wrapper // Create the React Query client wrapper
export const $api = createFetchClient<paths>(client); export const $api = createFetchClient<paths>(client);
// Configure authentication // Store the current auth token
export const configureApiAuth = (token: string | null | undefined) => { let currentAuthToken: string | null | undefined = null;
if (token) {
// Set up authentication middleware once
client.use({ client.use({
onRequest({ request }) { onRequest({ request }) {
request.headers.set("Authorization", `Bearer ${token}`); if (currentAuthToken) {
request.headers.set("Authorization", `Bearer ${currentAuthToken}`);
}
return request; return request;
}, },
}); });
}
// Configure authentication by updating the token
export const configureApiAuth = (token: string | null | undefined) => {
currentAuthToken = token;
}; };
// Export typed hooks for convenience // Export typed hooks for convenience