From fe7e2e6b9f4e73e33be1c389bdde231ecdb652a6 Mon Sep 17 00:00:00 2001 From: harshith-v-fyers Date: Thu, 9 Apr 2026 16:42:13 +0530 Subject: [PATCH 01/28] Support embedded WebView auth via cookie-based JWT and login suppression - proxyJwtStrategy: accept lc_access_token cookie as JWT fallback - AuthContext: detect embedded=true cookie, suppress /login redirects Made-with: Cursor --- api/strategies/proxyJwtStrategy.js | 5 ++++- client/src/hooks/AuthContext.tsx | 9 ++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/api/strategies/proxyJwtStrategy.js b/api/strategies/proxyJwtStrategy.js index d6dd2c408dec..546200de6348 100644 --- a/api/strategies/proxyJwtStrategy.js +++ b/api/strategies/proxyJwtStrategy.js @@ -17,7 +17,10 @@ const { getUserById, updateUser } = require('~/models'); const proxyJwtLogin = () => new JwtStrategy( { - jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), + jwtFromRequest: ExtractJwt.fromExtractors([ + ExtractJwt.fromAuthHeaderAsBearerToken(), + (req) => req?.cookies?.lc_access_token || null, + ]), secretOrKey: process.env.JWT_SECRET, passReqToCallback: false, }, diff --git a/client/src/hooks/AuthContext.tsx b/client/src/hooks/AuthContext.tsx index d9d583783a9e..851613d83694 100644 --- a/client/src/hooks/AuthContext.tsx +++ b/client/src/hooks/AuthContext.tsx @@ -47,6 +47,7 @@ const AuthContextProvider = ({ }); const navigate = useNavigate(); + const isEmbedded = useRef(document.cookie.includes('embedded=true')); const setUserContext = useMemo( () => @@ -143,7 +144,7 @@ const AuthContextProvider = ({ setUserContext({ token, isAuthenticated: true, user }); } else { console.log('Token is not present. User is not authenticated.'); - if (authConfig?.test === true) { + if (authConfig?.test === true || isEmbedded.current) { return; } navigate('/login'); @@ -151,7 +152,7 @@ const AuthContextProvider = ({ }, onError: (error) => { console.log('refreshToken mutation error:', error); - if (authConfig?.test === true) { + if (authConfig?.test === true || isEmbedded.current) { return; } navigate('/login'); @@ -164,7 +165,9 @@ const AuthContextProvider = ({ setUser(userQuery.data); } else if (userQuery.isError) { doSetError((userQuery.error as Error).message); - navigate('/login', { replace: true }); + if (!isEmbedded.current) { + navigate('/login', { replace: true }); + } } if (error != null && error && isAuthenticated) { doSetError(undefined); From ce3bd7755e18f912209b62b6106b40371444f53b Mon Sep 17 00:00:00 2001 From: harshith-v-fyers Date: Thu, 9 Apr 2026 17:36:28 +0530 Subject: [PATCH 02/28] Sync saas-api cookies to localStorage for improved authentication handling in embedded WebView. This change retrieves the access and refresh tokens from cookies and stores them in localStorage, enhancing session management. --- client/index.html | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/client/index.html b/client/index.html index c7063415fd11..c7ad197dd5b9 100644 --- a/client/index.html +++ b/client/index.html @@ -48,6 +48,18 @@ } `; document.head.appendChild(loadingContainerStyle); + + // Sync saas-api cookies to localStorage (set by /auth/embed flow) + (function() { + function getCookie(name) { + var m = document.cookie.match('(?:^|; )' + name + '=([^;]*)'); + return m ? decodeURIComponent(m[1]) : null; + } + var at = getCookie('saas_access_token'); + var rt = getCookie('saas_refresh_token'); + if (at) localStorage.setItem('access_token', at); + if (rt) localStorage.setItem('refresh_token', rt); + })(); From 7fcac2a083fec5dd0177f7c6e61af289d4441e19 Mon Sep 17 00:00:00 2001 From: harshith-v-fyers Date: Fri, 10 Apr 2026 16:09:14 +0530 Subject: [PATCH 03/28] Refactor Root component to conditionally render TopNavBar based on URL parameter. Updated initial state for navVisible to false for improved user experience. --- client/src/routes/Root.tsx | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/client/src/routes/Root.tsx b/client/src/routes/Root.tsx index da0da66996c2..bfba73e3e1c2 100644 --- a/client/src/routes/Root.tsx +++ b/client/src/routes/Root.tsx @@ -1,4 +1,4 @@ -import React, { useState, useEffect } from 'react'; +import React, { useState, useEffect, useMemo } from 'react'; import { Outlet, useLocation } from 'react-router-dom'; import type { ContextType } from '~/common'; import { @@ -28,11 +28,15 @@ export default function Root() { const [bannerHeight, setBannerHeight] = useState(0); const [navVisible, setNavVisible] = useState(() => { const savedNavVisible = localStorage.getItem('navVisible'); - return savedNavVisible !== null ? JSON.parse(savedNavVisible) : true; + return savedNavVisible !== null ? JSON.parse(savedNavVisible) : false; }); const { isAuthenticated, logout } = useAuthContext(); + const showTopNavBar = useMemo(() => { + return new URLSearchParams(location.search).get('showtopnav') === '1'; + }, [location.search]); + // Only show chat history sidebar on chat routes (FIA research), not on admin/templates/screener/resources const shouldShowNav = !location.pathname.startsWith('/admin') && !location.pathname.startsWith('/templates') && @@ -80,7 +84,7 @@ export default function Root() {
- + {showTopNavBar && } {/* Container with 12px horizontal padding and 16px gap (FYERS Design) */}
From c959a690cfb2fd646d9fe31eec6f99bd58f40210 Mon Sep 17 00:00:00 2001 From: harshith-v-fyers Date: Fri, 10 Apr 2026 17:02:00 +0530 Subject: [PATCH 04/28] Enhance user experience by updating navigation logic and improving state management. The Root component now conditionally renders the TopNavBar based on URL parameters, and the initial state for navVisible has been set to false. --- client/src/components/Chat/Header.tsx | 28 ++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/client/src/components/Chat/Header.tsx b/client/src/components/Chat/Header.tsx index cc3210755a0f..03e030d0bd16 100644 --- a/client/src/components/Chat/Header.tsx +++ b/client/src/components/Chat/Header.tsx @@ -1,13 +1,18 @@ +import { useState } from 'react'; import { useOutletContext } from 'react-router-dom'; import type { ContextType } from '~/common'; import { HeaderNewChat, OpenSidebar } from './Menus'; import { AnimatePresence, motion } from 'framer-motion'; import ModelSelector from '~/components/Chat/Menus/Endpoints/ModelSelector'; +import Settings from '~/components/Nav/Settings'; import { useGetStartupConfig } from '~/data-provider'; +import { useLocalize } from '~/hooks'; export default function Header() { const { navVisible, setNavVisible } = useOutletContext(); const { data: startupConfig } = useGetStartupConfig(); + const localize = useLocalize(); + const [showSettings, setShowSettings] = useState(false); return (
@@ -47,13 +52,30 @@ export default function Header() {
- {/* Right: Model Selector */} + {/* Right: model row + Settings inside same scale-75 block (gear sits beside model button) */}
-
- +
+
+ +
+
+ {showSettings && ( + + )}
); } From 51c6abd189544e683ff73665bc3a446858a78441 Mon Sep 17 00:00:00 2001 From: harshith-v-fyers Date: Mon, 13 Apr 2026 16:49:33 +0530 Subject: [PATCH 05/28] Implement theme management via URL parameters and localStorage - Added functionality to set the color theme based on URL query parameters, allowing users to switch between light and dark modes. - Integrated theme initialization in the App component, prioritizing environment variables and URL parameters for theme settings. - Introduced ThemeFromQueryParam component to manage theme state across routes, enhancing user experience with consistent theming. --- client/index.html | 12 ++++++++++ client/src/App.jsx | 16 +++++++++----- .../components/System/ThemeFromQueryParam.tsx | 22 +++++++++++++++++++ client/src/routes/index.tsx | 2 ++ client/src/utils/themeFromQuery.ts | 15 +++++++++++++ 5 files changed, 62 insertions(+), 5 deletions(-) create mode 100644 client/src/components/System/ThemeFromQueryParam.tsx create mode 100644 client/src/utils/themeFromQuery.ts diff --git a/client/index.html b/client/index.html index c7ad197dd5b9..7b789918756c 100644 --- a/client/index.html +++ b/client/index.html @@ -23,6 +23,18 @@ }