@iblai/web-utils 1.9.1 → 1.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -112,6 +112,7 @@ interface RedirectToAuthSpaOptions {
112
112
  /** Function to check if the app is running as a native app (e.g., Tauri). Affects redirect behavior. */
113
113
  isNativeApp?: () => boolean;
114
114
  forceRedirect?: boolean;
115
+ scheme?: string;
115
116
  }
116
117
  /**
117
118
  * Redirect to authentication SPA for login/logout
@@ -181,7 +181,7 @@ async function redirectToAuthSpa(options) {
181
181
  logoutTimestamp: "ibl_logout_timestamp",
182
182
  loginTimestamp: "ibl_login_timestamp",
183
183
  tenantSwitching: "ibl_tenant_switching",
184
- }, hasNonExpiredAuthToken, isOffline, preserveTokenKey, authRedirectProxy, isNativeApp, forceRedirect = false, } = options;
184
+ }, hasNonExpiredAuthToken, isOffline, preserveTokenKey, authRedirectProxy, isNativeApp, scheme = "iblai-mentor://", forceRedirect = false, } = options;
185
185
  console.log("[redirectToAuthSpa] starting redirect to auth spa", redirectTo, platformKey, logout, saveRedirect, forceRedirect);
186
186
  // Skip if a tenant switch is already in progress
187
187
  if (!forceRedirect &&
@@ -256,7 +256,7 @@ async function redirectToAuthSpa(options) {
256
256
  window.localStorage.setItem(redirectPathStorageKey, redirectPath);
257
257
  }
258
258
  const platform = platformKey !== null && platformKey !== void 0 ? platformKey : getPlatformKey(redirectPath);
259
- const redirectToUrl = `${window.location.origin}`;
259
+ const redirectToUrl = (isNativeApp === null || isNativeApp === void 0 ? void 0 : isNativeApp()) ? scheme : `${window.location.origin}`;
260
260
  let authRedirectUrl = `${authUrl}/login?${queryParams.app}=${appName}`;
261
261
  authRedirectUrl += `&${queryParams.redirectTo}=${redirectToUrl}`;
262
262
  if (platform) {
@@ -1 +1 @@
1
- {"version":3,"file":"index.esm.js","sources":["../../src/utils/auth.ts"],"sourcesContent":["/**\n * Authentication and Authorization Utilities\n *\n * This module provides utility functions for handling authentication flows,\n * including redirects to auth SPA, cookie management, and session handling.\n */\n\n/**\n * Check if the current window is inside an iframe\n * @returns {boolean} True if running in an iframe, false otherwise\n */\nexport function isInIframe(): boolean {\n if (typeof window === \"undefined\") {\n return false;\n }\n return window?.self !== window?.top;\n}\n\n/**\n * Send a message to the parent website (when in iframe)\n * @param payload - The data to send to parent window\n */\nexport function sendMessageToParentWebsite(payload: unknown): void {\n window.parent.postMessage(payload, \"*\");\n}\n\n/**\n * Delete a cookie with specific name, path, and domain\n * @param name - Cookie name\n * @param path - Cookie path\n * @param domain - Cookie domain\n */\nexport function deleteCookie(name: string, path: string, domain: string): void {\n const expires = \"expires=Thu, 01 Jan 1970 00:00:00 UTC;\";\n const cookieValue = `${name}=;`;\n const pathValue = path ? `path=${path};` : \"\";\n const domainValue = domain ? `domain=${domain};` : \"\";\n document.cookie = cookieValue + expires + pathValue + domainValue;\n}\n\n/**\n * Get all possible domain parts for cookie deletion\n * @param domain - The domain to split\n * @returns Array of domain parts\n * @example\n * getDomainParts('app.example.com') // returns ['app.example.com', 'example.com', 'com']\n */\nexport function getDomainParts(domain: string): string[] {\n const parts = domain.split(\".\");\n const domains: string[] = [];\n for (let i = parts.length - 1; i >= 0; i--) {\n domains.push(parts.slice(i).join(\".\"));\n }\n return domains;\n}\n\n/**\n * Delete a cookie across all possible domain variations\n * @param name - Cookie name to delete\n * @param childDomain - The current domain\n */\nexport function deleteCookieOnAllDomains(\n name: string,\n childDomain: string,\n): void {\n getDomainParts(childDomain).forEach((domainPart) => {\n deleteCookie(name, \"/\", domainPart);\n deleteCookie(name, \"\", domainPart);\n });\n}\n\n/**\n * Get the parent domain from a given domain\n * @param domain - The domain to process\n * @returns The parent domain (e.g., 'app.example.com' → '.example.com')\n */\nexport function getParentDomain(domain?: string): string {\n if (!domain) {\n return \"\";\n }\n const parts = domain.split(\".\");\n return parts.length > 1 ? `.${parts.slice(-2).join(\".\")}` : domain;\n}\n\n/**\n * Set a cookie for authentication with cross-domain support\n * @param name - Cookie name\n * @param value - Cookie value\n * @param days - Number of days until expiration (default: 365)\n */\nexport function setCookieForAuth(\n name: string,\n value: string,\n days: number = 365,\n): void {\n const expires = new Date();\n expires.setTime(expires.getTime() + days * 24 * 60 * 60 * 1000);\n\n const hostname = window.location.hostname;\n let baseDomain = hostname;\n\n // Calculate base domain (skip for localhost and IP addresses)\n if (hostname !== \"localhost\" && !/^\\d+\\.\\d+\\.\\d+\\.\\d+$/.test(hostname)) {\n const parts = hostname.split(\".\");\n if (parts.length > 2) {\n baseDomain = `.${parts.slice(-2).join(\".\")}`;\n }\n }\n\n const domainAttr = baseDomain ? `;domain=${baseDomain}` : \"\";\n document.cookie = `${name}=${encodeURIComponent(value)};expires=${expires.toUTCString()};path=/;SameSite=None;Secure${domainAttr}`;\n}\n\n/**\n * Clear all cookies for the current domain\n */\nexport function clearCookies(): void {\n const cookies = document.cookie.split(\";\");\n for (let i = 0; i < cookies.length; i++) {\n const cookie = cookies[i];\n const eqPos = cookie.indexOf(\"=\");\n const name = eqPos > -1 ? cookie.substr(0, eqPos) : cookie;\n deleteCookieOnAllDomains(name, window.location.hostname);\n document.cookie = `${name}=;expires=Thu, 01 Jan 1970 00:00:00 GMT;path=/;Domain=${getParentDomain(\n window.location.hostname,\n )}`;\n }\n}\n\n/**\n * Get the value of a cookie by name\n * @param name - Cookie name\n * @returns The cookie value or null if not found\n */\nexport function getCookieValue(name: string): string | null {\n const match = document.cookie.match(new RegExp(`(?:^|;\\\\s*)${name}=([^;]*)`));\n return match ? decodeURIComponent(match[1]) : null;\n}\n\n/**\n * Check if user is currently logged in\n * @param tokenKey - The localStorage key for the auth token (default: 'axd_token')\n * @returns True if logged in, false otherwise\n */\nexport function isLoggedIn(tokenKey: string = \"axd_token\"): boolean {\n return !!localStorage.getItem(tokenKey);\n}\n\n/**\n * Extract platform/tenant key from URL\n * @param url - The URL to parse\n * @param pattern - RegExp pattern to match platform key (default matches /platform/[key]/...)\n * @returns The platform key or null if not found\n */\nexport function getPlatformKey(\n url: string,\n pattern: RegExp = /\\/platform\\/([^/]+)/,\n): string | null {\n const match = url.match(pattern);\n return match ? match[1] : null;\n}\n\nexport interface RedirectToAuthSpaOptions {\n /** URL to redirect to after auth (defaults to current path + search) */\n redirectTo?: string;\n /** Platform/tenant key */\n platformKey?: string;\n /** Whether this is a logout action */\n logout?: boolean;\n /** Whether to save redirect path to localStorage (default: true) */\n saveRedirect?: boolean;\n /** Auth SPA base URL */\n authUrl: string;\n /** Current app/platform identifier (e.g., 'mentor', 'skills') */\n appName: string;\n /** Query param names */\n queryParams?: {\n app?: string;\n redirectTo?: string;\n tenant?: string;\n };\n /** localStorage key for saving redirect path */\n redirectPathStorageKey?: string;\n /** Cookie names for cross-SPA sync */\n cookieNames?: {\n currentTenant?: string;\n userData?: string;\n tenant?: string;\n logoutTimestamp?: string;\n loginTimestamp?: string;\n tenantSwitching?: string;\n };\n /** Function to check if auth token is valid and non-expired. Used to skip redirect when a recent login occurred. */\n hasNonExpiredAuthToken?: () => boolean;\n /** Function to check if the app is in offline mode (e.g., Tauri offline). Skips redirect when true. */\n isOffline?: () => boolean;\n /** localStorage key for a token to preserve before clearing storage (e.g., 'edx_jwt_token') */\n preserveTokenKey?: string;\n /** Path to an auth redirect proxy endpoint (e.g., '/api/auth-redirect'). When set, redirects via this proxy in browser. */\n authRedirectProxy?: string;\n /** Function to check if the app is running as a native app (e.g., Tauri). Affects redirect behavior. */\n isNativeApp?: () => boolean;\n forceRedirect?: boolean;\n}\n\n/**\n * Redirect to authentication SPA for login/logout\n *\n * This function handles the complete authentication flow:\n * - Clears localStorage and cookies on logout\n * - Saves redirect path for post-auth return\n * - Handles iframe scenarios\n * - Syncs logout across multiple SPAs via cookies\n *\n * @param options - Configuration options for the redirect\n *\n * @example\n * ```tsx\n * // Basic usage\n * redirectToAuthSpa({\n * authUrl: 'https://auth.example.com',\n * appName: 'mentor',\n * });\n *\n * // With logout\n * redirectToAuthSpa({\n * authUrl: 'https://auth.example.com',\n * appName: 'mentor',\n * logout: true,\n * platformKey: 'my-tenant',\n * });\n *\n * // With custom redirect\n * redirectToAuthSpa({\n * authUrl: 'https://auth.example.com',\n * appName: 'mentor',\n * redirectTo: '/dashboard',\n * platformKey: 'my-tenant',\n * });\n * ```\n */\nexport async function redirectToAuthSpa(\n options: RedirectToAuthSpaOptions,\n): Promise<void> {\n const {\n redirectTo,\n platformKey,\n logout = false,\n saveRedirect = true,\n authUrl,\n appName,\n queryParams = {\n app: \"app\",\n redirectTo: \"redirect-to\",\n tenant: \"tenant\",\n },\n redirectPathStorageKey = \"redirect_to\",\n cookieNames = {\n currentTenant: \"ibl_current_tenant\",\n userData: \"ibl_user_data\",\n tenant: \"ibl_tenant\",\n logoutTimestamp: \"ibl_logout_timestamp\",\n loginTimestamp: \"ibl_login_timestamp\",\n tenantSwitching: \"ibl_tenant_switching\",\n },\n hasNonExpiredAuthToken,\n isOffline,\n preserveTokenKey,\n authRedirectProxy,\n isNativeApp,\n forceRedirect = false,\n } = options;\n\n console.log(\n \"[redirectToAuthSpa] starting redirect to auth spa\",\n redirectTo,\n platformKey,\n logout,\n saveRedirect,\n forceRedirect,\n );\n\n // Skip if a tenant switch is already in progress\n if (\n !forceRedirect &&\n cookieNames.tenantSwitching &&\n document.cookie.includes(cookieNames.tenantSwitching)\n ) {\n console.log(\n \"[redirectToAuthSpa] Tenant switch in progress, skipping redirect\",\n );\n return;\n }\n\n // Skip if a login occurred after the last logout (login takes precedence)\n // but only if this app actually has a valid auth token\n if (\n !forceRedirect &&\n hasNonExpiredAuthToken &&\n cookieNames.loginTimestamp &&\n cookieNames.logoutTimestamp\n ) {\n const loginTs = getCookieValue(cookieNames.loginTimestamp);\n const logoutTs = getCookieValue(cookieNames.logoutTimestamp);\n const hasValidToken = hasNonExpiredAuthToken();\n console.log(\"[redirectToAuthSpa] Login/logout timestamp check\", {\n loginTs,\n logoutTs,\n hasValidToken,\n loginAhead:\n loginTs && logoutTs ? Number(loginTs) > Number(logoutTs) : false,\n });\n if (\n !forceRedirect &&\n hasValidToken &&\n loginTs &&\n logoutTs &&\n Number(loginTs) > Number(logoutTs)\n ) {\n console.log(\n \"[redirectToAuthSpa] Login timestamp is ahead of logout timestamp, skipping redirect\",\n { loginTs, logoutTs },\n );\n return;\n }\n }\n\n // Skip redirect in offline mode\n if (isOffline?.()) {\n console.log(\"[redirectToAuthSpa] Skipping redirect - offline mode\");\n return;\n }\n\n // Preserve a token before clearing localStorage if requested\n const preservedToken = preserveTokenKey\n ? window.localStorage.getItem(preserveTokenKey)\n : null;\n\n console.log(\"[redirectToAuthSpa] clearing local storage\");\n localStorage.clear();\n\n if (logout || isInIframe()) {\n // Delete authentication cookies for cross-SPA synchronization\n const currentDomain = window.location.hostname;\n if (cookieNames.currentTenant) {\n deleteCookieOnAllDomains(cookieNames.currentTenant, currentDomain);\n }\n if (cookieNames.userData) {\n deleteCookieOnAllDomains(cookieNames.userData, currentDomain);\n }\n if (cookieNames.tenant) {\n deleteCookieOnAllDomains(cookieNames.tenant, currentDomain);\n }\n\n // Set logout timestamp cookie to trigger logout on other SPAs\n if (cookieNames.logoutTimestamp && !isInIframe()) {\n setCookieForAuth(cookieNames.logoutTimestamp, Date.now().toString());\n }\n }\n\n // Handle iframe scenario\n if (isInIframe()) {\n console.log(\"[redirectToAuthSpa]: sending authExpired to parent\");\n sendMessageToParentWebsite({ authExpired: true });\n return;\n }\n\n const redirectPath =\n redirectTo ?? `${window.location.pathname}${window.location.search}`;\n\n // Never save sso-login routes as redirect paths\n if (\n !redirectPath.startsWith(\"/sso-login\") &&\n !redirectPath.startsWith(\"/sso-login-complete\") &&\n saveRedirect\n ) {\n window.localStorage.setItem(redirectPathStorageKey, redirectPath);\n }\n\n const platform = platformKey ?? getPlatformKey(redirectPath);\n\n const redirectToUrl = `${window.location.origin}`;\n\n let authRedirectUrl = `${authUrl}/login?${queryParams.app}=${appName}`;\n\n authRedirectUrl += `&${queryParams.redirectTo}=${redirectToUrl}`;\n\n if (platform) {\n authRedirectUrl += `&${queryParams.tenant}=${platform}`;\n }\n if (logout) {\n authRedirectUrl += \"&logout=1\";\n }\n\n // Small delay for any pending operations\n await new Promise((resolve) => setTimeout(resolve, 100));\n\n if (isNativeApp?.()) {\n // On native apps (e.g., Tauri), pass preserved token and navigate directly\n if (preservedToken && preserveTokenKey) {\n authRedirectUrl += `&token=${encodeURIComponent(preservedToken)}`;\n console.log(\"[redirectToAuthSpa] Added preserved token to auth URL\");\n }\n console.log(\n \"[redirectToAuthSpa] Native app, navigating to auth URL:\",\n authRedirectUrl,\n );\n window.location.href = authRedirectUrl;\n } else if (authRedirectProxy) {\n // Use auth redirect proxy endpoint\n window.location.href = `${authRedirectProxy}?to=${encodeURIComponent(authRedirectUrl)}`;\n } else {\n window.location.href = authRedirectUrl;\n }\n}\n\n/**\n * Get the URL for joining a tenant (sign up flow)\n * @param authUrl - Auth SPA base URL\n * @param tenantKey - Tenant to join\n * @param redirectUrl - URL to redirect to after joining (defaults to current URL)\n * @returns The join URL\n */\nexport function getAuthSpaJoinUrl(\n authUrl: string,\n tenantKey?: string,\n redirectUrl?: string,\n): string {\n const resolvedTenant =\n tenantKey || getPlatformKey(window.location.pathname) || \"\";\n\n if (!resolvedTenant) {\n return \"\";\n }\n\n const targetUrl = redirectUrl ?? window.location.href;\n const joinUrl = `${authUrl}/join?tenant=${encodeURIComponent(resolvedTenant)}&redirect-to=${encodeURIComponent(\n targetUrl,\n )}`;\n return joinUrl;\n}\n\n/**\n * Redirect to auth SPA's join/signup page for a specific tenant\n * @param authUrl - Auth SPA base URL\n * @param tenantKey - Tenant to join\n * @param redirectUrl - URL to redirect to after joining (defaults to current URL)\n */\nexport function redirectToAuthSpaJoinTenant(\n authUrl: string,\n tenantKey?: string,\n redirectUrl?: string,\n): void {\n const resolvedTenant =\n tenantKey || getPlatformKey(window.location.pathname) || \"\";\n\n if (!resolvedTenant) {\n console.log(\"[auth-redirect] Missing tenant key for join\", {\n tenantKey,\n redirectUrl,\n });\n redirectToAuthSpa({\n authUrl,\n appName: \"app\", // Will need to be configured\n redirectTo: redirectUrl,\n });\n return;\n }\n\n const targetUrl = redirectUrl ?? window.location.href;\n const joinUrl = `${authUrl}/join?tenant=${encodeURIComponent(resolvedTenant)}&redirect-to=${encodeURIComponent(\n targetUrl,\n )}`;\n\n window.location.href = joinUrl;\n}\n\nexport interface HandleLogoutOptions {\n /** URL to redirect to after logout (defaults to current origin) */\n redirectUrl?: string;\n /** Auth SPA base URL */\n authUrl: string;\n /** localStorage key for tenant */\n tenantStorageKey?: string;\n /** Cookie name for logout timestamp */\n logoutTimestampCookie?: string;\n /** Callback to execute before logout */\n callback?: () => void;\n}\n\n/**\n * Handle user logout\n *\n * This function:\n * - Clears localStorage (preserving tenant)\n * - Sets logout timestamp cookie for cross-SPA sync\n * - Clears all cookies\n * - Redirects to auth SPA logout endpoint\n *\n * @param options - Logout configuration options\n *\n * @example\n * ```tsx\n * handleLogout({\n * authUrl: 'https://auth.example.com',\n * redirectUrl: 'https://app.example.com',\n * });\n * ```\n */\nexport function handleLogout(options: HandleLogoutOptions): void {\n const {\n redirectUrl = window.location.origin,\n authUrl,\n tenantStorageKey = \"tenant\",\n logoutTimestampCookie = \"ibl_logout_timestamp\",\n callback,\n } = options;\n\n const tenant = window.localStorage.getItem(tenantStorageKey);\n window.localStorage.clear();\n if (tenant) {\n window.localStorage.setItem(tenantStorageKey, tenant);\n }\n\n // Set logout timestamp cookie to trigger logout on other SPAs\n setCookieForAuth(logoutTimestampCookie, Date.now().toString());\n\n clearCookies();\n callback?.();\n\n if (!isInIframe()) {\n window.location.href = `${authUrl}/logout?redirect-to=${redirectUrl}${tenant ? \"&tenant=\" + tenant : \"\"}`;\n }\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.esm.js","sources":["../../src/utils/auth.ts"],"sourcesContent":["/**\n * Authentication and Authorization Utilities\n *\n * This module provides utility functions for handling authentication flows,\n * including redirects to auth SPA, cookie management, and session handling.\n */\n\n/**\n * Check if the current window is inside an iframe\n * @returns {boolean} True if running in an iframe, false otherwise\n */\nexport function isInIframe(): boolean {\n if (typeof window === \"undefined\") {\n return false;\n }\n return window?.self !== window?.top;\n}\n\n/**\n * Send a message to the parent website (when in iframe)\n * @param payload - The data to send to parent window\n */\nexport function sendMessageToParentWebsite(payload: unknown): void {\n window.parent.postMessage(payload, \"*\");\n}\n\n/**\n * Delete a cookie with specific name, path, and domain\n * @param name - Cookie name\n * @param path - Cookie path\n * @param domain - Cookie domain\n */\nexport function deleteCookie(name: string, path: string, domain: string): void {\n const expires = \"expires=Thu, 01 Jan 1970 00:00:00 UTC;\";\n const cookieValue = `${name}=;`;\n const pathValue = path ? `path=${path};` : \"\";\n const domainValue = domain ? `domain=${domain};` : \"\";\n document.cookie = cookieValue + expires + pathValue + domainValue;\n}\n\n/**\n * Get all possible domain parts for cookie deletion\n * @param domain - The domain to split\n * @returns Array of domain parts\n * @example\n * getDomainParts('app.example.com') // returns ['app.example.com', 'example.com', 'com']\n */\nexport function getDomainParts(domain: string): string[] {\n const parts = domain.split(\".\");\n const domains: string[] = [];\n for (let i = parts.length - 1; i >= 0; i--) {\n domains.push(parts.slice(i).join(\".\"));\n }\n return domains;\n}\n\n/**\n * Delete a cookie across all possible domain variations\n * @param name - Cookie name to delete\n * @param childDomain - The current domain\n */\nexport function deleteCookieOnAllDomains(\n name: string,\n childDomain: string,\n): void {\n getDomainParts(childDomain).forEach((domainPart) => {\n deleteCookie(name, \"/\", domainPart);\n deleteCookie(name, \"\", domainPart);\n });\n}\n\n/**\n * Get the parent domain from a given domain\n * @param domain - The domain to process\n * @returns The parent domain (e.g., 'app.example.com' → '.example.com')\n */\nexport function getParentDomain(domain?: string): string {\n if (!domain) {\n return \"\";\n }\n const parts = domain.split(\".\");\n return parts.length > 1 ? `.${parts.slice(-2).join(\".\")}` : domain;\n}\n\n/**\n * Set a cookie for authentication with cross-domain support\n * @param name - Cookie name\n * @param value - Cookie value\n * @param days - Number of days until expiration (default: 365)\n */\nexport function setCookieForAuth(\n name: string,\n value: string,\n days: number = 365,\n): void {\n const expires = new Date();\n expires.setTime(expires.getTime() + days * 24 * 60 * 60 * 1000);\n\n const hostname = window.location.hostname;\n let baseDomain = hostname;\n\n // Calculate base domain (skip for localhost and IP addresses)\n if (hostname !== \"localhost\" && !/^\\d+\\.\\d+\\.\\d+\\.\\d+$/.test(hostname)) {\n const parts = hostname.split(\".\");\n if (parts.length > 2) {\n baseDomain = `.${parts.slice(-2).join(\".\")}`;\n }\n }\n\n const domainAttr = baseDomain ? `;domain=${baseDomain}` : \"\";\n document.cookie = `${name}=${encodeURIComponent(value)};expires=${expires.toUTCString()};path=/;SameSite=None;Secure${domainAttr}`;\n}\n\n/**\n * Clear all cookies for the current domain\n */\nexport function clearCookies(): void {\n const cookies = document.cookie.split(\";\");\n for (let i = 0; i < cookies.length; i++) {\n const cookie = cookies[i];\n const eqPos = cookie.indexOf(\"=\");\n const name = eqPos > -1 ? cookie.substr(0, eqPos) : cookie;\n deleteCookieOnAllDomains(name, window.location.hostname);\n document.cookie = `${name}=;expires=Thu, 01 Jan 1970 00:00:00 GMT;path=/;Domain=${getParentDomain(\n window.location.hostname,\n )}`;\n }\n}\n\n/**\n * Get the value of a cookie by name\n * @param name - Cookie name\n * @returns The cookie value or null if not found\n */\nexport function getCookieValue(name: string): string | null {\n const match = document.cookie.match(new RegExp(`(?:^|;\\\\s*)${name}=([^;]*)`));\n return match ? decodeURIComponent(match[1]) : null;\n}\n\n/**\n * Check if user is currently logged in\n * @param tokenKey - The localStorage key for the auth token (default: 'axd_token')\n * @returns True if logged in, false otherwise\n */\nexport function isLoggedIn(tokenKey: string = \"axd_token\"): boolean {\n return !!localStorage.getItem(tokenKey);\n}\n\n/**\n * Extract platform/tenant key from URL\n * @param url - The URL to parse\n * @param pattern - RegExp pattern to match platform key (default matches /platform/[key]/...)\n * @returns The platform key or null if not found\n */\nexport function getPlatformKey(\n url: string,\n pattern: RegExp = /\\/platform\\/([^/]+)/,\n): string | null {\n const match = url.match(pattern);\n return match ? match[1] : null;\n}\n\nexport interface RedirectToAuthSpaOptions {\n /** URL to redirect to after auth (defaults to current path + search) */\n redirectTo?: string;\n /** Platform/tenant key */\n platformKey?: string;\n /** Whether this is a logout action */\n logout?: boolean;\n /** Whether to save redirect path to localStorage (default: true) */\n saveRedirect?: boolean;\n /** Auth SPA base URL */\n authUrl: string;\n /** Current app/platform identifier (e.g., 'mentor', 'skills') */\n appName: string;\n /** Query param names */\n queryParams?: {\n app?: string;\n redirectTo?: string;\n tenant?: string;\n };\n /** localStorage key for saving redirect path */\n redirectPathStorageKey?: string;\n /** Cookie names for cross-SPA sync */\n cookieNames?: {\n currentTenant?: string;\n userData?: string;\n tenant?: string;\n logoutTimestamp?: string;\n loginTimestamp?: string;\n tenantSwitching?: string;\n };\n /** Function to check if auth token is valid and non-expired. Used to skip redirect when a recent login occurred. */\n hasNonExpiredAuthToken?: () => boolean;\n /** Function to check if the app is in offline mode (e.g., Tauri offline). Skips redirect when true. */\n isOffline?: () => boolean;\n /** localStorage key for a token to preserve before clearing storage (e.g., 'edx_jwt_token') */\n preserveTokenKey?: string;\n /** Path to an auth redirect proxy endpoint (e.g., '/api/auth-redirect'). When set, redirects via this proxy in browser. */\n authRedirectProxy?: string;\n /** Function to check if the app is running as a native app (e.g., Tauri). Affects redirect behavior. */\n isNativeApp?: () => boolean;\n forceRedirect?: boolean;\n scheme?: string;\n}\n\n/**\n * Redirect to authentication SPA for login/logout\n *\n * This function handles the complete authentication flow:\n * - Clears localStorage and cookies on logout\n * - Saves redirect path for post-auth return\n * - Handles iframe scenarios\n * - Syncs logout across multiple SPAs via cookies\n *\n * @param options - Configuration options for the redirect\n *\n * @example\n * ```tsx\n * // Basic usage\n * redirectToAuthSpa({\n * authUrl: 'https://auth.example.com',\n * appName: 'mentor',\n * });\n *\n * // With logout\n * redirectToAuthSpa({\n * authUrl: 'https://auth.example.com',\n * appName: 'mentor',\n * logout: true,\n * platformKey: 'my-tenant',\n * });\n *\n * // With custom redirect\n * redirectToAuthSpa({\n * authUrl: 'https://auth.example.com',\n * appName: 'mentor',\n * redirectTo: '/dashboard',\n * platformKey: 'my-tenant',\n * });\n * ```\n */\nexport async function redirectToAuthSpa(\n options: RedirectToAuthSpaOptions,\n): Promise<void> {\n const {\n redirectTo,\n platformKey,\n logout = false,\n saveRedirect = true,\n authUrl,\n appName,\n queryParams = {\n app: \"app\",\n redirectTo: \"redirect-to\",\n tenant: \"tenant\",\n },\n redirectPathStorageKey = \"redirect_to\",\n cookieNames = {\n currentTenant: \"ibl_current_tenant\",\n userData: \"ibl_user_data\",\n tenant: \"ibl_tenant\",\n logoutTimestamp: \"ibl_logout_timestamp\",\n loginTimestamp: \"ibl_login_timestamp\",\n tenantSwitching: \"ibl_tenant_switching\",\n },\n hasNonExpiredAuthToken,\n isOffline,\n preserveTokenKey,\n authRedirectProxy,\n isNativeApp,\n scheme = \"iblai-mentor://\",\n forceRedirect = false,\n } = options;\n\n console.log(\n \"[redirectToAuthSpa] starting redirect to auth spa\",\n redirectTo,\n platformKey,\n logout,\n saveRedirect,\n forceRedirect,\n );\n\n // Skip if a tenant switch is already in progress\n if (\n !forceRedirect &&\n cookieNames.tenantSwitching &&\n document.cookie.includes(cookieNames.tenantSwitching)\n ) {\n console.log(\n \"[redirectToAuthSpa] Tenant switch in progress, skipping redirect\",\n );\n return;\n }\n\n // Skip if a login occurred after the last logout (login takes precedence)\n // but only if this app actually has a valid auth token\n if (\n !forceRedirect &&\n hasNonExpiredAuthToken &&\n cookieNames.loginTimestamp &&\n cookieNames.logoutTimestamp\n ) {\n const loginTs = getCookieValue(cookieNames.loginTimestamp);\n const logoutTs = getCookieValue(cookieNames.logoutTimestamp);\n const hasValidToken = hasNonExpiredAuthToken();\n console.log(\"[redirectToAuthSpa] Login/logout timestamp check\", {\n loginTs,\n logoutTs,\n hasValidToken,\n loginAhead:\n loginTs && logoutTs ? Number(loginTs) > Number(logoutTs) : false,\n });\n if (\n !forceRedirect &&\n hasValidToken &&\n loginTs &&\n logoutTs &&\n Number(loginTs) > Number(logoutTs)\n ) {\n console.log(\n \"[redirectToAuthSpa] Login timestamp is ahead of logout timestamp, skipping redirect\",\n { loginTs, logoutTs },\n );\n return;\n }\n }\n\n // Skip redirect in offline mode\n if (isOffline?.()) {\n console.log(\"[redirectToAuthSpa] Skipping redirect - offline mode\");\n return;\n }\n\n // Preserve a token before clearing localStorage if requested\n const preservedToken = preserveTokenKey\n ? window.localStorage.getItem(preserveTokenKey)\n : null;\n\n console.log(\"[redirectToAuthSpa] clearing local storage\");\n localStorage.clear();\n\n if (logout || isInIframe()) {\n // Delete authentication cookies for cross-SPA synchronization\n const currentDomain = window.location.hostname;\n if (cookieNames.currentTenant) {\n deleteCookieOnAllDomains(cookieNames.currentTenant, currentDomain);\n }\n if (cookieNames.userData) {\n deleteCookieOnAllDomains(cookieNames.userData, currentDomain);\n }\n if (cookieNames.tenant) {\n deleteCookieOnAllDomains(cookieNames.tenant, currentDomain);\n }\n\n // Set logout timestamp cookie to trigger logout on other SPAs\n if (cookieNames.logoutTimestamp && !isInIframe()) {\n setCookieForAuth(cookieNames.logoutTimestamp, Date.now().toString());\n }\n }\n\n // Handle iframe scenario\n if (isInIframe()) {\n console.log(\"[redirectToAuthSpa]: sending authExpired to parent\");\n sendMessageToParentWebsite({ authExpired: true });\n return;\n }\n\n const redirectPath =\n redirectTo ?? `${window.location.pathname}${window.location.search}`;\n\n // Never save sso-login routes as redirect paths\n if (\n !redirectPath.startsWith(\"/sso-login\") &&\n !redirectPath.startsWith(\"/sso-login-complete\") &&\n saveRedirect\n ) {\n window.localStorage.setItem(redirectPathStorageKey, redirectPath);\n }\n\n const platform = platformKey ?? getPlatformKey(redirectPath);\n\n const redirectToUrl = isNativeApp?.() ? scheme : `${window.location.origin}`;\n\n let authRedirectUrl = `${authUrl}/login?${queryParams.app}=${appName}`;\n\n authRedirectUrl += `&${queryParams.redirectTo}=${redirectToUrl}`;\n\n if (platform) {\n authRedirectUrl += `&${queryParams.tenant}=${platform}`;\n }\n if (logout) {\n authRedirectUrl += \"&logout=1\";\n }\n\n // Small delay for any pending operations\n await new Promise((resolve) => setTimeout(resolve, 100));\n\n if (isNativeApp?.()) {\n // On native apps (e.g., Tauri), pass preserved token and navigate directly\n if (preservedToken && preserveTokenKey) {\n authRedirectUrl += `&token=${encodeURIComponent(preservedToken)}`;\n console.log(\"[redirectToAuthSpa] Added preserved token to auth URL\");\n }\n console.log(\n \"[redirectToAuthSpa] Native app, navigating to auth URL:\",\n authRedirectUrl,\n );\n window.location.href = authRedirectUrl;\n } else if (authRedirectProxy) {\n // Use auth redirect proxy endpoint\n window.location.href = `${authRedirectProxy}?to=${encodeURIComponent(authRedirectUrl)}`;\n } else {\n window.location.href = authRedirectUrl;\n }\n}\n\n/**\n * Get the URL for joining a tenant (sign up flow)\n * @param authUrl - Auth SPA base URL\n * @param tenantKey - Tenant to join\n * @param redirectUrl - URL to redirect to after joining (defaults to current URL)\n * @returns The join URL\n */\nexport function getAuthSpaJoinUrl(\n authUrl: string,\n tenantKey?: string,\n redirectUrl?: string,\n): string {\n const resolvedTenant =\n tenantKey || getPlatformKey(window.location.pathname) || \"\";\n\n if (!resolvedTenant) {\n return \"\";\n }\n\n const targetUrl = redirectUrl ?? window.location.href;\n const joinUrl = `${authUrl}/join?tenant=${encodeURIComponent(resolvedTenant)}&redirect-to=${encodeURIComponent(\n targetUrl,\n )}`;\n return joinUrl;\n}\n\n/**\n * Redirect to auth SPA's join/signup page for a specific tenant\n * @param authUrl - Auth SPA base URL\n * @param tenantKey - Tenant to join\n * @param redirectUrl - URL to redirect to after joining (defaults to current URL)\n */\nexport function redirectToAuthSpaJoinTenant(\n authUrl: string,\n tenantKey?: string,\n redirectUrl?: string,\n): void {\n const resolvedTenant =\n tenantKey || getPlatformKey(window.location.pathname) || \"\";\n\n if (!resolvedTenant) {\n console.log(\"[auth-redirect] Missing tenant key for join\", {\n tenantKey,\n redirectUrl,\n });\n redirectToAuthSpa({\n authUrl,\n appName: \"app\", // Will need to be configured\n redirectTo: redirectUrl,\n });\n return;\n }\n\n const targetUrl = redirectUrl ?? window.location.href;\n const joinUrl = `${authUrl}/join?tenant=${encodeURIComponent(resolvedTenant)}&redirect-to=${encodeURIComponent(\n targetUrl,\n )}`;\n\n window.location.href = joinUrl;\n}\n\nexport interface HandleLogoutOptions {\n /** URL to redirect to after logout (defaults to current origin) */\n redirectUrl?: string;\n /** Auth SPA base URL */\n authUrl: string;\n /** localStorage key for tenant */\n tenantStorageKey?: string;\n /** Cookie name for logout timestamp */\n logoutTimestampCookie?: string;\n /** Callback to execute before logout */\n callback?: () => void;\n}\n\n/**\n * Handle user logout\n *\n * This function:\n * - Clears localStorage (preserving tenant)\n * - Sets logout timestamp cookie for cross-SPA sync\n * - Clears all cookies\n * - Redirects to auth SPA logout endpoint\n *\n * @param options - Logout configuration options\n *\n * @example\n * ```tsx\n * handleLogout({\n * authUrl: 'https://auth.example.com',\n * redirectUrl: 'https://app.example.com',\n * });\n * ```\n */\nexport function handleLogout(options: HandleLogoutOptions): void {\n const {\n redirectUrl = window.location.origin,\n authUrl,\n tenantStorageKey = \"tenant\",\n logoutTimestampCookie = \"ibl_logout_timestamp\",\n callback,\n } = options;\n\n const tenant = window.localStorage.getItem(tenantStorageKey);\n window.localStorage.clear();\n if (tenant) {\n window.localStorage.setItem(tenantStorageKey, tenant);\n }\n\n // Set logout timestamp cookie to trigger logout on other SPAs\n setCookieForAuth(logoutTimestampCookie, Date.now().toString());\n\n clearCookies();\n callback?.();\n\n if (!isInIframe()) {\n window.location.href = `${authUrl}/logout?redirect-to=${redirectUrl}${tenant ? \"&tenant=\" + tenant : \"\"}`;\n }\n}\n"],"names":[],"mappings":"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"}
@@ -183,7 +183,7 @@ async function redirectToAuthSpa(options) {
183
183
  logoutTimestamp: "ibl_logout_timestamp",
184
184
  loginTimestamp: "ibl_login_timestamp",
185
185
  tenantSwitching: "ibl_tenant_switching",
186
- }, hasNonExpiredAuthToken, isOffline, preserveTokenKey, authRedirectProxy, isNativeApp, forceRedirect = false, } = options;
186
+ }, hasNonExpiredAuthToken, isOffline, preserveTokenKey, authRedirectProxy, isNativeApp, scheme = "iblai-mentor://", forceRedirect = false, } = options;
187
187
  console.log("[redirectToAuthSpa] starting redirect to auth spa", redirectTo, platformKey, logout, saveRedirect, forceRedirect);
