diff --git a/src/frontend/src/App.tsx b/src/frontend/src/App.tsx index 0a8583486..09f663fc5 100644 --- a/src/frontend/src/App.tsx +++ b/src/frontend/src/App.tsx @@ -1,4 +1,5 @@ import { useContext, useEffect, useState } from "react"; +import { Cookies } from "react-cookie"; import { ErrorBoundary } from "react-error-boundary"; import { useNavigate } from "react-router-dom"; import "reactflow/dist/style.css"; @@ -10,6 +11,7 @@ import LoadingComponent from "./components/loadingComponent"; import { FETCH_ERROR_DESCRIPION, FETCH_ERROR_MESSAGE, + LANGFLOW_AUTO_LOGIN_OPTION, } from "./constants/constants"; import { AuthContext } from "./contexts/authContext"; import { autoLogin } from "./controllers/API"; @@ -27,13 +29,14 @@ import { useFolderStore } from "./stores/foldersStore"; export default function App() { useTrackLastVisitedPath(); const isLoading = useFlowsManagerStore((state) => state.isLoading); - const { isAuthenticated, login, setUserData, setAutoLogin, getUser } = + const { isAuthenticated, login, setUserData, setAutoLogin, getUser, logout } = useContext(AuthContext); const setLoading = useAlertStore((state) => state.setLoading); const refreshStars = useDarkStore((state) => state.refreshStars); const dark = useDarkStore((state) => state.dark); useGetVersionQuery(); + const cookies = new Cookies(); const isLoadingFolders = useFolderStore((state) => state.isLoadingFolders); @@ -60,7 +63,7 @@ export default function App() { .then(async (user) => { if (user && user["access_token"]) { user["refresh_token"] = "auto"; - login(user["access_token"]); + login(user["access_token"], "auto"); setUserData(user); setAutoLogin(true); fetchAllData(); @@ -69,6 +72,14 @@ export default function App() { .catch(async (error) => { if (error.name !== "CanceledError") { setAutoLogin(false); + if ( + cookies.get(LANGFLOW_AUTO_LOGIN_OPTION) === "auto" && + isAuthenticated + ) { + logout(); + return; + } + if (isAuthenticated && !isLoginPage) { getUser(); fetchAllData(); diff --git a/src/frontend/src/constants/constants.ts b/src/frontend/src/constants/constants.ts index 9ca0122f4..1a89cd27f 100644 --- a/src/frontend/src/constants/constants.ts +++ b/src/frontend/src/constants/constants.ts @@ -866,3 +866,7 @@ export const TABS_ORDER = [ "python code", "chat widget html", ]; + +export const LANGFLOW_ACCESS_TOKEN = "access_token_lf"; +export const LANGFLOW_API_TOKEN = "apikey_tkn_lflw"; +export const LANGFLOW_AUTO_LOGIN_OPTION = "auto_login_lf"; diff --git a/src/frontend/src/contexts/authContext.tsx b/src/frontend/src/contexts/authContext.tsx index 89b6b2b6b..a4709c42b 100644 --- a/src/frontend/src/contexts/authContext.tsx +++ b/src/frontend/src/contexts/authContext.tsx @@ -1,3 +1,8 @@ +import { + LANGFLOW_ACCESS_TOKEN, + LANGFLOW_API_TOKEN, + LANGFLOW_AUTO_LOGIN_OPTION, +} from "@/constants/constants"; import useFlowsManagerStore from "@/stores/flowsManagerStore"; import { createContext, useEffect, useState } from "react"; import { useNavigate } from "react-router-dom"; @@ -38,17 +43,17 @@ export function AuthProvider({ children }): React.ReactElement { const navigate = useNavigate(); const cookies = new Cookies(); const [accessToken, setAccessToken] = useState( - cookies.get("access_token_lf") ?? null, + cookies.get(LANGFLOW_ACCESS_TOKEN) ?? null, ); const [isAuthenticated, setIsAuthenticated] = useState( - !!cookies.get("access_token_lf"), + !!cookies.get(LANGFLOW_ACCESS_TOKEN), ); const [isAdmin, setIsAdmin] = useState(false); const [userData, setUserData] = useState(null); const [autoLogin, setAutoLogin] = useState(false); const setLoading = useAlertStore((state) => state.setLoading); const [apiKey, setApiKey] = useState( - cookies.get("apikey_tkn_lflw"), + cookies.get(LANGFLOW_API_TOKEN), ); const getFoldersApi = useFolderStore((state) => state.getFoldersApi); @@ -61,14 +66,14 @@ export function AuthProvider({ children }): React.ReactElement { const setSelectedFolder = useFolderStore((state) => state.setSelectedFolder); useEffect(() => { - const storedAccessToken = cookies.get("access_token_lf"); + const storedAccessToken = cookies.get(LANGFLOW_ACCESS_TOKEN); if (storedAccessToken) { setAccessToken(storedAccessToken); } }, []); useEffect(() => { - const apiKey = cookies.get("apikey_tkn_lflw"); + const apiKey = cookies.get(LANGFLOW_API_TOKEN); if (apiKey) { setApiKey(apiKey); } @@ -91,7 +96,8 @@ export function AuthProvider({ children }): React.ReactElement { }); } - function login(newAccessToken: string) { + function login(newAccessToken: string, autoLogin: string) { + cookies.set(LANGFLOW_AUTO_LOGIN_OPTION, autoLogin, { path: "/" }); setAccessToken(newAccessToken); setIsAuthenticated(true); getUser(); @@ -103,7 +109,8 @@ export function AuthProvider({ children }): React.ReactElement { } try { await requestLogout(); - cookies.remove("apikey_tkn_lflw", { path: "/" }); + cookies.remove(LANGFLOW_API_TOKEN, { path: "/" }); + cookies.remove(LANGFLOW_AUTO_LOGIN_OPTION, { path: "/" }); setIsAdmin(false); setUserData(null); setAccessToken(null); @@ -111,6 +118,7 @@ export function AuthProvider({ children }): React.ReactElement { setAllFlows([]); setSelectedFolder(null); navigate("/login"); + useFlowsManagerStore.setState({ isLoading: false }); } catch (error) { console.error(error); throw error; @@ -118,7 +126,7 @@ export function AuthProvider({ children }): React.ReactElement { } function storeApiKey(apikey: string) { - cookies.set("apikey_tkn_lflw", apikey, { path: "/" }); + cookies.set(LANGFLOW_ACCESS_TOKEN, apikey, { path: "/" }); setApiKey(apikey); } diff --git a/src/frontend/src/controllers/API/api.tsx b/src/frontend/src/controllers/API/api.tsx index c34fb0946..3545a639c 100644 --- a/src/frontend/src/controllers/API/api.tsx +++ b/src/frontend/src/controllers/API/api.tsx @@ -1,3 +1,7 @@ +import { + LANGFLOW_ACCESS_TOKEN, + LANGFLOW_AUTO_LOGIN_OPTION, +} from "@/constants/constants"; import axios, { AxiosError, AxiosInstance } from "axios"; import { useContext, useEffect } from "react"; import { Cookies } from "react-cookie"; @@ -37,7 +41,7 @@ function ApiInterceptor() { } const acceptedRequest = await tryToRenewAccessToken(error); - const accessToken = cookies.get("access_token_lf"); + const accessToken = cookies.get(LANGFLOW_ACCESS_TOKEN); if (!accessToken && error?.config?.url?.includes("login")) { return Promise.reject(error); @@ -90,7 +94,7 @@ function ApiInterceptor() { console.error("Duplicate Request"); } - const accessToken = cookies.get("access_token_lf"); + const accessToken = cookies.get(LANGFLOW_ACCESS_TOKEN); if (accessToken && !isAuthorizedURL(config?.url)) { config.headers["Authorization"] = `Bearer ${accessToken}`; } @@ -129,7 +133,7 @@ function ApiInterceptor() { if (window.location.pathname.includes("/login")) return; const res = await renewAccessToken(); if (res?.data?.access_token && res?.data?.refresh_token) { - login(res?.data?.access_token); + login(res?.data?.access_token, cookies.get(LANGFLOW_AUTO_LOGIN_OPTION)); } } catch (error) { clearBuildVerticesState(error); diff --git a/src/frontend/src/controllers/API/index.ts b/src/frontend/src/controllers/API/index.ts index e25cc98c6..6805d0f96 100644 --- a/src/frontend/src/controllers/API/index.ts +++ b/src/frontend/src/controllers/API/index.ts @@ -140,8 +140,8 @@ export async function saveFlowToDatabase(newFlow: { endpoint_name: newFlow.endpoint_name, }); - if (response.status !== 201) { - throw new Error(`HTTP error! status: ${response.status}`); + if (response?.status !== 201) { + throw new Error(`HTTP error! status: ${response?.status}`); } return response.data; } catch (error) { @@ -254,8 +254,8 @@ export async function deleteFlowFromDatabase(flowId: string) { export async function getFlowFromDatabase(flowId: number) { try { const response = await api.get(`${BASE_URL_API}flows/${flowId}`); - if (response.status !== 200) { - throw new Error(`HTTP error! status: ${response.status}`); + if (response?.status !== 200) { + throw new Error(`HTTP error! status: ${response?.status}`); } return response.data; } catch (error) { diff --git a/src/frontend/src/pages/AdminPage/LoginPage/index.tsx b/src/frontend/src/pages/AdminPage/LoginPage/index.tsx index 0c7e073df..13e996c4a 100644 --- a/src/frontend/src/pages/AdminPage/LoginPage/index.tsx +++ b/src/frontend/src/pages/AdminPage/LoginPage/index.tsx @@ -40,7 +40,7 @@ export default function LoginAdminPage() { setLoading(true); - login(user.access_token); + login(user.access_token, "login"); navigate("/admin/"); }) .catch((error) => { diff --git a/src/frontend/src/pages/LoginPage/index.tsx b/src/frontend/src/pages/LoginPage/index.tsx index d25d1c2e1..ea2e0b553 100644 --- a/src/frontend/src/pages/LoginPage/index.tsx +++ b/src/frontend/src/pages/LoginPage/index.tsx @@ -39,10 +39,8 @@ export default function LoginPage(): JSX.Element { }; onLogin(user) .then((user) => { - console.log("login page"); - setLoading(true); - login(user.access_token); + login(user.access_token, "login"); navigate("/"); }) .catch((error) => { diff --git a/src/frontend/src/stores/foldersStore.tsx b/src/frontend/src/stores/foldersStore.tsx index 3ec462800..ec013d66e 100644 --- a/src/frontend/src/stores/foldersStore.tsx +++ b/src/frontend/src/stores/foldersStore.tsx @@ -25,7 +25,7 @@ export const useFolderStore = create((set, get) => ({ (folder) => folder.name === STARTER_FOLDER_NAME, ); - set({ starterProjectId: starterProjects!.id ?? "" }); + set({ starterProjectId: starterProjects?.id ?? "" }); set({ folders: foldersWithoutStarterProjects }); const myCollectionId = res?.find( @@ -72,7 +72,7 @@ export const useFolderStore = create((set, get) => ({ (folder) => folder.name === STARTER_FOLDER_NAME, ); - set({ starterProjectId: starterProjects!.id ?? "" }); + set({ starterProjectId: starterProjects?.id ?? "" }); set({ folders: foldersWithoutStarterProjects }); const myCollectionId = res?.find( diff --git a/src/frontend/src/types/contexts/auth.ts b/src/frontend/src/types/contexts/auth.ts index ba0998064..00550a69a 100644 --- a/src/frontend/src/types/contexts/auth.ts +++ b/src/frontend/src/types/contexts/auth.ts @@ -5,7 +5,7 @@ export type AuthContextType = { setIsAdmin: (isAdmin: boolean) => void; isAuthenticated: boolean; accessToken: string | null; - login: (accessToken: string) => void; + login: (accessToken: string, autoLogin: string) => void; logout: () => Promise; userData: Users | null; setUserData: (userData: Users | null) => void;