import { Fetch, getFetchDefault, ILOidcLocation, OidcClient, OidcConfiguration, OidcLocation, } from '@axa-fr/oidc-client'; import { ComponentType, FC, PropsWithChildren, useEffect, useState } from 'react'; import AuthenticatingError from './core/default-component/AuthenticateError.component.js'; import { Authenticating, CallBackSuccess, Loading, SessionLost, } from './core/default-component/index.js'; import ServiceWorkerNotSupported from './core/default-component/ServiceWorkerNotSupported.component.js'; import OidcRoutes from './core/routes/OidcRoutes.js'; import { CustomHistory } from './core/routes/withRouter.js'; export type oidcContext = { (name?: string): OidcClient; }; const defaultEventState = { name: '', data: null }; export type OidcProviderProps = { callbackSuccessComponent?: ComponentType; sessionLostComponent?: ComponentType; authenticatingComponent?: ComponentType; authenticatingErrorComponent?: ComponentType; loadingComponent?: ComponentType; serviceWorkerNotSupportedComponent?: ComponentType; configurationName?: string; configuration?: OidcConfiguration; children: any; onSessionLost?: () => void; onLogoutFromAnotherTab?: () => void; onLogoutFromSameTab?: () => void; withCustomHistory?: () => CustomHistory; onEvent?: (configuration: string, name: string, data: any) => void; getFetch?: () => Fetch; location?: ILOidcLocation; }; export type OidcSessionProps = { configurationName: string; loadingComponent: PropsWithChildren; }; const OidcSession: FC> = ({ loadingComponent, children, configurationName, }) => { const [isLoading, setIsLoading] = useState(true); const getOidc = OidcClient.get; const oidc = getOidc(configurationName); useEffect(() => { let isMounted = true; if (oidc) { oidc.tryKeepExistingSessionAsync().then(() => { if (isMounted) { setIsLoading(false); } }); } return () => { isMounted = false; }; }, [configurationName]); const LoadingComponent = loadingComponent; return ( <>{isLoading ? : <>{children}} ); }; const Switch = ({ isLoading, loadingComponent, children, configurationName }) => { const LoadingComponent = loadingComponent; if (isLoading) { return {children}; } return <>{children}; }; export const OidcProvider: FC> = ({ children, configuration, configurationName = 'default', callbackSuccessComponent = CallBackSuccess, authenticatingComponent = Authenticating, loadingComponent = Loading, serviceWorkerNotSupportedComponent = ServiceWorkerNotSupported, authenticatingErrorComponent = AuthenticatingError, sessionLostComponent = SessionLost, onSessionLost = null, onLogoutFromAnotherTab = null, onLogoutFromSameTab = null, withCustomHistory = null, onEvent = null, getFetch = null, location = null, }) => { if (configuration && configuration.redirect_uri && configuration.silent_redirect_uri) { if (configuration.redirect_uri === configuration.silent_redirect_uri) { throw new Error('redirect_uri and silent_redirect_uri must be different'); } } const getOidc = (configurationName = 'default') => { return OidcClient.getOrCreate(getFetch ?? getFetchDefault, location ?? new OidcLocation())( configuration, configurationName, ); }; const loading = false; const [event, setEvent] = useState(defaultEventState); const [currentConfigurationName, setConfigurationName] = useState(configurationName); useEffect(() => { const oidc = getOidc(configurationName); const newSubscriptionId = oidc.subscribeEvents((name, data) => { if (onEvent) { onEvent(configurationName, name, data); } }); return () => { const previousOidc = getOidc(configurationName); previousOidc.removeEventSubscription(newSubscriptionId); }; }, [configurationName, onEvent]); useEffect(() => { const oidc = getOidc(configurationName); const newSubscriptionId = oidc.subscribeEvents((name, data) => { if ( name === OidcClient.eventNames.refreshTokensAsync_error || name === OidcClient.eventNames.syncTokensAsync_error ) { if (onSessionLost != null) { onSessionLost(); return; } setEvent({ name, data }); } else if (name === OidcClient.eventNames.logout_from_another_tab) { if (onLogoutFromAnotherTab != null) { onLogoutFromAnotherTab(); return; } setEvent({ name, data }); } else if (name === OidcClient.eventNames.logout_from_same_tab) { if (onLogoutFromSameTab != null) { onLogoutFromSameTab(); } // setEvent({name, data}); } else if ( name === OidcClient.eventNames.loginAsync_begin || name === OidcClient.eventNames.loginCallbackAsync_end || name === OidcClient.eventNames.loginAsync_error || name === OidcClient.eventNames.loginCallbackAsync_error ) { setEvent({ name, data }); } else if ( name === OidcClient.eventNames.service_worker_not_supported_by_browser && configuration.service_worker_only === true ) { setEvent({ name, data }); } }); queueMicrotask(() => { setConfigurationName(configurationName); }); return () => { const previousOidc = getOidc(configurationName); previousOidc.removeEventSubscription(newSubscriptionId); setEvent(defaultEventState); }; }, [configuration, configurationName]); useEffect(() => { setConfigurationName(configurationName); }, [configurationName]); const SessionLostComponent = sessionLostComponent; const AuthenticatingComponent = authenticatingComponent; const LoadingComponent = loadingComponent; const ServiceWorkerNotSupportedComponent = serviceWorkerNotSupportedComponent; const AuthenticatingErrorComponent = authenticatingErrorComponent; const isLoading = loading || currentConfigurationName !== configurationName; const oidc = getOidc(configurationName); const eventName = event.name; switch (eventName) { case OidcClient.eventNames.service_worker_not_supported_by_browser: return ( ); case OidcClient.eventNames.loginAsync_begin: return ( ); case OidcClient.eventNames.loginAsync_error: case OidcClient.eventNames.loginCallbackAsync_error: return ( ); case OidcClient.eventNames.refreshTokensAsync_error: case OidcClient.eventNames.syncTokensAsync_error: case OidcClient.eventNames.logout_from_another_tab: return ( ); default: return ( {children} ); } }; export default OidcProvider;