Skip to content

Commit 819bad0

Browse files
Fix: Only show login modal for genuine 401 errors, not connection issues (All-Hands-AI#8540)
Co-authored-by: openhands <[email protected]>
1 parent 2faed14 commit 819bad0

File tree

3 files changed

+35
-24
lines changed

3 files changed

+35
-24
lines changed

frontend/src/api/open-hands.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,9 +76,9 @@ class OpenHands {
7676
): Promise<boolean> {
7777
if (appMode === "oss") return true;
7878

79-
const response =
80-
await openHands.post<AuthenticateResponse>("/api/authenticate");
81-
return response.status === 200;
79+
// Just make the request, if it succeeds (no exception thrown), return true
80+
await openHands.post<AuthenticateResponse>("/api/authenticate");
81+
return true;
8282
}
8383

8484
/**

frontend/src/hooks/query/use-is-authed.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { useQuery } from "@tanstack/react-query";
2+
import axios, { AxiosError } from "axios";
23
import OpenHands from "#/api/open-hands";
34
import { useConfig } from "./use-config";
45
import { useIsOnTosPage } from "#/hooks/use-is-on-tos-page";
@@ -11,7 +12,23 @@ export const useIsAuthed = () => {
1112

1213
return useQuery({
1314
queryKey: ["user", "authenticated", appMode],
14-
queryFn: () => OpenHands.authenticate(appMode!),
15+
queryFn: async () => {
16+
try {
17+
// If in OSS mode or authentication succeeds, return true
18+
await OpenHands.authenticate(appMode!);
19+
return true;
20+
} catch (error) {
21+
// If it's a 401 error, return false (not authenticated)
22+
if (axios.isAxiosError(error)) {
23+
const axiosError = error as AxiosError;
24+
if (axiosError.response?.status === 401) {
25+
return false;
26+
}
27+
}
28+
// For any other error, throw it to put the query in error state
29+
throw error;
30+
}
31+
},
1532
enabled: !!appMode && !isOnTosPage,
1633
staleTime: 1000 * 60 * 5, // 5 minutes
1734
gcTime: 1000 * 60 * 15, // 15 minutes

frontend/src/routes/root-layout.tsx

Lines changed: 14 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ export function ErrorBoundary() {
5858
export default function MainApp() {
5959
const navigate = useNavigate();
6060
const { pathname } = useLocation();
61-
const tosPageStatus = useIsOnTosPage();
61+
const isOnTosPage = useIsOnTosPage();
6262
const { data: settings } = useSettings();
6363
const { error } = useBalance();
6464
const { migrateUserConsent } = useMigrateUserConsent();
@@ -68,7 +68,7 @@ export default function MainApp() {
6868
const {
6969
data: isAuthed,
7070
isFetching: isFetchingAuth,
71-
isError: authError,
71+
isError: isAuthError,
7272
} = useIsAuthed();
7373

7474
// Always call the hook, but we'll only use the result when not on TOS page
@@ -78,38 +78,38 @@ export default function MainApp() {
7878
});
7979

8080
// When on TOS page, we don't use the GitHub auth URL
81-
const effectiveGitHubAuthUrl = tosPageStatus ? null : gitHubAuthUrl;
81+
const effectiveGitHubAuthUrl = isOnTosPage ? null : gitHubAuthUrl;
8282

8383
const [consentFormIsOpen, setConsentFormIsOpen] = React.useState(false);
8484

8585
React.useEffect(() => {
8686
// Don't change language when on TOS page
87-
if (!tosPageStatus && settings?.LANGUAGE) {
87+
if (!isOnTosPage && settings?.LANGUAGE) {
8888
i18n.changeLanguage(settings.LANGUAGE);
8989
}
90-
}, [settings?.LANGUAGE, tosPageStatus]);
90+
}, [settings?.LANGUAGE, isOnTosPage]);
9191

9292
React.useEffect(() => {
9393
// Don't show consent form when on TOS page
94-
if (!tosPageStatus) {
94+
if (!isOnTosPage) {
9595
const consentFormModalIsOpen =
9696
settings?.USER_CONSENTS_TO_ANALYTICS === null;
9797

9898
setConsentFormIsOpen(consentFormModalIsOpen);
9999
}
100-
}, [settings, tosPageStatus]);
100+
}, [settings, isOnTosPage]);
101101

102102
React.useEffect(() => {
103103
// Don't migrate user consent when on TOS page
104-
if (!tosPageStatus) {
104+
if (!isOnTosPage) {
105105
// Migrate user consent to the server if it was previously stored in localStorage
106106
migrateUserConsent({
107107
handleAnalyticsWasPresentInLocalStorage: () => {
108108
setConsentFormIsOpen(false);
109109
},
110110
});
111111
}
112-
}, [tosPageStatus]);
112+
}, [isOnTosPage]);
113113

114114
React.useEffect(() => {
115115
if (settings?.IS_NEW_USER && config.data?.APP_MODE === "saas") {
@@ -120,22 +120,16 @@ export default function MainApp() {
120120
React.useEffect(() => {
121121
// Don't do any redirects when on TOS page
122122
// Don't allow users to use the app if it 402s
123-
if (!tosPageStatus && error?.status === 402 && pathname !== "/") {
123+
if (!isOnTosPage && error?.status === 402 && pathname !== "/") {
124124
navigate("/");
125125
}
126-
}, [error?.status, pathname, tosPageStatus]);
126+
}, [error?.status, pathname, isOnTosPage]);
127127

128-
// When on TOS page, we don't make any API calls, so we need to handle this case
129-
const userIsAuthed = tosPageStatus ? false : !!isAuthed && !authError;
130-
131-
// Only show the auth modal if:
132-
// 1. User is not authenticated
133-
// 2. We're not currently on the TOS page
134-
// 3. We're in SaaS mode
135128
const renderAuthModal =
129+
!isAuthed &&
130+
!isAuthError &&
136131
!isFetchingAuth &&
137-
!userIsAuthed &&
138-
!tosPageStatus &&
132+
!isOnTosPage &&
139133
config.data?.APP_MODE === "saas";
140134

141135
return (

0 commit comments

Comments
 (0)