diff --git a/app/client/src/pages/UserAuth/VerifyUser.tsx b/app/client/src/pages/UserAuth/VerifyUser.tsx index 8800a8e60ee2..81e669c49d25 100644 --- a/app/client/src/pages/UserAuth/VerifyUser.tsx +++ b/app/client/src/pages/UserAuth/VerifyUser.tsx @@ -13,6 +13,7 @@ const VerifyUser = ( email: string; token: string; redirectUrl: string; + organizationId: string; }>, ) => { const queryParams = new URLSearchParams(props.location.search); diff --git a/app/client/src/sagas/InitSagas.ts b/app/client/src/sagas/InitSagas.ts index 3b3f635ec929..edf4e42df07a 100644 --- a/app/client/src/sagas/InitSagas.ts +++ b/app/client/src/sagas/InitSagas.ts @@ -92,6 +92,7 @@ import { import type { ApplicationPayload } from "entities/Application"; import type { Page } from "entities/Page"; import type { PACKAGE_PULL_STATUS } from "ee/constants/ModuleConstants"; +import { validateSessionToken } from "utils/SessionUtils"; export const URL_CHANGE_ACTIONS = [ ReduxActionTypes.CURRENT_APPLICATION_NAME_UPDATE, @@ -462,6 +463,15 @@ function* appEngineSaga(action: ReduxAction) { } function* eagerPageInitSaga() { + try { + // Validate session token if present + yield call(validateSessionToken); + } catch (error) { + // Log error but don't block the rest of the initialization + log.error("Error validating session token:", error); + Sentry.captureException(error); + } + const url = window.location.pathname; const search = window.location.search; diff --git a/app/client/src/utils/SessionUtils.ts b/app/client/src/utils/SessionUtils.ts new file mode 100644 index 000000000000..7855b68ea122 --- /dev/null +++ b/app/client/src/utils/SessionUtils.ts @@ -0,0 +1,42 @@ +import Api from "api/Api"; +import type { ApiResponse } from "api/types"; + +export const SESSION_TOKEN_PARAM = "sessionToken"; + +/** + * Validates a session token from the URL and sets up the session. + * This is used during cross-domain session transfers. + * + * @returns A promise that resolves to true if the session was validated successfully + */ +export const validateSessionToken = async (): Promise => { + try { + const urlParams = new URLSearchParams(window.location.search); + const sessionToken = urlParams.get("sessionToken"); + + if (!sessionToken) { + return false; + } + + // Get the response from the API + const response = (await Api.get( + `v1/session/validate?sessionToken=${sessionToken}`, + )) as unknown as ApiResponse; + + // Check if the request was successful + if (!response?.responseMeta?.success) { + return false; + } + + // Remove the session token from the URL + const url = new URL(window.location.href); + + url.searchParams.delete("sessionToken"); + window.history.replaceState({}, "", url.toString()); + + // The data field contains the boolean result directly + return !!response.data; + } catch (error) { + return false; + } +};