Compare commits

...

3 Commits

Author SHA1 Message Date
chuckbutkus
7d31958f00 Merge branch 'main' into fix-login-method-after-auth 2025-05-27 15:36:56 -04:00
openhands
60d70411e3 Fix: Move setLoginMethod call to after authentication is completed 2025-05-27 19:17:47 +00:00
openhands
b10872b544 Update loginMethodExists to recompute on logout 2025-05-27 18:09:00 +00:00
4 changed files with 106 additions and 14 deletions

View File

@@ -26,23 +26,23 @@ export function AuthModal({ githubAuthUrl, appMode }: AuthModalProps) {
const handleGitHubAuth = () => {
if (githubAuthUrl) {
// Store the login method in local storage (only in SAAS mode)
if (appMode === "saas") {
setLoginMethod(LoginMethod.GITHUB);
}
// Add a query parameter to identify the login method
const url = new URL(githubAuthUrl);
url.searchParams.append("login_method", LoginMethod.GITHUB);
// Always start the OIDC flow, let the backend handle TOS check
window.location.href = githubAuthUrl;
window.location.href = url.toString();
}
};
const handleGitLabAuth = () => {
if (gitlabAuthUrl) {
// Store the login method in local storage (only in SAAS mode)
if (appMode === "saas") {
setLoginMethod(LoginMethod.GITLAB);
}
// Add a query parameter to identify the login method
const url = new URL(gitlabAuthUrl);
url.searchParams.append("login_method", LoginMethod.GITLAB);
// Always start the OIDC flow, let the backend handle TOS check
window.location.href = gitlabAuthUrl;
window.location.href = url.toString();
}
};

View File

@@ -0,0 +1,45 @@
import { useEffect } from "react";
import { useLocation } from "react-router";
import { useIsAuthed } from "./query/use-is-authed";
import { LoginMethod, setLoginMethod } from "#/utils/local-storage";
import { useConfig } from "./query/use-config";
/**
* Hook to handle authentication callback and set login method after successful authentication
*/
export const useAuthCallback = () => {
const location = useLocation();
const { data: isAuthed, isLoading: isAuthLoading } = useIsAuthed();
const { data: config } = useConfig();
useEffect(() => {
// Only run in SAAS mode
if (config?.APP_MODE !== "saas") {
return;
}
// Wait for auth to load
if (isAuthLoading) {
return;
}
// Only set login method if authentication was successful
if (!isAuthed) {
return;
}
// Check if we have a login_method query parameter
const searchParams = new URLSearchParams(location.search);
const loginMethod = searchParams.get("login_method");
// Set the login method if it's valid
if (loginMethod === LoginMethod.GITHUB || loginMethod === LoginMethod.GITLAB) {
setLoginMethod(loginMethod as LoginMethod);
// Clean up the URL by removing the login_method parameter
searchParams.delete("login_method");
const newUrl = `${location.pathname}${searchParams.toString() ? `?${searchParams.toString()}` : ""}`;
window.history.replaceState({}, "", newUrl);
}
}, [isAuthed, isAuthLoading, location.search, config?.APP_MODE]);
};

View File

@@ -48,13 +48,17 @@ export const useAutoLogin = () => {
}
// Get the appropriate auth URL based on the stored login method
const authUrl =
let authUrl =
loginMethod === LoginMethod.GITHUB ? githubAuthUrl : gitlabAuthUrl;
// If we have an auth URL, redirect to it
if (authUrl) {
// Add the login method as a query parameter
const url = new URL(authUrl);
url.searchParams.append("login_method", loginMethod);
// After successful login, the user will be redirected back and can navigate to the last page
window.location.href = authUrl;
window.location.href = url.toString();
}
}, [
config?.APP_MODE,

View File

@@ -23,6 +23,7 @@ import { SetupPaymentModal } from "#/components/features/payment/setup-payment-m
import { displaySuccessToast } from "#/utils/custom-toast-handlers";
import { useIsOnTosPage } from "#/hooks/use-is-on-tos-page";
import { useAutoLogin } from "#/hooks/use-auto-login";
import { useAuthCallback } from "#/hooks/use-auth-callback";
import { LOCAL_STORAGE_KEYS } from "#/utils/local-storage";
export function ErrorBoundary() {
@@ -87,6 +88,9 @@ export default function MainApp() {
// Auto-login if login method is stored in local storage
useAutoLogin();
// Handle authentication callback and set login method after successful authentication
useAuthCallback();
React.useEffect(() => {
// Don't change language when on TOS page
@@ -131,8 +135,8 @@ export default function MainApp() {
}
}, [error?.status, pathname, isOnTosPage]);
// Check if login method exists in local storage
const loginMethodExists = React.useMemo(() => {
// Function to check if login method exists in local storage
const checkLoginMethodExists = React.useCallback(() => {
// Only check localStorage if we're in a browser environment
if (typeof window !== "undefined" && window.localStorage) {
return localStorage.getItem(LOCAL_STORAGE_KEYS.LOGIN_METHOD) !== null;
@@ -140,6 +144,45 @@ export default function MainApp() {
return false;
}, []);
// State to track if login method exists
const [loginMethodExists, setLoginMethodExists] = React.useState(
checkLoginMethodExists(),
);
// Listen for storage events to update loginMethodExists when logout happens
React.useEffect(() => {
const handleStorageChange = (event: StorageEvent) => {
if (event.key === LOCAL_STORAGE_KEYS.LOGIN_METHOD) {
setLoginMethodExists(checkLoginMethodExists());
}
};
// Also check on window focus, as logout might happen in another tab
const handleWindowFocus = () => {
setLoginMethodExists(checkLoginMethodExists());
};
window.addEventListener("storage", handleStorageChange);
window.addEventListener("focus", handleWindowFocus);
return () => {
window.removeEventListener("storage", handleStorageChange);
window.removeEventListener("focus", handleWindowFocus);
};
}, [checkLoginMethodExists]);
// Check login method status when auth status changes
React.useEffect(() => {
// When auth status changes (especially on logout), recheck login method
setLoginMethodExists(checkLoginMethodExists());
}, [isAuthed, checkLoginMethodExists]);
// Recheck on component mount to ensure we have the latest value after page reload
React.useEffect(() => {
// This will run once when the component mounts, ensuring we have the latest value
setLoginMethodExists(checkLoginMethodExists());
}, [checkLoginMethodExists]);
const renderAuthModal =
!isAuthed &&
!isAuthError &&