Skip to content

Commit

Permalink
Adrienne / Fix SSO triggering multiple times due to useeffect depende…
Browse files Browse the repository at this point in the history
…ncies (#18114)

* feat: store redirect metadata for traders hub from os-redirect

* Merge branch 'master' of github.com:deriv-com/deriv-app

* chore: refactored sso and slo conditions

* chore: remove debouncing in sso and slo handler

* chore: resolve test cases
  • Loading branch information
adrienne-deriv authored Mar 7, 2025
1 parent 39c1841 commit bd25379
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 55 deletions.
1 change: 0 additions & 1 deletion packages/core/src/App/AppContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,6 @@ const AppContent: React.FC<{ passthrough: unknown }> = observer(({ passthrough }
is_client_store_initialized,
isOAuth2Enabled,
oAuthLogout,
prevent_single_login,
});

const [isWebPasskeysFFEnabled, isGBLoaded] = useGrowthbookIsOn({
Expand Down
12 changes: 10 additions & 2 deletions packages/core/src/App/Containers/RootComponent/root-component.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,14 @@ const RootComponent = observer(props => {
setIsWalletsOnboardingTourGuideVisible,
notification_messages_ui,
} = ui;
const { has_wallet, logout, prevent_redirect_to_hub, is_client_store_initialized, setPreventSingleLogin } = client;
const {
has_wallet,
logout,
prevent_redirect_to_hub,
is_client_store_initialized,
prevent_single_login,
setPreventSingleLogin,
} = client;

const { oAuthLogout } = useOauth2({ handleLogout: logout });

Expand Down Expand Up @@ -56,14 +63,15 @@ const RootComponent = observer(props => {
}

const shouldStayInDerivApp = !isHubRedirectionEnabled || !has_wallet || prevent_redirect_to_hub;
if (isHubRedirectionLoaded && is_client_store_initialized && shouldStayInDerivApp) {
if (prevent_single_login && isHubRedirectionLoaded && is_client_store_initialized && shouldStayInDerivApp) {
setPreventSingleLogin(false);
}
}, [
isHubRedirectionLoaded,
isHubRedirectionEnabled,
has_wallet,
prevent_redirect_to_hub,
prevent_single_login,
is_client_store_initialized,
]);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import React from 'react';
import Cookies from 'js-cookie';

import { requestOidcAuthentication } from '@deriv-com/auth-client';
import { renderHook } from '@testing-library/react-hooks';

import useSilentLoginAndLogout from '../useSilentLoginAndLogout';
import { mockStore, StoreProvider } from '@deriv/stores';

jest.mock('js-cookie', () => ({
get: jest.fn(),
Expand All @@ -15,6 +17,12 @@ jest.mock('@deriv-com/auth-client', () => ({

describe('useSilentLoginAndLogout', () => {
const mockOAuthLogout = jest.fn();
const mockStoreData = mockStore({
client: { prevent_single_login: false },
});
const wrapper = ({ children }: { children: JSX.Element }) => (
<StoreProvider store={mockStoreData}>{children}</StoreProvider>
);

beforeEach(() => {
jest.clearAllMocks();
Expand Down Expand Up @@ -42,12 +50,14 @@ describe('useSilentLoginAndLogout', () => {

jest.spyOn(Storage.prototype, 'getItem').mockReturnValue(JSON.stringify({}));

renderHook(() =>
useSilentLoginAndLogout({
is_client_store_initialized: true,
isOAuth2Enabled: true,
oAuthLogout: mockOAuthLogout,
})
renderHook(
() =>
useSilentLoginAndLogout({
is_client_store_initialized: true,
isOAuth2Enabled: true,
oAuthLogout: mockOAuthLogout,
}),
{ wrapper }
);

expect(requestOidcAuthentication).toHaveBeenCalledWith({
Expand All @@ -61,12 +71,14 @@ describe('useSilentLoginAndLogout', () => {

jest.spyOn(Storage.prototype, 'getItem').mockReturnValue(JSON.stringify({}));

renderHook(() =>
useSilentLoginAndLogout({
is_client_store_initialized: true,
isOAuth2Enabled: true,
oAuthLogout: mockOAuthLogout,
})
renderHook(
() =>
useSilentLoginAndLogout({
is_client_store_initialized: true,
isOAuth2Enabled: true,
oAuthLogout: mockOAuthLogout,
}),
{ wrapper }
);

expect(requestOidcAuthentication).not.toHaveBeenCalled();
Expand All @@ -83,12 +95,14 @@ describe('useSilentLoginAndLogout', () => {
value: { pathname: '/callback' },
});

renderHook(() =>
useSilentLoginAndLogout({
is_client_store_initialized: true,
isOAuth2Enabled: true,
oAuthLogout: mockOAuthLogout,
})
renderHook(
() =>
useSilentLoginAndLogout({
is_client_store_initialized: true,
isOAuth2Enabled: true,
oAuthLogout: mockOAuthLogout,
}),
{ wrapper }
);

expect(requestOidcAuthentication).not.toHaveBeenCalled();
Expand All @@ -100,12 +114,14 @@ describe('useSilentLoginAndLogout', () => {

jest.spyOn(Storage.prototype, 'getItem').mockReturnValue(JSON.stringify({ account1: {}, account2: {} }));

renderHook(() =>
useSilentLoginAndLogout({
is_client_store_initialized: true,
isOAuth2Enabled: true,
oAuthLogout: mockOAuthLogout,
})
renderHook(
() =>
useSilentLoginAndLogout({
is_client_store_initialized: true,
isOAuth2Enabled: true,
oAuthLogout: mockOAuthLogout,
}),
{ wrapper }
);

expect(requestOidcAuthentication).not.toHaveBeenCalled();
Expand All @@ -117,12 +133,14 @@ describe('useSilentLoginAndLogout', () => {

jest.spyOn(Storage.prototype, 'getItem').mockReturnValue(JSON.stringify({ account1: {}, account2: {} }));

renderHook(() =>
useSilentLoginAndLogout({
is_client_store_initialized: true,
isOAuth2Enabled: true,
oAuthLogout: mockOAuthLogout,
})
renderHook(
() =>
useSilentLoginAndLogout({
is_client_store_initialized: true,
isOAuth2Enabled: true,
oAuthLogout: mockOAuthLogout,
}),
{ wrapper }
);

expect(requestOidcAuthentication).not.toHaveBeenCalled();
Expand Down
37 changes: 15 additions & 22 deletions packages/hooks/src/useSilentLoginAndLogout.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { useEffect } from 'react';
import { useEffect, useRef } from 'react';
import Cookies from 'js-cookie';

import { requestOidcAuthentication } from '@deriv-com/auth-client';

import { useStore } from '@deriv/stores';
/**
* Handles silent login and single logout logic for OAuth2.
*
Expand All @@ -16,60 +16,53 @@ const useSilentLoginAndLogout = ({
is_client_store_initialized,
isOAuth2Enabled,
oAuthLogout,
prevent_single_login,
}: {
is_client_store_initialized: boolean;
isOAuth2Enabled: boolean;
oAuthLogout: () => Promise<void>;
prevent_single_login?: boolean;
}) => {
const loggedState = Cookies.get('logged_state');

const { client } = useStore();
const clientAccounts = JSON.parse(localStorage.getItem('client.accounts') || '{}');
const isClientAccountsPopulated = Object.keys(clientAccounts).length > 0;
const isSilentLoginExcluded =
window.location.pathname.includes('callback') || window.location.pathname.includes('endpoint');

// state to manage and ensure OIDC callback functions are invoked once only
const isAuthenticating = useRef(false);
const isLoggingOut = useRef(false);
const { prevent_single_login } = client;

useEffect(() => {
if (prevent_single_login) return;
if (prevent_single_login || !isOAuth2Enabled || !is_client_store_initialized || isSilentLoginExcluded) return;
// NOTE: Remove this logic once social signup is intergated with OIDC
const params = new URLSearchParams(window.location.search);
const isUsingLegacyFlow = params.has('token1') && params.has('acct1');
if (isUsingLegacyFlow && loggedState === 'false' && isOAuth2Enabled) {
return;
}

if (
!isUsingLegacyFlow &&
loggedState === 'true' &&
!isClientAccountsPopulated &&
isOAuth2Enabled &&
is_client_store_initialized &&
!isSilentLoginExcluded
) {
if (!isUsingLegacyFlow && loggedState === 'true' && !isClientAccountsPopulated) {
// Perform silent login
if (isAuthenticating.current) return;
isAuthenticating.current = true;
requestOidcAuthentication({
redirectCallbackUri: `${window.location.origin}/callback`,
});
}

if (
!isUsingLegacyFlow &&
loggedState === 'false' &&
is_client_store_initialized &&
isOAuth2Enabled &&
isClientAccountsPopulated &&
!window.location.pathname.includes('callback')
) {
if (!isUsingLegacyFlow && loggedState === 'false' && isClientAccountsPopulated) {
// Perform single logout
if (isLoggingOut.current) return;
isLoggingOut.current = true;
oAuthLogout();
}
}, [
loggedState,
isClientAccountsPopulated,
is_client_store_initialized,
isOAuth2Enabled,
oAuthLogout,
isSilentLoginExcluded,
prevent_single_login,
]);
Expand Down

0 comments on commit bd25379

Please sign in to comment.