🐛(sso) prevent flash when trying to autologin

the issue was we return the fetchUser promise to react query too early
(before the browser reloaded the page). now we make sure react query
doesn't get the info
This commit is contained in:
Emmanuel Pelletier
2024-07-25 18:08:10 +02:00
committed by aleb_the_flash
parent 234116163a
commit fdff5092b0
5 changed files with 23 additions and 12 deletions

View File

@@ -1,7 +1,7 @@
import { ApiError } from '@/api/ApiError'
import { fetchApi } from '@/api/fetchApi'
import { type ApiUser } from './ApiUser'
import { attemptSilentLogin } from "@/features/auth";
import { attemptSilentLogin, canAttemptSilentLogin } from '../utils/silentLogin'
/**
* fetch the logged-in user from the api.
@@ -17,8 +17,13 @@ export const fetchUser = (): Promise<ApiUser | false> => {
.catch((error) => {
// we assume that a 401 means the user is not logged in
if (error instanceof ApiError && error.statusCode === 401) {
attemptSilentLogin(3600)
resolve(false)
// make sure to not resolve the promise while trying to silent login
// so that consumers of fetchUser don't think the work already ended
if (canAttemptSilentLogin()) {
attemptSilentLogin(3600)
} else {
resolve(false)
}
} else {
reject(error)
}

View File

@@ -1,6 +1,7 @@
import { useQuery } from '@tanstack/react-query'
import { keys } from '@/api/queryKeys'
import { fetchUser } from './fetchUser'
import { type ApiUser } from './ApiUser'
/**
* returns info about currently logged in user
@@ -13,14 +14,13 @@ export const useUser = () => {
queryFn: fetchUser,
})
let isLoggedIn = undefined
if (query.data !== undefined) {
isLoggedIn = query.data !== false
}
const isLoggedIn =
query.status === 'success' ? query.data !== false : undefined
const isLoggedOut = isLoggedIn === false
return {
...query,
// if fetchUser returns false, it means the user is not logged in: expose that
user: query.data === false ? undefined : query.data,
user: isLoggedOut ? undefined : (query.data as ApiUser | undefined),
isLoggedIn,
}
}

View File

@@ -2,4 +2,3 @@ export { useUser } from './api/useUser'
export { authUrl } from './utils/authUrl'
export { logoutUrl } from './utils/logoutUrl'
export { RenderIfUserFetched } from './components/RenderIfUserFetched'
export { attemptSilentLogin } from './utils/silentLogin'

View File

@@ -1,5 +1,8 @@
import { apiUrl } from '@/api/apiUrl'
export const authUrl = (silent = false, returnTo = window.location.href) => {
export const authUrl = ({
silent = false,
returnTo = window.location.href,
} = {}) => {
return apiUrl(`/authenticate?silent=${encodeURIComponent(silent)}&returnTo=${encodeURIComponent(returnTo)}`)
}

View File

@@ -18,7 +18,11 @@ const setNextRetryTime = (retryIntervalInSeconds: number) => {
}
const initiateSilentLogin = () => {
window.location.href = authUrl(true)
window.location.href = authUrl({ silent: true })
}
export const canAttemptSilentLogin = () => {
return isRetryAllowed()
}
export const attemptSilentLogin = (retryIntervalInSeconds: number) => {