Enhance Authentication Flow and Slicer App Integration
All checks were successful
farmcontrol/farmcontrol-ui/pipeline/head This commit looks good

- Introduced a mechanism to handle pending login token requests using a Map for improved request management.
- Added a utility function to extract the slicer app key from the URL, enhancing authentication handling for the slicer route.
- Updated state management to track slicer authentication status, preventing unauthorized modal display during slicer authentication.
- Refactored logic to streamline the handling of authentication tokens and session management, improving overall user experience.
This commit is contained in:
Tom Butcher 2026-11-07 22:25:55 +00:00
parent b8b8684344
commit 2baf9cffab

View File

@ -43,6 +43,13 @@ const AuthContext = createContext()
const { Text } = Typography const { Text } = Typography
const pendingLoginTokenRequests = new Map()
const getSlicerAppKey = (location) => {
if (location?.pathname !== '/slicer') return null
return new URLSearchParams(location.search).get('authCode') || null
}
const extractUserFromAuthData = (authData) => { const extractUserFromAuthData = (authData) => {
if (!authData || typeof authData !== 'object') return null if (!authData || typeof authData !== 'object') return null
if (authData.user && typeof authData.user === 'object') return authData.user if (authData.user && typeof authData.user === 'object') return authData.user
@ -113,6 +120,10 @@ const AuthProvider = ({ children }) => {
} = useContext(ElectronContext) } = useContext(ElectronContext)
const location = useLocation() const location = useLocation()
const navigate = useNavigate() const navigate = useNavigate()
const slicerAuthPendingRef = useRef(Boolean(getSlicerAppKey(location)))
const [slicerAuthPending, setSlicerAuthPending] = useState(
slicerAuthPendingRef.current
)
const locationRef = useRef(location) const locationRef = useRef(location)
locationRef.current = location locationRef.current = location
const sessionRef = useRef({ const sessionRef = useRef({
@ -123,6 +134,9 @@ const AuthProvider = ({ children }) => {
}) })
sessionRef.current = { token, expiresAt, userProfile, authenticated } sessionRef.current = { token, expiresAt, userProfile, authenticated }
const isDesktopHelperRoute = location.pathname.startsWith('/desktop') const isDesktopHelperRoute = location.pathname.startsWith('/desktop')
const slicerAppKey = getSlicerAppKey(location)
const suppressUnauthorizedModal =
isDesktopHelperRoute || Boolean(slicerAppKey) || slicerAuthPending
var redirectType = 'web' var redirectType = 'web'
@ -458,10 +472,17 @@ const AuthProvider = ({ children }) => {
setShowUnauthorizedModal(false) setShowUnauthorizedModal(false)
setShowSessionExpiredModal(false) setShowSessionExpiredModal(false)
setAuthError(null) setAuthError(null)
try {
const response = await axios.get( let request = pendingLoginTokenRequests.get(code)
if (!request) {
request = axios.get(
`${config.backendUrl}/auth/${redirectType}/token?code=${code}` `${config.backendUrl}/auth/${redirectType}/token?code=${code}`
) )
pendingLoginTokenRequests.set(code, request)
}
try {
const response = await request
if (response.status === 200 && response.data) { if (response.status === 200 && response.data) {
logger.debug('Got auth token!') logger.debug('Got auth token!')
@ -513,6 +534,8 @@ const AuthProvider = ({ children }) => {
} }
setAuthenticated(false) setAuthenticated(false)
} finally { } finally {
slicerAuthPendingRef.current = false
setSlicerAuthPending(false)
setLoading(false) setLoading(false)
setRetreivedTokenFromCookies(true) setRetreivedTokenFromCookies(true)
} }
@ -582,7 +605,11 @@ const AuthProvider = ({ children }) => {
if (hadSession) { if (hadSession) {
clearPersistedSession() clearPersistedSession()
} }
if (showSessionExpiredModal == false) { if (
showSessionExpiredModal == false &&
!slicerAuthPendingRef.current &&
!getSlicerAppKey(locationRef.current)
) {
setShowUnauthorizedModal(true) setShowUnauthorizedModal(true)
} }
}, [clearPersistedSession, showSessionExpiredModal]) }, [clearPersistedSession, showSessionExpiredModal])
@ -768,13 +795,25 @@ const AuthProvider = ({ children }) => {
} }
const authCode = const authCode =
new URLSearchParams(location.search).get('authCode') || null new URLSearchParams(location.search).get('authCode') || null
const slicerKey = getSlicerAppKey(location)
if ( if (
authCode != null && authCode != null &&
processedAuthCodeRef.current !== authCode processedAuthCodeRef.current !== authCode
) { ) {
processedAuthCodeRef.current = authCode processedAuthCodeRef.current = authCode
if (slicerKey) {
slicerAuthPendingRef.current = true
setSlicerAuthPending(true)
setShowUnauthorizedModal(false)
setInitialized(true)
}
getLoginToken(authCode) getLoginToken(authCode)
} else if ( return
}
if (slicerAuthPendingRef.current || slicerKey) {
return
}
if (
token == null && token == null &&
retreivedTokenFromCookies == true && retreivedTokenFromCookies == true &&
initialized == false && initialized == false &&
@ -786,10 +825,9 @@ const AuthProvider = ({ children }) => {
} }
}, [ }, [
checkAuthStatus, checkAuthStatus,
location.search, location,
getLoginToken, getLoginToken,
initialized, initialized,
location.pathname,
navigate, navigate,
token, token,
retreivedTokenFromCookies retreivedTokenFromCookies
@ -870,7 +908,7 @@ const AuthProvider = ({ children }) => {
} }
open={ open={
showUnauthorizedModal && showUnauthorizedModal &&
!isDesktopHelperRoute && !suppressUnauthorizedModal &&
!authenticated && !authenticated &&
!loading && !loading &&
!showAuthErrorModal !showAuthErrorModal