Fix: Only show login modal for genuine 401 errors, not connection issues (#8540)

Co-authored-by: openhands <openhands@all-hands.dev>
This commit is contained in:
Robert Brennan
2025-05-16 13:33:06 -04:00
committed by GitHub
parent 2faed14139
commit 819bad0777
3 changed files with 35 additions and 24 deletions

View File

@@ -76,9 +76,9 @@ class OpenHands {
): Promise<boolean> {
if (appMode === "oss") return true;
const response =
await openHands.post<AuthenticateResponse>("/api/authenticate");
return response.status === 200;
// Just make the request, if it succeeds (no exception thrown), return true
await openHands.post<AuthenticateResponse>("/api/authenticate");
return true;
}
/**

View File

@@ -1,4 +1,5 @@
import { useQuery } from "@tanstack/react-query";
import axios, { AxiosError } from "axios";
import OpenHands from "#/api/open-hands";
import { useConfig } from "./use-config";
import { useIsOnTosPage } from "#/hooks/use-is-on-tos-page";
@@ -11,7 +12,23 @@ export const useIsAuthed = () => {
return useQuery({
queryKey: ["user", "authenticated", appMode],
queryFn: () => OpenHands.authenticate(appMode!),
queryFn: async () => {
try {
// If in OSS mode or authentication succeeds, return true
await OpenHands.authenticate(appMode!);
return true;
} catch (error) {
// If it's a 401 error, return false (not authenticated)
if (axios.isAxiosError(error)) {
const axiosError = error as AxiosError;
if (axiosError.response?.status === 401) {
return false;
}
}
// For any other error, throw it to put the query in error state
throw error;
}
},
enabled: !!appMode && !isOnTosPage,
staleTime: 1000 * 60 * 5, // 5 minutes
gcTime: 1000 * 60 * 15, // 15 minutes

View File

@@ -58,7 +58,7 @@ export function ErrorBoundary() {
export default function MainApp() {
const navigate = useNavigate();
const { pathname } = useLocation();
const tosPageStatus = useIsOnTosPage();
const isOnTosPage = useIsOnTosPage();
const { data: settings } = useSettings();
const { error } = useBalance();
const { migrateUserConsent } = useMigrateUserConsent();
@@ -68,7 +68,7 @@ export default function MainApp() {
const {
data: isAuthed,
isFetching: isFetchingAuth,
isError: authError,
isError: isAuthError,
} = useIsAuthed();
// Always call the hook, but we'll only use the result when not on TOS page
@@ -78,30 +78,30 @@ export default function MainApp() {
});
// When on TOS page, we don't use the GitHub auth URL
const effectiveGitHubAuthUrl = tosPageStatus ? null : gitHubAuthUrl;
const effectiveGitHubAuthUrl = isOnTosPage ? null : gitHubAuthUrl;
const [consentFormIsOpen, setConsentFormIsOpen] = React.useState(false);
React.useEffect(() => {
// Don't change language when on TOS page
if (!tosPageStatus && settings?.LANGUAGE) {
if (!isOnTosPage && settings?.LANGUAGE) {
i18n.changeLanguage(settings.LANGUAGE);
}
}, [settings?.LANGUAGE, tosPageStatus]);
}, [settings?.LANGUAGE, isOnTosPage]);
React.useEffect(() => {
// Don't show consent form when on TOS page
if (!tosPageStatus) {
if (!isOnTosPage) {
const consentFormModalIsOpen =
settings?.USER_CONSENTS_TO_ANALYTICS === null;
setConsentFormIsOpen(consentFormModalIsOpen);
}
}, [settings, tosPageStatus]);
}, [settings, isOnTosPage]);
React.useEffect(() => {
// Don't migrate user consent when on TOS page
if (!tosPageStatus) {
if (!isOnTosPage) {
// Migrate user consent to the server if it was previously stored in localStorage
migrateUserConsent({
handleAnalyticsWasPresentInLocalStorage: () => {
@@ -109,7 +109,7 @@ export default function MainApp() {
},
});
}
}, [tosPageStatus]);
}, [isOnTosPage]);
React.useEffect(() => {
if (settings?.IS_NEW_USER && config.data?.APP_MODE === "saas") {
@@ -120,22 +120,16 @@ export default function MainApp() {
React.useEffect(() => {
// Don't do any redirects when on TOS page
// Don't allow users to use the app if it 402s
if (!tosPageStatus && error?.status === 402 && pathname !== "/") {
if (!isOnTosPage && error?.status === 402 && pathname !== "/") {
navigate("/");
}
}, [error?.status, pathname, tosPageStatus]);
}, [error?.status, pathname, isOnTosPage]);
// When on TOS page, we don't make any API calls, so we need to handle this case
const userIsAuthed = tosPageStatus ? false : !!isAuthed && !authError;
// Only show the auth modal if:
// 1. User is not authenticated
// 2. We're not currently on the TOS page
// 3. We're in SaaS mode
const renderAuthModal =
!isAuthed &&
!isAuthError &&
!isFetchingAuth &&
!userIsAuthed &&
!tosPageStatus &&
!isOnTosPage &&
config.data?.APP_MODE === "saas";
return (