188
188
  // Skip if a tenant switch is already in progress
189
189
  if (!forceRedirect &&
@@ -258,7 +258,7 @@ async function redirectToAuthSpa(options) {
258
258
  window.localStorage.setItem(redirectPathStorageKey, redirectPath);
259
259
  }
260
260
  const platform = platformKey !== null && platformKey !== void 0 ? platformKey : getPlatformKey(redirectPath);
261
- const redirectToUrl = `${window.location.origin}`;
261
+ const redirectToUrl = (isNativeApp === null || isNativeApp === void 0 ? void 0 : isNativeApp()) ? scheme : `${window.location.origin}`;
262
262
  let authRedirectUrl = `${authUrl}/login?${queryParams.app}=${appName}`;
263
263
  authRedirectUrl += `&${queryParams.redirectTo}=${redirectToUrl}`;
264
264
  if (platform) {
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../src/utils/auth.ts"],"sourcesContent":["/**\n * Authentication and Authorization Utilities\n *\n * This module provides utility functions for handling authentication flows,\n * including redirects to auth SPA, cookie management, and session handling.\n */\n\n/**\n * Check if the current window is inside an iframe\n * @returns {boolean} True if running in an iframe, false otherwise\n */\nexport function isInIframe(): boolean {\n if (typeof window === \"undefined\") {\n return false;\n }\n return window?.self !== window?.top;\n}\n\n/**\n * Send a message to the parent website (when in iframe)\n * @param payload - The data to send to parent window\n */\nexport function sendMessageToParentWebsite(payload: unknown): void {\n window.parent.postMessage(payload, \"*\");\n}\n\n/**\n * Delete a cookie with specific name, path, and domain\n * @param name - Cookie name\n * @param path - Cookie path\n * @param domain - Cookie domain\n */\nexport function deleteCookie(name: string, path: string, domain: string): void {\n const expires = \"expires=Thu, 01 Jan 1970 00:00:00 UTC;\";\n const cookieValue = `${name}=;`;\n const pathValue = path ? `path=${path};` : \"\";\n const domainValue = domain ? `domain=${domain};` : \"\";\n document.cookie = cookieValue + expires + pathValue + domainValue;\n}\n\n/**\n * Get all possible domain parts for cookie deletion\n * @param domain - The domain to split\n * @returns Array of domain parts\n * @example\n * getDomainParts('app.example.com') // returns ['app.example.com', 'example.com', 'com']\n */\nexport function getDomainParts(domain: string): string[] {\n const parts = domain.split(\".\");\n const domains: string[] = [];\n for (let i = parts.length - 1; i >= 0; i--) {\n domains.push(parts.slice(i).join(\".\"));\n }\n return domains;\n}\n\n/**\n * Delete a cookie across all possible domain variations\n * @param name - Cookie name to delete\n * @param childDomain - The current domain\n */\nexport function deleteCookieOnAllDomains(\n name: string,\n childDomain: string,\n): void {\n getDomainParts(childDomain).forEach((domainPart) => {\n deleteCookie(name, \"/\", domainPart);\n deleteCookie(name, \"\", domainPart);\n });\n}\n\n/**\n * Get the parent domain from a given domain\n * @param domain - The domain to process\n * @returns The parent domain (e.g., 'app.example.com' → '.example.com')\n */\nexport function getParentDomain(domain?: string): string {\n if (!domain) {\n return \"\";\n }\n const parts = domain.split(\".\");\n return parts.length > 1 ? `.${parts.slice(-2).join(\".\")}` : domain;\n}\n\n/**\n * Set a cookie for authentication with cross-domain support\n * @param name - Cookie name\n * @param value - Cookie value\n * @param days - Number of days until expiration (default: 365)\n */\nexport function setCookieForAuth(\n name: string,\n value: string,\n days: number = 365,\n): void {\n const expires = new Date();\n expires.setTime(expires.getTime() + days * 24 * 60 * 60 * 1000);\n\n const hostname = window.location.hostname;\n let baseDomain = hostname;\n\n // Calculate base domain (skip for localhost and IP addresses)\n if (hostname !== \"localhost\" && !/^\\d+\\.\\d+\\.\\d+\\.\\d+$/.test(hostname)) {\n const parts = hostname.split(\".\");\n if (parts.length > 2) {\n baseDomain = `.${parts.slice(-2).join(\".\")}`;\n }\n }\n\n const domainAttr = baseDomain ? `;domain=${baseDomain}` : \"\";\n document.cookie = `${name}=${encodeURIComponent(value)};expires=${expires.toUTCString()};path=/;SameSite=None;Secure${domainAttr}`;\n}\n\n/**\n * Clear all cookies for the current domain\n */\nexport function clearCookies(): void {\n const cookies = document.cookie.split(\";\");\n for (let i = 0; i < cookies.length; i++) {\n const cookie = cookies[i];\n const eqPos = cookie.indexOf(\"=\");\n const name = eqPos > -1 ? cookie.substr(0, eqPos) : cookie;\n deleteCookieOnAllDomains(name, window.location.hostname);\n document.cookie = `${name}=;expires=Thu, 01 Jan 1970 00:00:00 GMT;path=/;Domain=${getParentDomain(\n window.location.hostname,\n )}`;\n }\n}\n\n/**\n * Get the value of a cookie by name\n * @param name - Cookie name\n * @returns The cookie value or null if not found\n */\nexport function getCookieValue(name: string): string | null {\n const match = document.cookie.match(new RegExp(`(?:^|;\\\\s*)${name}=([^;]*)`));\n return match ? decodeURIComponent(match[1]) : null;\n}\n\n/**\n * Check if user is currently logged in\n * @param tokenKey - The localStorage key for the auth token (default: 'axd_token')\n * @returns True if logged in, false otherwise\n */\nexport function isLoggedIn(tokenKey: string = \"axd_token\"): boolean {\n return !!localStorage.getItem(tokenKey);\n}\n\n/**\n * Extract platform/tenant key from URL\n * @param url - The URL to parse\n * @param pattern - RegExp pattern to match platform key (default matches /platform/[key]/...)\n * @returns The platform key or null if not found\n */\nexport function getPlatformKey(\n url: string,\n pattern: RegExp = /\\/platform\\/([^/]+)/,\n): string | null {\n const match = url.match(pattern);\n return match ? match[1] : null;\n}\n\nexport interface RedirectToAuthSpaOptions {\n /** URL to redirect to after auth (defaults to current path + search) */\n redirectTo?: string;\n /** Platform/tenant key */\n platformKey?: string;\n /** Whether this is a logout action */\n logout?: boolean;\n /** Whether to save redirect path to localStorage (default: true) */\n saveRedirect?: boolean;\n /** Auth SPA base URL */\n authUrl: string;\n /** Current app/platform identifier (e.g., 'mentor', 'skills') */\n appName: string;\n /** Query param names */\n queryParams?: {\n app?: string;\n redirectTo?: string;\n tenant?: string;\n };\n /** localStorage key for saving redirect path */\n redirectPathStorageKey?: string;\n /** Cookie names for cross-SPA sync */\n cookieNames?: {\n currentTenant?: string;\n userData?: string;\n tenant?: string;\n logoutTimestamp?: string;\n loginTimestamp?: string;\n tenantSwitching?: string;\n };\n /** Function to check if auth token is valid and non-expired. Used to skip redirect when a recent login occurred. */\n hasNonExpiredAuthToken?: () => boolean;\n /** Function to check if the app is in offline mode (e.g., Tauri offline). Skips redirect when true. */\n isOffline?: () => boolean;\n /** localStorage key for a token to preserve before clearing storage (e.g., 'edx_jwt_token') */\n preserveTokenKey?: string;\n /** Path to an auth redirect proxy endpoint (e.g., '/api/auth-redirect'). When set, redirects via this proxy in browser. */\n authRedirectProxy?: string;\n /** Function to check if the app is running as a native app (e.g., Tauri). Affects redirect behavior. */\n isNativeApp?: () => boolean;\n forceRedirect?: boolean;\n}\n\n/**\n * Redirect to authentication SPA for login/logout\n *\n * This function handles the complete authentication flow:\n * - Clears localStorage and cookies on logout\n * - Saves redirect path for post-auth return\n * - Handles iframe scenarios\n * - Syncs logout across multiple SPAs via cookies\n *\n * @param options - Configuration options for the redirect\n *\n * @example\n * ```tsx\n * // Basic usage\n * redirectToAuthSpa({\n * authUrl: 'https://auth.example.com',\n * appName: 'mentor',\n * });\n *\n * // With logout\n * redirectToAuthSpa({\n * authUrl: 'https://auth.example.com',\n * appName: 'mentor',\n * logout: true,\n * platformKey: 'my-tenant',\n * });\n *\n * // With custom redirect\n * redirectToAuthSpa({\n * authUrl: 'https://auth.example.com',\n * appName: 'mentor',\n * redirectTo: '/dashboard',\n * platformKey: 'my-tenant',\n * });\n * ```\n */\nexport async function redirectToAuthSpa(\n options: RedirectToAuthSpaOptions,\n): Promise<void> {\n const {\n redirectTo,\n platformKey,\n logout = false,\n saveRedirect = true,\n authUrl,\n appName,\n queryParams = {\n app: \"app\",\n redirectTo: \"redirect-to\",\n tenant: \"tenant\",\n },\n redirectPathStorageKey = \"redirect_to\",\n cookieNames = {\n currentTenant: \"ibl_current_tenant\",\n userData: \"ibl_user_data\",\n tenant: \"ibl_tenant\",\n logoutTimestamp: \"ibl_logout_timestamp\",\n loginTimestamp: \"ibl_login_timestamp\",\n tenantSwitching: \"ibl_tenant_switching\",\n },\n hasNonExpiredAuthToken,\n isOffline,\n preserveTokenKey,\n authRedirectProxy,\n isNativeApp,\n forceRedirect = false,\n } = options;\n\n console.log(\n \"[redirectToAuthSpa] starting redirect to auth spa\",\n redirectTo,\n platformKey,\n logout,\n saveRedirect,\n forceRedirect,\n );\n\n // Skip if a tenant switch is already in progress\n if (\n !forceRedirect &&\n cookieNames.tenantSwitching &&\n document.cookie.includes(cookieNames.tenantSwitching)\n ) {\n console.log(\n \"[redirectToAuthSpa] Tenant switch in progress, skipping redirect\",\n );\n return;\n }\n\n // Skip if a login occurred after the last logout (login takes precedence)\n // but only if this app actually has a valid auth token\n if (\n !forceRedirect &&\n hasNonExpiredAuthToken &&\n cookieNames.loginTimestamp &&\n cookieNames.logoutTimestamp\n ) {\n const loginTs = getCookieValue(cookieNames.loginTimestamp);\n const logoutTs = getCookieValue(cookieNames.logoutTimestamp);\n const hasValidToken = hasNonExpiredAuthToken();\n console.log(\"[redirectToAuthSpa] Login/logout timestamp check\", {\n loginTs,\n logoutTs,\n hasValidToken,\n loginAhead:\n loginTs && logoutTs ? Number(loginTs) > Number(logoutTs) : false,\n });\n if (\n !forceRedirect &&\n hasValidToken &&\n loginTs &&\n logoutTs &&\n Number(loginTs) > Number(logoutTs)\n ) {\n console.log(\n \"[redirectToAuthSpa] Login timestamp is ahead of logout timestamp, skipping redirect\",\n { loginTs, logoutTs },\n );\n return;\n }\n }\n\n // Skip redirect in offline mode\n if (isOffline?.()) {\n console.log(\"[redirectToAuthSpa] Skipping redirect - offline mode\");\n return;\n }\n\n // Preserve a token before clearing localStorage if requested\n const preservedToken = preserveTokenKey\n ? window.localStorage.getItem(preserveTokenKey)\n : null;\n\n console.log(\"[redirectToAuthSpa] clearing local storage\");\n localStorage.clear();\n\n if (logout || isInIframe()) {\n // Delete authentication cookies for cross-SPA synchronization\n const currentDomain = window.location.hostname;\n if (cookieNames.currentTenant) {\n deleteCookieOnAllDomains(cookieNames.currentTenant, currentDomain);\n }\n if (cookieNames.userData) {\n deleteCookieOnAllDomains(cookieNames.userData, currentDomain);\n }\n if (cookieNames.tenant) {\n deleteCookieOnAllDomains(cookieNames.tenant, currentDomain);\n }\n\n // Set logout timestamp cookie to trigger logout on other SPAs\n if (cookieNames.logoutTimestamp && !isInIframe()) {\n setCookieForAuth(cookieNames.logoutTimestamp, Date.now().toString());\n }\n }\n\n // Handle iframe scenario\n if (isInIframe()) {\n console.log(\"[redirectToAuthSpa]: sending authExpired to parent\");\n sendMessageToParentWebsite({ authExpired: true });\n return;\n }\n\n const redirectPath =\n redirectTo ?? `${window.location.pathname}${window.location.search}`;\n\n // Never save sso-login routes as redirect paths\n if (\n !redirectPath.startsWith(\"/sso-login\") &&\n !redirectPath.startsWith(\"/sso-login-complete\") &&\n saveRedirect\n ) {\n window.localStorage.setItem(redirectPathStorageKey, redirectPath);\n }\n\n const platform = platformKey ?? getPlatformKey(redirectPath);\n\n const redirectToUrl = `${window.location.origin}`;\n\n let authRedirectUrl = `${authUrl}/login?${queryParams.app}=${appName}`;\n\n authRedirectUrl += `&${queryParams.redirectTo}=${redirectToUrl}`;\n\n if (platform) {\n authRedirectUrl += `&${queryParams.tenant}=${platform}`;\n }\n if (logout) {\n authRedirectUrl += \"&logout=1\";\n }\n\n // Small delay for any pending operations\n await new Promise((resolve) => setTimeout(resolve, 100));\n\n if (isNativeApp?.()) {\n // On native apps (e.g., Tauri), pass preserved token and navigate directly\n if (preservedToken && preserveTokenKey) {\n authRedirectUrl += `&token=${encodeURIComponent(preservedToken)}`;\n console.log(\"[redirectToAuthSpa] Added preserved token to auth URL\");\n }\n console.log(\n \"[redirectToAuthSpa] Native app, navigating to auth URL:\",\n authRedirectUrl,\n );\n window.location.href = authRedirectUrl;\n } else if (authRedirectProxy) {\n // Use auth redirect proxy endpoint\n window.location.href = `${authRedirectProxy}?to=${encodeURIComponent(authRedirectUrl)}`;\n } else {\n window.location.href = authRedirectUrl;\n }\n}\n\n/**\n * Get the URL for joining a tenant (sign up flow)\n * @param authUrl - Auth SPA base URL\n * @param tenantKey - Tenant to join\n * @param redirectUrl - URL to redirect to after joining (defaults to current URL)\n * @returns The join URL\n */\nexport function getAuthSpaJoinUrl(\n authUrl: string,\n tenantKey?: string,\n redirectUrl?: string,\n): string {\n const resolvedTenant =\n tenantKey || getPlatformKey(window.location.pathname) || \"\";\n\n if (!resolvedTenant) {\n return \"\";\n }\n\n const targetUrl = redirectUrl ?? window.location.href;\n const joinUrl = `${authUrl}/join?tenant=${encodeURIComponent(resolvedTenant)}&redirect-to=${encodeURIComponent(\n targetUrl,\n )}`;\n return joinUrl;\n}\n\n/**\n * Redirect to auth SPA's join/signup page for a specific tenant\n * @param authUrl - Auth SPA base URL\n * @param tenantKey - Tenant to join\n * @param redirectUrl - URL to redirect to after joining (defaults to current URL)\n */\nexport function redirectToAuthSpaJoinTenant(\n authUrl: string,\n tenantKey?: string,\n redirectUrl?: string,\n): void {\n const resolvedTenant =\n tenantKey || getPlatformKey(window.location.pathname) || \"\";\n\n if (!resolvedTenant) {\n console.log(\"[auth-redirect] Missing tenant key for join\", {\n tenantKey,\n redirectUrl,\n });\n redirectToAuthSpa({\n authUrl,\n appName: \"app\", // Will need to be configured\n redirectTo: redirectUrl,\n });\n return;\n }\n\n const targetUrl = redirectUrl ?? window.location.href;\n const joinUrl = `${authUrl}/join?tenant=${encodeURIComponent(resolvedTenant)}&redirect-to=${encodeURIComponent(\n targetUrl,\n )}`;\n\n window.location.href = joinUrl;\n}\n\nexport interface HandleLogoutOptions {\n /** URL to redirect to after logout (defaults to current origin) */\n redirectUrl?: string;\n /** Auth SPA base URL */\n authUrl: string;\n /** localStorage key for tenant */\n tenantStorageKey?: string;\n /** Cookie name for logout timestamp */\n logoutTimestampCookie?: string;\n /** Callback to execute before logout */\n callback?: () => void;\n}\n\n/**\n * Handle user logout\n *\n * This function:\n * - Clears localStorage (preserving tenant)\n * - Sets logout timestamp cookie for cross-SPA sync\n * - Clears all cookies\n * - Redirects to auth SPA logout endpoint\n *\n * @param options - Logout configuration options\n *\n * @example\n * ```tsx\n * handleLogout({\n * authUrl: 'https://auth.example.com',\n * redirectUrl: 'https://app.example.com',\n * });\n * ```\n */\nexport function handleLogout(options: HandleLogoutOptions): void {\n const {\n redirectUrl = window.location.origin,\n authUrl,\n tenantStorageKey = \"tenant\",\n logoutTimestampCookie = \"ibl_logout_timestamp\",\n callback,\n } = options;\n\n const tenant = window.localStorage.getItem(tenantStorageKey);\n window.localStorage.clear();\n if (tenant) {\n window.localStorage.setItem(tenantStorageKey, tenant);\n }\n\n // Set logout timestamp cookie to trigger logout on other SPAs\n setCookieForAuth(logoutTimestampCookie, Date.now().toString());\n\n clearCookies();\n callback?.();\n\n if (!isInIframe()) {\n window.location.href = `${authUrl}/logout?redirect-to=${redirectUrl}${tenant ? \"&tenant=\" + tenant : \"\"}`;\n }\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../../src/utils/auth.ts"],"sourcesContent":["/**\n * Authentication and Authorization Utilities\n *\n * This module provides utility functions for handling authentication flows,\n * including redirects to auth SPA, cookie management, and session handling.\n */\n\n/**\n * Check if the current window is inside an iframe\n * @returns {boolean} True if running in an iframe, false otherwise\n */\nexport function isInIframe(): boolean {\n if (typeof window === \"undefined\") {\n return false;\n }\n return window?.self !== window?.top;\n}\n\n/**\n * Send a message to the parent website (when in iframe)\n * @param payload - The data to send to parent window\n */\nexport function sendMessageToParentWebsite(payload: unknown): void {\n window.parent.postMessage(payload, \"*\");\n}\n\n/**\n * Delete a cookie with specific name, path, and domain\n * @param name - Cookie name\n * @param path - Cookie path\n * @param domain - Cookie domain\n */\nexport function deleteCookie(name: string, path: string, domain: string): void {\n const expires = \"expires=Thu, 01 Jan 1970 00:00:00 UTC;\";\n const cookieValue = `${name}=;`;\n const pathValue = path ? `path=${path};` : \"\";\n const domainValue = domain ? `domain=${domain};` : \"\";\n document.cookie = cookieValue + expires + pathValue + domainValue;\n}\n\n/**\n * Get all possible domain parts for cookie deletion\n * @param domain - The domain to split\n * @returns Array of domain parts\n * @example\n * getDomainParts('app.example.com') // returns ['app.example.com', 'example.com', 'com']\n */\nexport function getDomainParts(domain: string): string[] {\n const parts = domain.split(\".\");\n const domains: string[] = [];\n for (let i = parts.length - 1; i >= 0; i--) {\n domains.push(parts.slice(i).join(\".\"));\n }\n return domains;\n}\n\n/**\n * Delete a cookie across all possible domain variations\n * @param name - Cookie name to delete\n * @param childDomain - The current domain\n */\nexport function deleteCookieOnAllDomains(\n name: string,\n childDomain: string,\n): void {\n getDomainParts(childDomain).forEach((domainPart) => {\n deleteCookie(name, \"/\", domainPart);\n deleteCookie(name, \"\", domainPart);\n });\n}\n\n/**\n * Get the parent domain from a given domain\n * @param domain - The domain to process\n * @returns The parent domain (e.g., 'app.example.com' → '.example.com')\n */\nexport function getParentDomain(domain?: string): string {\n if (!domain) {\n return \"\";\n }\n const parts = domain.split(\".\");\n return parts.length > 1 ? `.${parts.slice(-2).join(\".\")}` : domain;\n}\n\n/**\n * Set a cookie for authentication with cross-domain support\n * @param name - Cookie name\n * @param value - Cookie value\n * @param days - Number of days until expiration (default: 365)\n */\nexport function setCookieForAuth(\n name: string,\n value: string,\n days: number = 365,\n): void {\n const expires = new Date();\n expires.setTime(expires.getTime() + days * 24 * 60 * 60 * 1000);\n\n const hostname = window.location.hostname;\n let baseDomain = hostname;\n\n // Calculate base domain (skip for localhost and IP addresses)\n if (hostname !== \"localhost\" && !/^\\d+\\.\\d+\\.\\d+\\.\\d+$/.test(hostname)) {\n const parts = hostname.split(\".\");\n if (parts.length > 2) {\n baseDomain = `.${parts.slice(-2).join(\".\")}`;\n }\n }\n\n const domainAttr = baseDomain ? `;domain=${baseDomain}` : \"\";\n document.cookie = `${name}=${encodeURIComponent(value)};expires=${expires.toUTCString()};path=/;SameSite=None;Secure${domainAttr}`;\n}\n\n/**\n * Clear all cookies for the current domain\n */\nexport function clearCookies(): void {\n const cookies = document.cookie.split(\";\");\n for (let i = 0; i < cookies.length; i++) {\n const cookie = cookies[i];\n const eqPos = cookie.indexOf(\"=\");\n const name = eqPos > -1 ? cookie.substr(0, eqPos) : cookie;\n deleteCookieOnAllDomains(name, window.location.hostname);\n document.cookie = `${name}=;expires=Thu, 01 Jan 1970 00:00:00 GMT;path=/;Domain=${getParentDomain(\n window.location.hostname,\n )}`;\n }\n}\n\n/**\n * Get the value of a cookie by name\n * @param name - Cookie name\n * @returns The cookie value or null if not found\n */\nexport function getCookieValue(name: string): string | null {\n const match = document.cookie.match(new RegExp(`(?:^|;\\\\s*)${name}=([^;]*)`));\n return match ? decodeURIComponent(match[1]) : null;\n}\n\n/**\n * Check if user is currently logged in\n * @param tokenKey - The localStorage key for the auth token (default: 'axd_token')\n * @returns True if logged in, false otherwise\n */\nexport function isLoggedIn(tokenKey: string = \"axd_token\"): boolean {\n return !!localStorage.getItem(tokenKey);\n}\n\n/**\n * Extract platform/tenant key from URL\n * @param url - The URL to parse\n * @param pattern - RegExp pattern to match platform key (default matches /platform/[key]/...)\n * @returns The platform key or null if not found\n */\nexport function getPlatformKey(\n url: string,\n pattern: RegExp = /\\/platform\\/([^/]+)/,\n): string | null {\n const match = url.match(pattern);\n return match ? match[1] : null;\n}\n\nexport interface RedirectToAuthSpaOptions {\n /** URL to redirect to after auth (defaults to current path + search) */\n redirectTo?: string;\n /** Platform/tenant key */\n platformKey?: string;\n /** Whether this is a logout action */\n logout?: boolean;\n /** Whether to save redirect path to localStorage (default: true) */\n saveRedirect?: boolean;\n /** Auth SPA base URL */\n authUrl: string;\n /** Current app/platform identifier (e.g., 'mentor', 'skills') */\n appName: string;\n /** Query param names */\n queryParams?: {\n app?: string;\n redirectTo?: string;\n tenant?: string;\n };\n /** localStorage key for saving redirect path */\n redirectPathStorageKey?: string;\n /** Cookie names for cross-SPA sync */\n cookieNames?: {\n currentTenant?: string;\n userData?: string;\n tenant?: string;\n logoutTimestamp?: string;\n loginTimestamp?: string;\n tenantSwitching?: string;\n };\n /** Function to check if auth token is valid and non-expired. Used to skip redirect when a recent login occurred. */\n hasNonExpiredAuthToken?: () => boolean;\n /** Function to check if the app is in offline mode (e.g., Tauri offline). Skips redirect when true. */\n isOffline?: () => boolean;\n /** localStorage key for a token to preserve before clearing storage (e.g., 'edx_jwt_token') */\n preserveTokenKey?: string;\n /** Path to an auth redirect proxy endpoint (e.g., '/api/auth-redirect'). When set, redirects via this proxy in browser. */\n authRedirectProxy?: string;\n /** Function to check if the app is running as a native app (e.g., Tauri). Affects redirect behavior. */\n isNativeApp?: () => boolean;\n forceRedirect?: boolean;\n scheme?: string;\n}\n\n/**\n * Redirect to authentication SPA for login/logout\n *\n * This function handles the complete authentication flow:\n * - Clears localStorage and cookies on logout\n * - Saves redirect path for post-auth return\n * - Handles iframe scenarios\n * - Syncs logout across multiple SPAs via cookies\n *\n * @param options - Configuration options for the redirect\n *\n * @example\n * ```tsx\n * // Basic usage\n * redirectToAuthSpa({\n * authUrl: 'https://auth.example.com',\n * appName: 'mentor',\n * });\n *\n * // With logout\n * redirectToAuthSpa({\n * authUrl: 'https://auth.example.com',\n * appName: 'mentor',\n * logout: true,\n * platformKey: 'my-tenant',\n * });\n *\n * // With custom redirect\n * redirectToAuthSpa({\n * authUrl: 'https://auth.example.com',\n * appName: 'mentor',\n * redirectTo: '/dashboard',\n * platformKey: 'my-tenant',\n * });\n * ```\n */\nexport async function redirectToAuthSpa(\n options: RedirectToAuthSpaOptions,\n): Promise<void> {\n const {\n redirectTo,\n platformKey,\n logout = false,\n saveRedirect = true,\n authUrl,\n appName,\n queryParams = {\n app: \"app\",\n redirectTo: \"redirect-to\",\n tenant: \"tenant\",\n },\n redirectPathStorageKey = \"redirect_to\",\n cookieNames = {\n currentTenant: \"ibl_current_tenant\",\n userData: \"ibl_user_data\",\n tenant: \"ibl_tenant\",\n logoutTimestamp: \"ibl_logout_timestamp\",\n loginTimestamp: \"ibl_login_timestamp\",\n tenantSwitching: \"ibl_tenant_switching\",\n },\n hasNonExpiredAuthToken,\n isOffline,\n preserveTokenKey,\n authRedirectProxy,\n isNativeApp,\n scheme = \"iblai-mentor://\",\n forceRedirect = false,\n } = options;\n\n console.log(\n \"[redirectToAuthSpa] starting redirect to auth spa\",\n redirectTo,\n platformKey,\n logout,\n saveRedirect,\n forceRedirect,\n );\n\n // Skip if a tenant switch is already in progress\n if (\n !forceRedirect &&\n cookieNames.tenantSwitching &&\n document.cookie.includes(cookieNames.tenantSwitching)\n ) {\n console.log(\n \"[redirectToAuthSpa] Tenant switch in progress, skipping redirect\",\n );\n return;\n }\n\n // Skip if a login occurred after the last logout (login takes precedence)\n // but only if this app actually has a valid auth token\n if (\n !forceRedirect &&\n hasNonExpiredAuthToken &&\n cookieNames.loginTimestamp &&\n cookieNames.logoutTimestamp\n ) {\n const loginTs = getCookieValue(cookieNames.loginTimestamp);\n const logoutTs = getCookieValue(cookieNames.logoutTimestamp);\n const hasValidToken = hasNonExpiredAuthToken();\n console.log(\"[redirectToAuthSpa] Login/logout timestamp check\", {\n loginTs,\n logoutTs,\n hasValidToken,\n loginAhead:\n loginTs && logoutTs ? Number(loginTs) > Number(logoutTs) : false,\n });\n if (\n !forceRedirect &&\n hasValidToken &&\n loginTs &&\n logoutTs &&\n Number(loginTs) > Number(logoutTs)\n ) {\n console.log(\n \"[redirectToAuthSpa] Login timestamp is ahead of logout timestamp, skipping redirect\",\n { loginTs, logoutTs },\n );\n return;\n }\n }\n\n // Skip redirect in offline mode\n if (isOffline?.()) {\n console.log(\"[redirectToAuthSpa] Skipping redirect - offline mode\");\n return;\n }\n\n // Preserve a token before clearing localStorage if requested\n const preservedToken = preserveTokenKey\n ? window.localStorage.getItem(preserveTokenKey)\n : null;\n\n console.log(\"[redirectToAuthSpa] clearing local storage\");\n localStorage.clear();\n\n if (logout || isInIframe()) {\n // Delete authentication cookies for cross-SPA synchronization\n const currentDomain = window.location.hostname;\n if (cookieNames.currentTenant) {\n deleteCookieOnAllDomains(cookieNames.currentTenant, currentDomain);\n }\n if (cookieNames.userData) {\n deleteCookieOnAllDomains(cookieNames.userData, currentDomain);\n }\n if (cookieNames.tenant) {\n deleteCookieOnAllDomains(cookieNames.tenant, currentDomain);\n }\n\n // Set logout timestamp cookie to trigger logout on other SPAs\n if (cookieNames.logoutTimestamp && !isInIframe()) {\n setCookieForAuth(cookieNames.logoutTimestamp, Date.now().toString());\n }\n }\n\n // Handle iframe scenario\n if (isInIframe()) {\n console.log(\"[redirectToAuthSpa]: sending authExpired to parent\");\n sendMessageToParentWebsite({ authExpired: true });\n return;\n }\n\n const redirectPath =\n redirectTo ?? `${window.location.pathname}${window.location.search}`;\n\n // Never save sso-login routes as redirect paths\n if (\n !redirectPath.startsWith(\"/sso-login\") &&\n !redirectPath.startsWith(\"/sso-login-complete\") &&\n saveRedirect\n ) {\n window.localStorage.setItem(redirectPathStorageKey, redirectPath);\n }\n\n const platform = platformKey ?? getPlatformKey(redirectPath);\n\n const redirectToUrl = isNativeApp?.() ? scheme : `${window.location.origin}`;\n\n let authRedirectUrl = `${authUrl}/login?${queryParams.app}=${appName}`;\n\n authRedirectUrl += `&${queryParams.redirectTo}=${redirectToUrl}`;\n\n if (platform) {\n authRedirectUrl += `&${queryParams.tenant}=${platform}`;\n }\n if (logout) {\n authRedirectUrl += \"&logout=1\";\n }\n\n // Small delay for any pending operations\n await new Promise((resolve) => setTimeout(resolve, 100));\n\n if (isNativeApp?.()) {\n // On native apps (e.g., Tauri), pass preserved token and navigate directly\n if (preservedToken && preserveTokenKey) {\n authRedirectUrl += `&token=${encodeURIComponent(preservedToken)}`;\n console.log(\"[redirectToAuthSpa] Added preserved token to auth URL\");\n }\n console.log(\n \"[redirectToAuthSpa] Native app, navigating to auth URL:\",\n authRedirectUrl,\n );\n window.location.href = authRedirectUrl;\n } else if (authRedirectProxy) {\n // Use auth redirect proxy endpoint\n window.location.href = `${authRedirectProxy}?to=${encodeURIComponent(authRedirectUrl)}`;\n } else {\n window.location.href = authRedirectUrl;\n }\n}\n\n/**\n * Get the URL for joining a tenant (sign up flow)\n * @param authUrl - Auth SPA base URL\n * @param tenantKey - Tenant to join\n * @param redirectUrl - URL to redirect to after joining (defaults to current URL)\n * @returns The join URL\n */\nexport function getAuthSpaJoinUrl(\n authUrl: string,\n tenantKey?: string,\n redirectUrl?: string,\n): string {\n const resolvedTenant =\n tenantKey || getPlatformKey(window.location.pathname) || \"\";\n\n if (!resolvedTenant) {\n return \"\";\n }\n\n const targetUrl = redirectUrl ?? window.location.href;\n const joinUrl = `${authUrl}/join?tenant=${encodeURIComponent(resolvedTenant)}&redirect-to=${encodeURIComponent(\n targetUrl,\n )}`;\n return joinUrl;\n}\n\n/**\n * Redirect to auth SPA's join/signup page for a specific tenant\n * @param authUrl - Auth SPA base URL\n * @param tenantKey - Tenant to join\n * @param redirectUrl - URL to redirect to after joining (defaults to current URL)\n */\nexport function redirectToAuthSpaJoinTenant(\n authUrl: string,\n tenantKey?: string,\n redirectUrl?: string,\n): void {\n const resolvedTenant =\n tenantKey || getPlatformKey(window.location.pathname) || \"\";\n\n if (!resolvedTenant) {\n console.log(\"[auth-redirect] Missing tenant key for join\", {\n tenantKey,\n redirectUrl,\n });\n redirectToAuthSpa({\n authUrl,\n appName: \"app\", // Will need to be configured\n redirectTo: redirectUrl,\n });\n return;\n }\n\n const targetUrl = redirectUrl ?? window.location.href;\n const joinUrl = `${authUrl}/join?tenant=${encodeURIComponent(resolvedTenant)}&redirect-to=${encodeURIComponent(\n targetUrl,\n )}`;\n\n window.location.href = joinUrl;\n}\n\nexport interface HandleLogoutOptions {\n /** URL to redirect to after logout (defaults to current origin) */\n redirectUrl?: string;\n /** Auth SPA base URL */\n authUrl: string;\n /** localStorage key for tenant */\n tenantStorageKey?: string;\n /** Cookie name for logout timestamp */\n logoutTimestampCookie?: string;\n /** Callback to execute before logout */\n callback?: () => void;\n}\n\n/**\n * Handle user logout\n *\n * This function:\n * - Clears localStorage (preserving tenant)\n * - Sets logout timestamp cookie for cross-SPA sync\n * - Clears all cookies\n * - Redirects to auth SPA logout endpoint\n *\n * @param options - Logout configuration options\n *\n * @example\n * ```tsx\n * handleLogout({\n * authUrl: 'https://auth.example.com',\n * redirectUrl: 'https://app.example.com',\n * });\n * ```\n */\nexport function handleLogout(options: HandleLogoutOptions): void {\n const {\n redirectUrl = window.location.origin,\n authUrl,\n tenantStorageKey = \"tenant\",\n logoutTimestampCookie = \"ibl_logout_timestamp\",\n callback,\n } = options;\n\n const tenant = window.localStorage.getItem(tenantStorageKey);\n window.localStorage.clear();\n if (tenant) {\n window.localStorage.setItem(tenantStorageKey, tenant);\n }\n\n // Set logout timestamp cookie to trigger logout on other SPAs\n setCookieForAuth(logoutTimestampCookie, Date.now().toString());\n\n clearCookies();\n callback?.();\n\n if (!isInIframe()) {\n window.location.href = `${authUrl}/logout?redirect-to=${redirectUrl}${tenant ? \"&tenant=\" + tenant : \"\"}`;\n }\n}\n"],"names":[],"mappings":"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"}
@@ -112,6 +112,7 @@ export interface RedirectToAuthSpaOptions {
112
112
  /** Function to check if the app is running as a native app (e.g., Tauri). Affects redirect behavior. */
113
113
  isNativeApp?: () => boolean;
114
114
  forceRedirect?: boolean;
115
+ scheme?: string;
115
116
  }
116
117
  /**
117
118
  * Redirect to authentication SPA for login/logout
package/dist/index.d.ts CHANGED
@@ -932,6 +932,7 @@ interface RedirectToAuthSpaOptions {
932
932
  /** Function to check if the app is running as a native app (e.g., Tauri). Affects redirect behavior. */
933
933
  isNativeApp?: () => boolean;
934
934
  forceRedirect?: boolean;
935
+ scheme?: string;
935
936
  }
936
937
  /**
937
938
  * Redirect to authentication SPA for login/logout
package/dist/index.esm.js CHANGED
@@ -1175,7 +1175,7 @@ async function redirectToAuthSpa(options) {
1175
1175
  logoutTimestamp: "ibl_logout_timestamp",
1176
1176
  loginTimestamp: "ibl_login_timestamp",
1177
1177
  tenantSwitching: "ibl_tenant_switching",
1178
- }, hasNonExpiredAuthToken, isOffline, preserveTokenKey, authRedirectProxy, isNativeApp, forceRedirect = false, } = options;
1178
+ }, hasNonExpiredAuthToken, isOffline, preserveTokenKey, authRedirectProxy, isNativeApp, scheme = "iblai-mentor://", forceRedirect = false, } = options;
1179
1179
  console.log("[redirectToAuthSpa] starting redirect to auth spa", redirectTo, platformKey, logout, saveRedirect, forceRedirect);
1180
1180
  // Skip if a tenant switch is already in progress
1181
1181
  if (!forceRedirect &&
@@ -1250,7 +1250,7 @@ async function redirectToAuthSpa(options) {
1250
1250
  window.localStorage.setItem(redirectPathStorageKey, redirectPath);
1251
1251
  }
1252
1252
  const platform = platformKey !== null && platformKey !== void 0 ? platformKey : getPlatformKey(redirectPath);
1253
- const redirectToUrl = `${window.location.origin}`;
1253
+ const redirectToUrl = (isNativeApp === null || isNativeApp === void 0 ? void 0 : isNativeApp()) ? scheme : `${window.location.origin}`;
1254
1254
  let authRedirectUrl = `${authUrl}/login?${queryParams.app}=${appName}`;
1255
1255
  authRedirectUrl += `&${queryParams.redirectTo}=${redirectToUrl}`;
1256
1256
  if (platform) {