diff --git a/api/controllers/web/login.py b/api/controllers/web/login.py index 244ef47982..538d0c44be 100644 --- a/api/controllers/web/login.py +++ b/api/controllers/web/login.py @@ -81,6 +81,7 @@ class LoginStatusApi(Resource): ) def get(self): app_code = request.args.get("app_code") + user_id = request.args.get("user_id") token = extract_webapp_access_token(request) if not app_code: return { @@ -103,7 +104,7 @@ class LoginStatusApi(Resource): user_logged_in = False try: - _ = decode_jwt_token(app_code=app_code) + _ = decode_jwt_token(app_code=app_code, user_id=user_id) app_logged_in = True except Exception: app_logged_in = False diff --git a/api/controllers/web/wraps.py b/api/controllers/web/wraps.py index 9efd9f25d1..152137f39c 100644 --- a/api/controllers/web/wraps.py +++ b/api/controllers/web/wraps.py @@ -38,7 +38,7 @@ def validate_jwt_token(view: Callable[Concatenate[App, EndUser, P], R] | None = return decorator -def decode_jwt_token(app_code: str | None = None): +def decode_jwt_token(app_code: str | None = None, user_id: str | None = None): system_features = FeatureService.get_system_features() if not app_code: app_code = str(request.headers.get(HEADER_NAME_APP_CODE)) @@ -63,6 +63,10 @@ def decode_jwt_token(app_code: str | None = None): if not end_user: raise NotFound() + # Validate user_id against end_user's session_id if provided + if user_id is not None and end_user.session_id != user_id: + raise Unauthorized("Authentication has expired.") + # for enterprise webapp auth app_web_auth_enabled = False webapp_settings = None diff --git a/web/app/(shareLayout)/components/splash.tsx b/web/app/(shareLayout)/components/splash.tsx index eb9538e49b..9315e79d20 100644 --- a/web/app/(shareLayout)/components/splash.tsx +++ b/web/app/(shareLayout)/components/splash.tsx @@ -58,7 +58,7 @@ const Splash: FC = ({ children }) => { (async () => { // if access mode is public, user login is always true, but the app login(passport) may be expired - const { userLoggedIn, appLoggedIn } = await webAppLoginStatus(shareCode!) + const { userLoggedIn, appLoggedIn } = await webAppLoginStatus(shareCode!, embeddedUserId || undefined) if (userLoggedIn && appLoggedIn) { redirectOrFinish() } diff --git a/web/service/webapp-auth.ts b/web/service/webapp-auth.ts index e7e3f86406..7a9abd9599 100644 --- a/web/service/webapp-auth.ts +++ b/web/service/webapp-auth.ts @@ -30,10 +30,13 @@ type isWebAppLogin = { app_logged_in: boolean } -export async function webAppLoginStatus(shareCode: string) { +export async function webAppLoginStatus(shareCode: string, userId?: string) { // always need to check login to prevent passport from being outdated // check remotely, the access token could be in cookie (enterprise SSO redirected with https) - const { logged_in, app_logged_in } = await getPublic(`/login/status?app_code=${shareCode}`) + const params = new URLSearchParams({ app_code: shareCode }) + if (userId) + params.append('user_id', userId) + const { logged_in, app_logged_in } = await getPublic(`/login/status?${params.toString()}`) return { userLoggedIn: logged_in, appLoggedIn: app_logged_in,