diff --git a/src/auth/index.ts b/src/auth/index.ts index e3254e8d1..7e0b8ba23 100644 --- a/src/auth/index.ts +++ b/src/auth/index.ts @@ -77,10 +77,11 @@ export const createGetUserPermissions = (libJwt: LibJWT, getUser: () => Promise< }; }; -export default ({ ssoUrl }: { ssoUrl?: string }): LibJWT => { +export default ({ ssoUrl, ssoScopes }: { ssoUrl?: string; ssoScopes: string[] }): LibJWT => { console.time(TIMER_STR); // eslint-disable-line no-console const options = { ...defaultOptions, + scope: ssoScopes.join(' '), }; wipePostbackParamsThatAreNotForUs(); diff --git a/src/bootstrap.tsx b/src/bootstrap.tsx index 1ec2015ef..f849fbb60 100644 --- a/src/bootstrap.tsx +++ b/src/bootstrap.tsx @@ -2,6 +2,8 @@ import React, { useEffect, useRef, useState } from 'react'; import { createRoot } from 'react-dom/client'; import { Provider, useSelector, useStore } from 'react-redux'; import { IntlProvider, ReactIntlErrorCode } from 'react-intl'; +import { matchRoutes } from 'react-router-dom'; + import { spinUpStore } from './redux/redux-config'; import RootApp from './components/RootApp'; import { loadModulesSchema } from './redux/actions'; @@ -10,7 +12,7 @@ import { ACTIVE_REMOTE_REQUEST, CROSS_ACCESS_ACCOUNT_NUMBER } from './utils/cons import auth, { LibJWT, createGetUserPermissions, crossAccountBouncer } from './auth'; import sentry from './utils/sentry'; import registerAnalyticsObserver from './analytics/analyticsObserver'; -import { ITLess, getEnv, loadFEOFedModules, loadFedModules, noop, trustarcScriptSetup } from './utils/common'; +import { ITLess, generateRoutesList, getEnv, loadFedModules, noop, trustarcScriptSetup } from './utils/common'; import messages from './locales/data.json'; import ErrorBoundary from './components/ErrorComponents/ErrorBoundary'; import LibtJWTContext from './components/LibJWTContext'; @@ -41,8 +43,8 @@ const initializeAccessRequestCookies = () => { } }; -const libjwtSetup = (chromeConfig: { ssoUrl?: string }) => { - const libjwt = auth(chromeConfig || {}); +const libjwtSetup = (chromeConfig: { ssoUrl?: string }, ssoScopes: string[] = []) => { + const libjwt = auth({ ...chromeConfig, ssoScopes } || { ssoScopes }); libjwt.initPromise.then(() => { return libjwt.jwt @@ -66,17 +68,30 @@ const useInitialize = () => { const chromeInstance = useRef({ cache: undefined }); const init = async () => { + const pathname = window.location.pathname; // We have to use `let` because we want to access it once jwt is initialized let libJwt: LibJWT | undefined = undefined; // init qe functions, callback for libjwt because we want it to initialize before jwt is ready qe.init(store, () => libJwt); - const { data: feoData } = await loadFEOFedModules(); - const { chrome: chromeConfig } = feoData; - let modulesData = feoData; + // Load federated modules before the SSO init phase to obtain scope configuration + const { data: modulesData } = await loadFedModules(); + const { chrome: chromeConfig } = modulesData; + const routes = generateRoutesList(modulesData); + store.dispatch(loadModulesSchema(modulesData)); + // ge the initial module UI identifier + const initialModuleScope = matchRoutes( + routes.map(({ path, ...rest }) => ({ + ...rest, + path: `${path}/*`, + })), + // modules config does not include the preview fragment + pathname.replace(/^\/(preview|beta)/, '') + )?.[0]?.route?.scope; + const initialModuleConfig = initialModuleScope && modulesData[initialModuleScope]?.config; initializeAccessRequestCookies(); // create JWT instance - libJwt = libjwtSetup({ ...chromeConfig?.config, ...chromeConfig }); + libJwt = libjwtSetup({ ...chromeConfig?.config, ...chromeConfig }, initialModuleConfig?.ssoScopes); await initializeJWT(libJwt, chromeInstance.current); const getUser = createGetUser(libJwt); @@ -90,19 +105,6 @@ const useInitialize = () => { libJwt, isReady: true, }); - - try { - const { data } = await loadFedModules(); - // merge configs with chrome service priority - modulesData = { - ...feoData, - ...data, - }; - } catch (error) { - console.error('Unable to fetch fed-modules from chrome service! Falling back to CDN.'); - } - - store.dispatch(loadModulesSchema(modulesData)); }; useEffect(() => { diff --git a/src/hooks/useUserSSOScopes.ts b/src/hooks/useUserSSOScopes.ts index 65508596e..1d65da60a 100644 --- a/src/hooks/useUserSSOScopes.ts +++ b/src/hooks/useUserSSOScopes.ts @@ -5,7 +5,7 @@ import { ReduxState } from '../redux/store'; import { LOGIN_SCOPES_STORAGE_KEY } from '../utils/common'; /** - * If required, attempt to reauthenticated current user with full profile login. + * If required, attempt to reauthenticate current user with full profile login. */ const useUserSSOScopes = () => { const getCurrentScopes = (): string[] => { @@ -18,6 +18,8 @@ const useUserSSOScopes = () => { }; // get scope module definition const activeModule = useSelector(({ chrome: { activeModule, modules } }: ReduxState) => (activeModule ? (modules || {})[activeModule] : undefined)); + const requiredScopes = activeModule?.config?.ssoScopes || []; + useEffect(() => { const currentScopes = getCurrentScopes(); const requiredScopes = activeModule?.config?.ssoScopes || []; @@ -32,7 +34,7 @@ const useUserSSOScopes = () => { if (shouldReAuth) { login(requiredScopes); } - }, [activeModule, activeModule?.fullProfile]); + }, [requiredScopes, activeModule?.fullProfile]); }; export default useUserSSOScopes; diff --git a/src/utils/common.ts b/src/utils/common.ts index f223579a7..227321fc9 100644 --- a/src/utils/common.ts +++ b/src/utils/common.ts @@ -344,11 +344,6 @@ const fedModulesheaders = { Expires: '0', }; -export const loadFEOFedModules = () => - axios.get(`${window.location.origin}${isBeta() ? '/beta' : ''}/config/chrome/fed-modules.json?ts=${Date.now()}`, { - headers: fedModulesheaders, - }); - export const loadFedModules = async () => axios.get(`${getChromeStaticPathname('modules')}/fed-modules.json`, { headers: fedModulesheaders,