mirror of
https://github.com/enso-org/enso.git
synced 2024-09-11 13:15:52 +03:00
Refetch user session when it expires (#9632)
This commit is contained in:
parent
7e345075b3
commit
30a80db4b0
@ -304,6 +304,8 @@ function AppRouter(props: AppRouterProps) {
|
||||
}, [props, /* should never change */ navigate])
|
||||
|
||||
const userSession = authService?.cognito.userSession.bind(authService.cognito) ?? null
|
||||
const refreshUserSession =
|
||||
authService?.cognito.refreshUserSession.bind(authService.cognito) ?? null
|
||||
const registerAuthEventListener = authService?.registerAuthEventListener ?? null
|
||||
const initialBackend: Backend =
|
||||
isAuthenticationDisabled && projectManagerUrl != null && projectManagerRootDirectory != null
|
||||
@ -425,6 +427,13 @@ function AppRouter(props: AppRouterProps) {
|
||||
mainPageUrl={mainPageUrl}
|
||||
userSession={userSession}
|
||||
registerAuthEventListener={registerAuthEventListener}
|
||||
refreshUserSession={
|
||||
refreshUserSession
|
||||
? async () => {
|
||||
await refreshUserSession()
|
||||
}
|
||||
: null
|
||||
}
|
||||
>
|
||||
{result}
|
||||
</SessionProvider>
|
||||
|
@ -273,6 +273,13 @@ export class Cognito {
|
||||
return results.Err(cognitoUserResult.val)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Refresh the current user's session.
|
||||
*/
|
||||
async refreshUserSession() {
|
||||
return Promise.resolve(results.Ok(null))
|
||||
}
|
||||
}
|
||||
|
||||
// ===================
|
||||
|
@ -273,6 +273,27 @@ export class Cognito {
|
||||
return result.mapErr(intoAmplifyErrorOrThrow).mapErr(intoSignInWithPasswordErrorOrThrow)
|
||||
}
|
||||
|
||||
/**
|
||||
* Refresh the current user session.
|
||||
*/
|
||||
async refreshUserSession() {
|
||||
const result = await results.Result.wrapAsync(async () => {
|
||||
const currentUser = await currentAuthenticatedUser()
|
||||
const refreshToken = (await amplify.Auth.currentSession()).getRefreshToken()
|
||||
|
||||
await new Promise((resolve, reject) => {
|
||||
currentUser.unwrap().refreshSession(refreshToken, (error, session) => {
|
||||
if (error instanceof Error) {
|
||||
reject(error)
|
||||
} else {
|
||||
resolve(session)
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
return result.mapErr(intoCurrentSessionErrorType)
|
||||
}
|
||||
|
||||
/** Sign out the current user. */
|
||||
async signOut() {
|
||||
// FIXME [NP]: https://github.com/enso-org/cloud-v2/issues/341
|
||||
|
@ -2,6 +2,8 @@
|
||||
* currently authenticated user's session. */
|
||||
import * as React from 'react'
|
||||
|
||||
import * as reactQuery from '@tanstack/react-query'
|
||||
|
||||
import * as asyncEffectHooks from '#/hooks/asyncEffectHooks'
|
||||
import * as refreshHooks from '#/hooks/refreshHooks'
|
||||
|
||||
@ -44,12 +46,17 @@ export interface SessionProviderProps {
|
||||
readonly mainPageUrl: URL
|
||||
readonly registerAuthEventListener: listen.ListenFunction | null
|
||||
readonly userSession: (() => Promise<cognito.UserSession | null>) | null
|
||||
readonly refreshUserSession: (() => Promise<void>) | null
|
||||
readonly children: React.ReactNode
|
||||
}
|
||||
|
||||
const FIVE_MINUTES_MS = 300_000
|
||||
const SIX_HOURS_MS = 21_600_000
|
||||
|
||||
/** A React provider for the session of the authenticated user. */
|
||||
export default function SessionProvider(props: SessionProviderProps) {
|
||||
const { mainPageUrl, children, userSession, registerAuthEventListener } = props
|
||||
const { mainPageUrl, children, userSession, registerAuthEventListener, refreshUserSession } =
|
||||
props
|
||||
const [refresh, doRefresh] = refreshHooks.useRefresh()
|
||||
const [initialized, setInitialized] = React.useState(false)
|
||||
const errorCallbacks = React.useRef(new Set<(error: Error) => void>())
|
||||
@ -89,6 +96,26 @@ export default function SessionProvider(props: SessionProviderProps) {
|
||||
[refresh]
|
||||
)
|
||||
|
||||
const timeUntilRefresh = session
|
||||
? // If the session has not expired, we should refresh it when it is 5 minutes from expiring.
|
||||
new Date(session.expireAt).getTime() - Date.now() - FIVE_MINUTES_MS
|
||||
: Infinity
|
||||
|
||||
reactQuery.useQuery({
|
||||
queryKey: ['userSession'],
|
||||
queryFn: refreshUserSession
|
||||
? () =>
|
||||
refreshUserSession()
|
||||
.then(() => {
|
||||
doRefresh()
|
||||
})
|
||||
.then(() => null)
|
||||
: reactQuery.skipToken,
|
||||
refetchOnWindowFocus: true,
|
||||
refetchIntervalInBackground: true,
|
||||
refetchInterval: timeUntilRefresh < SIX_HOURS_MS ? timeUntilRefresh : SIX_HOURS_MS,
|
||||
})
|
||||
|
||||
// Register an effect that will listen for authentication events. When the event occurs, we
|
||||
// will refresh or clear the user's session, forcing a re-render of the page with the new
|
||||
// session.
|
||||
|
Loading…
Reference in New Issue
Block a user