diff --git a/packages/ra-core/src/auth/useHandleAuthCallback.spec.tsx b/packages/ra-core/src/auth/useHandleAuthCallback.spec.tsx index 1ba624e777..7452fa26df 100644 --- a/packages/ra-core/src/auth/useHandleAuthCallback.spec.tsx +++ b/packages/ra-core/src/auth/useHandleAuthCallback.spec.tsx @@ -160,4 +160,28 @@ describe('useHandleAuthCallback', () => { expect(abort).toHaveBeenCalled(); }); }); + + it('should only call handleCallback once when the component is rendered', async () => { + const handleCallback = jest.spyOn(authProvider, 'handleCallback'); + render( + + + + + + Home} /> + } + /> + + + + + + ); + + await screen.findByText('Home'); + expect(handleCallback).toHaveBeenCalledTimes(1); + }); }); diff --git a/packages/ra-core/src/auth/useHandleAuthCallback.ts b/packages/ra-core/src/auth/useHandleAuthCallback.ts index 39c6df2bfe..b55a492f83 100644 --- a/packages/ra-core/src/auth/useHandleAuthCallback.ts +++ b/packages/ra-core/src/auth/useHandleAuthCallback.ts @@ -24,15 +24,38 @@ export const useHandleAuthCallback = ( const nextSearch = locationState && locationState.nextSearch; const defaultRedirectUrl = nextPathName ? nextPathName + nextSearch : '/'; const { onSuccess, onError, onSettled, ...queryOptions } = options ?? {}; + let handleCallbackPromise: Promise | null; const queryResult = useQuery({ queryKey: ['auth', 'handleCallback'], - queryFn: ({ signal }) => - authProvider && typeof authProvider.handleCallback === 'function' - ? authProvider - .handleCallback({ signal }) - .then(result => result ?? null) - : Promise.resolve(), + queryFn: ({ signal }) => { + console.log('queryFn', handleCallbackPromise); + if (!handleCallbackPromise) { + handleCallbackPromise = new Promise(async (resolve, reject) => { + if (authProvider) { + if (typeof authProvider.handleCallback === 'function') { + try { + const result = + await authProvider.handleCallback({ + signal, + }); + return resolve(result ?? null); + } catch (error) { + return reject({ + redirectTo: false, + message: error.message, + }); + } + } + return resolve(); + } + return reject({ + message: 'Failed to handle login callback.', + }); + }); + } + return handleCallbackPromise; + }, retry: false, ...queryOptions, });