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

View File

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

View File

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

View File

@@ -1,5 +1,8 @@
import { apiUrl } from '@/api/apiUrl' 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)}`) return apiUrl(`/authenticate?silent=${encodeURIComponent(silent)}&returnTo=${encodeURIComponent(returnTo)}`)
} }

View File

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