From 1f460701ab9cef676a4748ca3cd2f9f38411f2d1 Mon Sep 17 00:00:00 2001
From: Kurt Weiberth <kweiberth@users.noreply.github.com>
Date: Thu, 23 Dec 2021 07:41:06 -0500
Subject: [PATCH] Avoid potential multiple invocations of loginWithRedirect
 (#311)

* Avoid potential multiple invocations of loginWithRedirect

Resolves https://github.com/auth0/auth0-react/issues/309

* add test to assert single call

* remove comment
---
 .../with-authentication-required.test.tsx     | 23 +++++++++++++++++++
 src/with-authentication-required.tsx          |  4 ++--
 2 files changed, 25 insertions(+), 2 deletions(-)

diff --git a/__tests__/with-authentication-required.test.tsx b/__tests__/with-authentication-required.test.tsx
index 0c1a12b8..0a447110 100644
--- a/__tests__/with-authentication-required.test.tsx
+++ b/__tests__/with-authentication-required.test.tsx
@@ -189,4 +189,27 @@ describe('withAuthenticationRequired', () => {
       )
     );
   });
+
+  it('should call loginWithRedirect only once even if parent state changes', async () => {
+    mockClient.getUser.mockResolvedValue(undefined);
+    const MyComponent = (): JSX.Element => <>Private</>;
+    const WrappedComponent = withAuthenticationRequired(MyComponent);
+    const App = ({ foo }: { foo: number }): JSX.Element => (
+      <div>
+        {foo}
+        <Auth0Provider clientId="__test_client_id__" domain="__test_domain__">
+          <WrappedComponent />
+        </Auth0Provider>
+      </div>
+    );
+    const { rerender } = render(<App foo={1} />);
+    await waitFor(() =>
+      expect(mockClient.loginWithRedirect).toHaveBeenCalled()
+    );
+    mockClient.loginWithRedirect.mockClear();
+    rerender(<App foo={2} />);
+    await waitFor(() =>
+      expect(mockClient.loginWithRedirect).not.toHaveBeenCalled()
+    );
+  });
 });
diff --git a/src/with-authentication-required.tsx b/src/with-authentication-required.tsx
index dd24624a..5510a96a 100644
--- a/src/with-authentication-required.tsx
+++ b/src/with-authentication-required.tsx
@@ -84,8 +84,8 @@ const withAuthenticationRequired = <P extends object>(
     const {
       returnTo = defaultReturnTo,
       onRedirecting = defaultOnRedirecting,
-      loginOptions = {},
       claimCheck = (): boolean => true,
+      loginOptions,
     } = options;
 
     /**
@@ -101,7 +101,7 @@ const withAuthenticationRequired = <P extends object>(
       const opts = {
         ...loginOptions,
         appState: {
-          ...loginOptions.appState,
+          ...(loginOptions && loginOptions.appState),
           returnTo: typeof returnTo === 'function' ? returnTo() : returnTo,
         },
       };