import React , { useCallback , useState , useEffect , useRef } from "react" ; import { setContext } from "apollo-link-context" ; import ApolloClient from "apollo-client" ; import { DocumentNode } from "graphql" ; import { useApolloClient } from "@apollo/react-hooks" ; import { Security } from "@okta/okta-react" ; import { OktaAuth , AuthStateManager } from "@okta/okta-auth-js" ; import OktaSignIn from "@okta/okta-signin-widget" ; import { plugins } from "@webiny/plugins" ; import { CircularProgress } from "@webiny/ui/Progress" ; import { useSecurity } from "@webiny/app-security" ; import { ApolloLinkPlugin } from "@webiny/app/plugins/ApolloLinkPlugin" ; import OktaSignInWidget from "./OktaSignInWidget" ; import { createGetIdentityData , LOGIN_MT , LOGIN_ST } from "./createGetIdentityData" ; import { useTenancy , withTenant } from "@webiny/app-tenancy" ; const noop = ( ) => { } ; export interface Config { getIdentityData ? : any ; loginMutation ? : DocumentNode ; oktaAuth : OktaAuth ; oktaSignIn : OktaSignIn ; } export interface Props { getIdentityData ( params ) : Promise < { [ key ] : any ; } > ; children : React . ReactNode ; } export const createAuthentication = ( { oktaAuth , oktaSignIn , ... config } ) => { const withGetIdentityData = Component => { const WithGetIdentityData = ( { children } ) => { const { isMultiTenant } = useTenancy ( ) ; const loginMutation = config . loginMutation || ( isMultiTenant ? LOGIN_MT : LOGIN_ST ) ; const getIdentityData = config . getIdentityData || createGetIdentityData ( loginMutation ) ; return < Component getIdentityData = { getIdentityData } > { children } < /Component>; } ; return WithGetIdentityData ; } ; const Authentication = ( { getIdentityData , children } ) => { const timerRef = useRef ( null ) ; const apolloClient = useApolloClient ( ) ; const { identity , setIdentity } = useSecurity ( ) ; const [ isAuthenticated , setIsAuthenticated ] = useState ( false ) ; useEffect ( ( ) => { plugins . register ( new ApolloLinkPlugin ( ( ) => { return setContext ( async ( _ , payload ) => { clearTimeout ( timerRef . current ) ; timerRef . current = setTimeout ( ( ) => { window . location . reload ( ) ; } , 3600000 ) ; return payload ; } ) ; } ) , new ApolloLinkPlugin ( ( ) => { return setContext ( async ( _ , { headers } ) => { if ( headers && headers . Authorization ) { return { headers } ; } if ( ! oktaAuth . isAuthenticated ( ) ) { return { headers } ; } const idToken = oktaAuth . getIdToken ( ) ; if ( ! idToken ) { return { headers } ; } return { headers : { ... headers , Authorization : `Bearer ${ idToken }` } } ; } ) ; } ) ) ; } , [ ] ) ; const authStateChanged = useCallback ( async ( authState ) => { setIsAuthenticated ( authState . isAuthenticated ) ; if ( authState . isAuthenticated ) { try { const { id , displayName , type , permissions , ... other } = await getIdentityData ( { client : apolloClient } ) ; setIdentity ( { id , displayName , type , permissions , ... other , logout ( ) { clearTimeout ( timerRef . current ) ; oktaAuth . signOut ( ) ; setIdentity ( null ) ; setIsAuthenticated ( false ) ; } } ) ; } catch ( err ) { console . log ( err ) ; } } else { setIdentity ( null ) ; } } , [ ] ) ; useEffect ( ( ) => { const authStateManager = oktaAuth . authStateManager ; authStateManager . subscribe ( authStateChanged ) ; return ( ) => authStateManager . unsubscribe ( authStateChanged ) ; } , [ ] ) ; return ( < Security oktaAuth = { oktaAuth } restoreOriginalUri = { noop } > { identity ? ( children ) : isAuthenticated ? ( < CircularProgress label = { "Checking user..." } / > ) : ( < OktaSignInWidget oktaSignIn = { oktaSignIn } / > ) } < /Security>); } ; return withGetIdentityData ( withTenant ( Authentication ) ) ; } ;