@xinosolutions/auth-sdk 0.3.0 → 0.3.1

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.
package/dist/index.cjs CHANGED
@@ -27,10 +27,12 @@ __export(index_exports, {
27
27
  SessionBridgeError: () => SessionBridgeError,
28
28
  XSAuthDeniedError: () => XSAuthDeniedError,
29
29
  createPkcePair: () => createPkcePair,
30
+ idTokenIncludesMfa: () => idTokenIncludesMfa,
30
31
  isLoginRequiredError: () => isLoginRequiredError,
31
32
  isPrimaryAccountError: () => isPrimaryAccountError,
32
33
  loginWithXS: () => loginWithXS,
33
34
  openSessionBridge: () => openSessionBridge2,
35
+ parseIdTokenAmr: () => parseIdTokenAmr,
34
36
  signOutWithXS: () => signOutWithXS2
35
37
  });
36
38
  module.exports = __toCommonJS(index_exports);
@@ -441,7 +443,7 @@ async function loginWithXS(opts) {
441
443
  "loginWithXS requires a browser Window and explicit parentOrigin (or window.location)."
442
444
  );
443
445
  }
444
- const timeoutMs = opts.timeoutMs !== void 0 ? opts.timeoutMs : 12e4;
446
+ const timeoutMs = opts.timeoutMs !== void 0 ? opts.timeoutMs : 18e4;
445
447
  const state = randomBase64State();
446
448
  sessionStorage.setItem(STATE_KEY_STORAGE, state);
447
449
  const nonce = opts.useNonce ? randomBase64State() : void 0;
@@ -529,7 +531,7 @@ async function loginWithXS(opts) {
529
531
  window.removeEventListener("message", handleMessage);
530
532
  clearInterval(closePoll);
531
533
  cleaned = true;
532
- resolve({ user, idToken });
534
+ resolve({ user, idToken, mfaVerified: idTokenIncludesMfa(idToken) });
533
535
  try {
534
536
  popup.close();
535
537
  } catch {
@@ -545,6 +547,31 @@ async function loginWithXS(opts) {
545
547
  }, 280);
546
548
  });
547
549
  }
550
+ function idTokenIncludesMfa(idToken) {
551
+ const amr = parseIdTokenAmr(idToken);
552
+ return Array.isArray(amr) && amr.includes("mfa");
553
+ }
554
+ function parseIdTokenAmr(idToken) {
555
+ const payload = parseJwtPayload(idToken);
556
+ if (!payload || !("amr" in payload)) return null;
557
+ const amr = payload.amr;
558
+ if (Array.isArray(amr)) {
559
+ return amr.filter((v) => typeof v === "string");
560
+ }
561
+ if (typeof amr === "string" && amr.trim()) return [amr.trim()];
562
+ return null;
563
+ }
564
+ function parseJwtPayload(token) {
565
+ const parts = token.split(".");
566
+ if (parts.length < 2) return null;
567
+ try {
568
+ const json = atob(parts[1].replace(/-/g, "+").replace(/_/g, "/"));
569
+ const parsed = JSON.parse(json);
570
+ return parsed && typeof parsed === "object" ? parsed : null;
571
+ } catch {
572
+ return null;
573
+ }
574
+ }
548
575
  function randomBase64State() {
549
576
  return base64UrlEncode(bytesBuffer(32));
550
577
  }
@@ -573,10 +600,12 @@ function isLoginRequiredError(error) {
573
600
  SessionBridgeError,
574
601
  XSAuthDeniedError,
575
602
  createPkcePair,
603
+ idTokenIncludesMfa,
576
604
  isLoginRequiredError,
577
605
  isPrimaryAccountError,
578
606
  loginWithXS,
579
607
  openSessionBridge,
608
+ parseIdTokenAmr,
580
609
  signOutWithXS
581
610
  });
582
611
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/errors.ts","../src/session-bridge.ts","../src/sign-out.ts"],"sourcesContent":["import {\r\n LoginTimeoutError,\r\n PopupBlockedError,\r\n PopupClosedError,\r\n XSAuthDeniedError,\r\n} from './errors';\r\nimport {\r\n isPrimaryAccountError,\r\n openSessionBridge as openSessionBridgeInternal,\r\n SessionBridgeError,\r\n type OpenSessionBridgeOptions,\r\n type SessionBridge,\r\n type XSBrowserAccount,\r\n} from './session-bridge';\r\n\r\nimport {\r\n signOutWithXS as signOutWithXSInternal,\r\n type SignOutAction,\r\n type SignOutWithXSOptions,\r\n type SignOutWithXSResult,\r\n} from './sign-out';\r\n\r\nexport {\r\n LoginBridgeTimeoutError,\r\n LoginTimeoutError,\r\n PopupBlockedError,\r\n PopupClosedError,\r\n XSAuthDeniedError,\r\n} from './errors';\r\n\r\nexport {\r\n isPrimaryAccountError,\r\n SessionBridgeError,\r\n type OpenSessionBridgeOptions,\r\n type SessionBridge,\r\n type XSBrowserAccount,\r\n};\r\n\r\nexport {\r\n type SignOutAction,\r\n type SignOutWithXSOptions,\r\n type SignOutWithXSResult,\r\n};\r\n\r\n/** XS Auth server — baked in at build time (local vs production). */\r\nconst XS_AUTH_BASE_URL = __XS_AUTH_BASE_URL__;\r\n\r\n/** Opens the Auth-Server session bridge popup (multi-account sign-out). */\r\nexport function openSessionBridge(\r\n opts: OpenSessionBridgeOptions,\r\n): Promise<SessionBridge> {\r\n return openSessionBridgeInternal(opts, XS_AUTH_BASE_URL);\r\n}\r\n\r\n/** Google-style sign-out popup on the Auth-Server domain. */\r\nexport function signOutWithXS(opts: SignOutWithXSOptions): Promise<SignOutWithXSResult> {\r\n const authBase = opts.authBaseUrl?.trim() || XS_AUTH_BASE_URL;\r\n return signOutWithXSInternal(opts, authBase);\r\n}\r\n\r\n/** Signed-in user profile from XS Auth. */\r\nexport interface XSAuthUser {\r\n email: string;\r\n firstName?: string;\r\n lastName?: string;\r\n}\r\n\r\nexport interface LoginWithXSOptions {\r\n /** Your app's public client id from Xino Solutions. */\r\n clientId: string;\r\n /** Must be on your XS Auth client's allowed domains list (normally `window.location.origin`). */\r\n parentOrigin?: string;\r\n timeoutMs?: number;\r\n scope?: string;\r\n /**\r\n * Request a `nonce` inside `idToken` — your backend should verify it matches when validating the JWT.\r\n */\r\n useNonce?: boolean;\r\n /**\r\n * OAuth-style prompt for multi-account SSO on the Auth-Server domain.\r\n * - `none`: silent sign-in with the primary browser session (fails with `login_required` if absent)\r\n * - `select_account`: always show the account chooser when sessions exist\r\n * - `login`: force email/password (add another account)\r\n */\r\n prompt?: 'none' | 'select_account' | 'login';\r\n /** Prefer a specific XS Auth user id (`sub`) when continuing an existing browser session. */\r\n accountId?: string;\r\n /** When true and `prompt` is unset, defaults to `none` instead of account chooser. */\r\n preferPrimary?: boolean;\r\n /** Override Auth-Server base URL (e.g. same-origin `/xs-auth` proxy in local dev). */\r\n authBaseUrl?: string;\r\n}\r\n\r\nexport interface LoginWithXSResult {\r\n user: XSAuthUser;\r\n /** Short-lived signed JWT — send to your backend to create a session. */\r\n idToken: string;\r\n}\r\n\r\nfunction bytesBuffer(len: number): Uint8Array {\r\n const out = new Uint8Array(len);\r\n crypto.getRandomValues(out);\r\n return out;\r\n}\r\n\r\nfunction base64UrlEncode(buf: Uint8Array | ArrayBuffer): string {\r\n const bytes = buf instanceof Uint8Array ? buf : new Uint8Array(buf);\r\n let binary = '';\r\n const chunkSize = 0x8000;\r\n for (let i = 0; i < bytes.length; i += chunkSize) {\r\n binary += String.fromCharCode(...bytes.subarray(i, i + chunkSize));\r\n }\r\n const b64 = btoa(binary);\r\n return b64.replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/u, '');\r\n}\r\n\r\nasync function pkceVerifierAndChallenge(): Promise<{\r\n verifier: string;\r\n challenge: string;\r\n}> {\r\n const verifier = base64UrlEncode(bytesBuffer(64));\r\n const data = new TextEncoder().encode(verifier);\r\n const digest = await crypto.subtle.digest('SHA-256', data);\r\n const challenge = base64UrlEncode(digest);\r\n return { verifier, challenge };\r\n}\r\n\r\n/** PKCE helpers for tests / custom callers. */\r\nexport async function createPkcePair(): Promise<{\r\n verifier: string;\r\n challenge: string;\r\n}> {\r\n return pkceVerifierAndChallenge();\r\n}\r\n\r\nconst STATE_KEY_STORAGE = '__xs_login_state';\r\n\r\nfunction parseSdkUser(raw: unknown): XSAuthUser | null {\r\n if (!raw || typeof raw !== 'object') return null;\r\n const u = raw as Record<string, unknown>;\r\n const email = typeof u.email === 'string' ? u.email.trim() : '';\r\n if (!email) return null;\r\n const user: XSAuthUser = { email };\r\n const firstName =\r\n typeof u.firstName === 'string' ? u.firstName.trim() : '';\r\n const lastName = typeof u.lastName === 'string' ? u.lastName.trim() : '';\r\n if (firstName) user.firstName = firstName;\r\n if (lastName) user.lastName = lastName;\r\n return user;\r\n}\r\n\r\nfunction resolvePrompt(opts: LoginWithXSOptions): string | undefined {\r\n if (opts.prompt) return opts.prompt;\r\n if (opts.preferPrimary) return 'none';\r\n return undefined;\r\n}\r\n\r\nfunction authPublicPathFromBase(authBaseUrl: string): string {\r\n try {\r\n const pathname = new URL(authBaseUrl).pathname.replace(/\\/$/u, '');\r\n return pathname === '/' ? '' : pathname;\r\n } catch {\r\n return '';\r\n }\r\n}\r\n\r\nfunction maybeSetPublicPath(params: URLSearchParams, authBaseUrl: string): void {\r\n const publicPath = authPublicPathFromBase(authBaseUrl);\r\n if (publicPath) params.set('public_path', publicPath);\r\n}\r\n\r\n/**\r\n * Opens the XS Auth sign-in popup and returns the signed-in user plus a verifiable `idToken`.\r\n *\r\n * All Auth-Server HTTP calls happen inside the popup (same origin). The host app only\r\n * opens the popup and exchanges postMessages with the PKCE verifier — no fetch to Auth-Server.\r\n */\r\nexport async function loginWithXS(\r\n opts: LoginWithXSOptions,\r\n): Promise<LoginWithXSResult> {\r\n const authBase = opts.authBaseUrl?.trim() || XS_AUTH_BASE_URL;\r\n const normalizedBase = normalizeBaseUrl(authBase);\r\n const authOrigin = normalizedBase.origin;\r\n const parentOrigin = (opts.parentOrigin ?? globalThis.location?.origin) as\r\n | string\r\n | undefined;\r\n if (!parentOrigin || typeof window === 'undefined') {\r\n throw new Error(\r\n 'loginWithXS requires a browser Window and explicit parentOrigin (or window.location).',\r\n );\r\n }\r\n\r\n const timeoutMs =\r\n opts.timeoutMs !== undefined ? opts.timeoutMs : 120_000;\r\n\r\n const state = randomBase64State();\r\n sessionStorage.setItem(STATE_KEY_STORAGE, state);\r\n\r\n const nonce = opts.useNonce ? randomBase64State() : undefined;\r\n const pair = await pkceVerifierAndChallenge();\r\n\r\n const params = new URLSearchParams({\r\n client_id: opts.clientId,\r\n state,\r\n code_challenge: pair.challenge,\r\n code_challenge_method: 'S256',\r\n parent_origin: parentOrigin,\r\n response_mode: 'popup',\r\n });\r\n if (opts.scope?.trim()) params.set('scope', opts.scope.trim());\r\n if (nonce) params.set('nonce', nonce);\r\n const prompt = resolvePrompt(opts);\r\n if (prompt) params.set('prompt', prompt);\r\n if (opts.accountId?.trim()) params.set('account_id', opts.accountId.trim());\r\n maybeSetPublicPath(params, authBase);\r\n\r\n const authorizeUrl = `${normalizedBase.href.replace(/\\/?$/u, '')}/authorize?${params.toString()}`;\r\n\r\n const popupWidth = prompt === 'none' ? 420 : 480;\r\n const popupHeight = prompt === 'none' ? 120 : 640;\r\n const popup = window.open(\r\n authorizeUrl,\r\n `xs-auth-${crypto.randomUUID()}`,\r\n popupWindowFeatures(popupWidth, popupHeight),\r\n );\r\n if (!popup) throw new PopupBlockedError();\r\n\r\n return await new Promise<LoginWithXSResult>((resolve, reject) => {\r\n let cleaned = false;\r\n const teardown = (): void => {\r\n if (cleaned) return;\r\n cleaned = true;\r\n window.removeEventListener('message', handleMessage as EventListener);\r\n clearInterval(closePoll);\r\n clearTimeout(timer);\r\n try {\r\n popup.close();\r\n } catch {\r\n // ignore\r\n }\r\n };\r\n\r\n const fail = (e: unknown): void => {\r\n teardown();\r\n reject(e instanceof Error ? e : new Error(String(e)));\r\n };\r\n\r\n const timer = window.setTimeout(() => {\r\n fail(new LoginTimeoutError());\r\n }, timeoutMs);\r\n\r\n const handleMessage = (event: MessageEvent): void => {\r\n if (event.origin !== authOrigin) return;\r\n const d = event.data as Partial<Record<string, unknown>>;\r\n if (d?.source !== 'xs-auth') return;\r\n\r\n const st = typeof d.state === 'string' ? d.state : '';\r\n if (!st || st !== sessionStorage.getItem(STATE_KEY_STORAGE)) return;\r\n\r\n if (typeof d.error === 'string' && d.error.length > 0) {\r\n teardown();\r\n reject(\r\n new XSAuthDeniedError(\r\n String(d.error),\r\n typeof d.error_description === 'string'\r\n ? d.error_description\r\n : '',\r\n ),\r\n );\r\n return;\r\n }\r\n\r\n if (d.type === 'need_verifier') {\r\n try {\r\n popup.postMessage(\r\n {\r\n source: 'xs-auth-opener',\r\n state: st,\r\n code_verifier: pair.verifier,\r\n client_id: opts.clientId,\r\n },\r\n authOrigin,\r\n );\r\n } catch {\r\n fail(new XSAuthDeniedError('exchange_failed', 'Sign in could not be completed.'));\r\n }\r\n return;\r\n }\r\n\r\n const idToken =\r\n typeof d.id_token === 'string'\r\n ? d.id_token\r\n : typeof d.idToken === 'string'\r\n ? d.idToken\r\n : '';\r\n const user = parseSdkUser(d.user);\r\n if (!idToken || !user) return;\r\n\r\n sessionStorage.removeItem(STATE_KEY_STORAGE);\r\n clearTimeout(timer);\r\n window.removeEventListener('message', handleMessage as EventListener);\r\n clearInterval(closePoll);\r\n cleaned = true;\r\n\r\n resolve({ user, idToken });\r\n\r\n try {\r\n popup.close();\r\n } catch {\r\n // ignore\r\n }\r\n };\r\n\r\n window.addEventListener('message', handleMessage as EventListener);\r\n\r\n const closePoll = window.setInterval(() => {\r\n if (!popup.closed) return;\r\n if (cleaned) return;\r\n const pending = sessionStorage.getItem(STATE_KEY_STORAGE);\r\n if (!pending) return;\r\n fail(new PopupClosedError());\r\n }, 280);\r\n });\r\n}\r\n\r\nfunction randomBase64State(): string {\r\n return base64UrlEncode(bytesBuffer(32));\r\n}\r\n\r\nfunction normalizeBaseUrl(s: string): URL {\r\n return new URL(s);\r\n}\r\n\r\n/** Center popup over the opener window (falls back to screen center). */\r\nfunction popupWindowFeatures(width: number, height: number): string {\r\n const win = window;\r\n const outerW = win.outerWidth > 0 ? win.outerWidth : win.innerWidth;\r\n const outerH = win.outerHeight > 0 ? win.outerHeight : win.innerHeight;\r\n const screenX = win.screenX ?? win.screenLeft ?? 0;\r\n const screenY = win.screenY ?? win.screenTop ?? 0;\r\n const left = Math.round(screenX + Math.max(0, (outerW - width) / 2));\r\n const top = Math.round(screenY + Math.max(0, (outerH - height) / 2));\r\n return `width=${width},height=${height},left=${left},top=${top},resizable=yes,scrollbars=yes`;\r\n}\r\n\r\n/** True when Auth-Server has no active browser session for silent sign-in. */\r\nexport function isLoginRequiredError(error: unknown): boolean {\r\n return error instanceof XSAuthDeniedError && error.errorCode === 'login_required';\r\n}\r\n","/** Popup was blocked by the browser or environment. */\r\nexport class PopupBlockedError extends Error {\r\n readonly name = 'PopupBlockedError';\r\n}\r\n\r\n/** User closed the popup before completing login. */\r\nexport class PopupClosedError extends Error {\r\n readonly name = 'PopupClosedError';\r\n}\r\n\r\n/** XS Auth popup did not complete within timeout. */\r\nexport class LoginTimeoutError extends Error {\r\n readonly name = 'LoginTimeoutError';\r\n}\r\n\r\n/** XS Auth returned an OAuth-style error inside postMessage. */\r\nexport class XSAuthDeniedError extends Error {\r\n readonly name = 'XSAuthDeniedError';\r\n readonly errorCode: string;\r\n readonly description: string;\r\n\r\n constructor(errorCode: string, description: string) {\r\n super(description || errorCode || 'xs_auth_denied');\r\n this.errorCode = errorCode;\r\n this.description = description;\r\n }\r\n}\r\n\r\n/** Session bridge did not respond within timeout. */\r\nexport class LoginBridgeTimeoutError extends Error {\r\n readonly name = 'LoginBridgeTimeoutError';\r\n}\r\n","import {\r\n LoginBridgeTimeoutError,\r\n PopupBlockedError,\r\n PopupClosedError,\r\n} from './errors';\r\n\r\n/** XS Auth browser session account (multi-account SSO on the Auth-Server domain). */\r\nexport interface XSBrowserAccount {\r\n sessionId: string;\r\n userId: string;\r\n email: string;\r\n name: string;\r\n isPrimary: boolean;\r\n}\r\n\r\nexport interface OpenSessionBridgeOptions {\r\n clientId: string;\r\n parentOrigin?: string;\r\n timeoutMs?: number;\r\n}\r\n\r\nexport interface SessionBridge {\r\n listAccounts(): Promise<XSBrowserAccount[]>;\r\n revokeAccount(sessionId: string): Promise<{ accounts: XSBrowserAccount[]; remainingCount: number }>;\r\n revokeAll(): Promise<void>;\r\n setPrimary(sessionId: string): Promise<XSBrowserAccount[]>;\r\n close(): void;\r\n}\r\n\r\nexport class SessionBridgeError extends Error {\r\n readonly name = 'SessionBridgeError';\r\n readonly errorCode: string;\r\n\r\n constructor(errorCode: string, message: string) {\r\n super(message || errorCode);\r\n this.errorCode = errorCode;\r\n }\r\n}\r\n\r\ntype BridgeMessage = Partial<Record<string, unknown>>;\r\n\r\nconst BRIDGE_STATE_KEY = '__xs_bridge_state';\r\n\r\nfunction parseAccounts(raw: unknown): XSBrowserAccount[] {\r\n if (!Array.isArray(raw)) return [];\r\n return raw\r\n .map((item) => {\r\n if (!item || typeof item !== 'object') return null;\r\n const row = item as Record<string, unknown>;\r\n const sessionId =\r\n typeof row.sessionId === 'string'\r\n ? row.sessionId\r\n : typeof row.session_id === 'string'\r\n ? row.session_id\r\n : '';\r\n const userId =\r\n typeof row.userId === 'string'\r\n ? row.userId\r\n : typeof row.user_id === 'string'\r\n ? row.user_id\r\n : '';\r\n const email = typeof row.email === 'string' ? row.email : '';\r\n const name = typeof row.name === 'string' ? row.name : email;\r\n if (!sessionId || !email) return null;\r\n return {\r\n sessionId,\r\n userId,\r\n email,\r\n name,\r\n isPrimary: row.isPrimary === true || row.is_primary === true,\r\n };\r\n })\r\n .filter((x): x is XSBrowserAccount => x !== null);\r\n}\r\n\r\nfunction hiddenBridgePopupFeatures(): string {\r\n return 'width=1,height=1,left=-10000,top=-10000,resizable=no,scrollbars=no';\r\n}\r\n\r\nfunction randomBridgeState(): string {\r\n const bytes = new Uint8Array(32);\r\n crypto.getRandomValues(bytes);\r\n let binary = '';\r\n for (let i = 0; i < bytes.length; i++) {\r\n binary += String.fromCharCode(bytes[i]!);\r\n }\r\n return btoa(binary).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/u, '');\r\n}\r\n\r\n/**\r\n * Opens a same-origin Auth-Server popup bridge so the host app can list and revoke\r\n * browser SSO sessions without cross-origin cookie access.\r\n */\r\nexport async function openSessionBridge(\r\n opts: OpenSessionBridgeOptions,\r\n authBaseUrl: string,\r\n): Promise<SessionBridge> {\r\n const parentOrigin = (opts.parentOrigin ?? globalThis.location?.origin) as string | undefined;\r\n if (!parentOrigin || typeof window === 'undefined') {\r\n throw new Error(\r\n 'openSessionBridge requires a browser Window and explicit parentOrigin (or window.location).',\r\n );\r\n }\r\n\r\n const normalizedBase = new URL(authBaseUrl);\r\n const authOrigin = normalizedBase.origin;\r\n const state = randomBridgeState();\r\n sessionStorage.setItem(BRIDGE_STATE_KEY, state);\r\n\r\n const params = new URLSearchParams({\r\n client_id: opts.clientId,\r\n parent_origin: parentOrigin,\r\n state,\r\n });\r\n\r\n const bridgeUrl = `${normalizedBase.href.replace(/\\/?$/u, '')}/session/bridge?${params.toString()}`;\r\n const popup = window.open(\r\n bridgeUrl,\r\n `xs-auth-bridge-${crypto.randomUUID()}`,\r\n hiddenBridgePopupFeatures(),\r\n );\r\n if (!popup) throw new PopupBlockedError();\r\n\r\n const timeoutMs = opts.timeoutMs !== undefined ? opts.timeoutMs : 120_000;\r\n let cleaned = false;\r\n let closePoll: ReturnType<typeof setInterval> | undefined;\r\n\r\n const teardown = (): void => {\r\n if (cleaned) return;\r\n cleaned = true;\r\n window.removeEventListener('message', handleMessage as EventListener);\r\n if (closePoll !== undefined) clearInterval(closePoll);\r\n sessionStorage.removeItem(BRIDGE_STATE_KEY);\r\n try {\r\n popup.close();\r\n } catch {\r\n // ignore\r\n }\r\n };\r\n\r\n const pending = new Map<\r\n string,\r\n {\r\n resolve: (value: BridgeMessage) => void;\r\n reject: (error: Error) => void;\r\n }\r\n >();\r\n\r\n let bridgeReady = false;\r\n let readyResolve: (() => void) | null = null;\r\n let readyReject: ((error: Error) => void) | null = null;\r\n\r\n const readyPromise = new Promise<void>((resolve, reject) => {\r\n readyResolve = resolve;\r\n readyReject = reject;\r\n });\r\n\r\n const handleMessage = (event: MessageEvent): void => {\r\n if (event.origin !== authOrigin) return;\r\n const d = event.data as BridgeMessage;\r\n if (d?.source !== 'xs-auth') return;\r\n\r\n const st = typeof d.state === 'string' ? d.state : '';\r\n if (!st || st !== sessionStorage.getItem(BRIDGE_STATE_KEY)) return;\r\n\r\n if (d.type === 'bridge_ready') {\r\n bridgeReady = true;\r\n readyResolve?.();\r\n return;\r\n }\r\n\r\n const requestId = typeof d.requestId === 'string' ? d.requestId : '';\r\n if (!requestId) return;\r\n\r\n const entry = pending.get(requestId);\r\n if (!entry) return;\r\n\r\n pending.delete(requestId);\r\n\r\n if (typeof d.error === 'string' && d.error.length > 0) {\r\n entry.reject(\r\n new SessionBridgeError(\r\n String(d.error),\r\n typeof d.error_description === 'string' ? d.error_description : '',\r\n ),\r\n );\r\n return;\r\n }\r\n\r\n if (d.type === 'result') {\r\n entry.resolve(d);\r\n }\r\n };\r\n\r\n window.addEventListener('message', handleMessage as EventListener);\r\n\r\n closePoll = window.setInterval(() => {\r\n if (!popup.closed) return;\r\n if (cleaned) return;\r\n for (const [, entry] of pending) {\r\n entry.reject(new PopupClosedError());\r\n }\r\n pending.clear();\r\n readyReject?.(new PopupClosedError());\r\n teardown();\r\n }, 280);\r\n\r\n const readyTimer = window.setTimeout(() => {\r\n if (bridgeReady) return;\r\n readyReject?.(new LoginBridgeTimeoutError());\r\n teardown();\r\n }, timeoutMs);\r\n\r\n try {\r\n await readyPromise;\r\n } catch (error) {\r\n clearTimeout(readyTimer);\r\n throw error;\r\n }\r\n clearTimeout(readyTimer);\r\n\r\n const sendRequest = (type: string, extra: Record<string, unknown> = {}): Promise<BridgeMessage> => {\r\n if (popup.closed) {\r\n return Promise.reject(new PopupClosedError());\r\n }\r\n\r\n const requestId = crypto.randomUUID();\r\n return new Promise<BridgeMessage>((resolve, reject) => {\r\n const timer = window.setTimeout(() => {\r\n pending.delete(requestId);\r\n reject(new LoginBridgeTimeoutError());\r\n }, timeoutMs);\r\n\r\n pending.set(requestId, {\r\n resolve: (value) => {\r\n clearTimeout(timer);\r\n resolve(value);\r\n },\r\n reject: (error) => {\r\n clearTimeout(timer);\r\n reject(error);\r\n },\r\n });\r\n\r\n try {\r\n popup.postMessage(\r\n {\r\n source: 'xs-auth-opener',\r\n state,\r\n client_id: opts.clientId,\r\n requestId,\r\n type,\r\n ...extra,\r\n },\r\n authOrigin,\r\n );\r\n } catch {\r\n pending.delete(requestId);\r\n clearTimeout(timer);\r\n reject(new SessionBridgeError('post_message_failed', 'Could not reach the session bridge.'));\r\n }\r\n });\r\n };\r\n\r\n return {\r\n async listAccounts() {\r\n const result = await sendRequest('list_accounts');\r\n return parseAccounts(result.accounts);\r\n },\r\n\r\n async revokeAccount(sessionId: string) {\r\n const result = await sendRequest('revoke', { session_id: sessionId.trim() });\r\n const accounts = parseAccounts(result.accounts);\r\n const remainingCount =\r\n typeof result.remainingCount === 'number' ? result.remainingCount : accounts.length;\r\n return { accounts, remainingCount };\r\n },\r\n\r\n async revokeAll() {\r\n await sendRequest('revoke_all');\r\n },\r\n\r\n async setPrimary(sessionId: string) {\r\n const result = await sendRequest('set_primary', { session_id: sessionId.trim() });\r\n return parseAccounts(result.accounts);\r\n },\r\n\r\n close() {\r\n teardown();\r\n },\r\n };\r\n}\r\n\r\n/** True when the user must pick another primary account before signing out. */\r\nexport function isPrimaryAccountError(error: unknown): boolean {\r\n return error instanceof SessionBridgeError && error.errorCode === 'primary_account';\r\n}\r\n","import {\r\n LoginBridgeTimeoutError,\r\n PopupBlockedError,\r\n PopupClosedError,\r\n} from './errors';\r\n\r\nexport interface SignOutWithXSOptions {\r\n clientId: string;\r\n parentOrigin?: string;\r\n /** XS Auth user id (`sub`) for the account active in the host app. */\r\n activeUserId?: string;\r\n timeoutMs?: number;\r\n /** Override Auth-Server base URL (e.g. same-origin `/xs-auth` proxy in local dev). */\r\n authBaseUrl?: string;\r\n}\r\n\r\nexport type SignOutAction = 'revoked_one' | 'revoked_all' | 'cancelled';\r\n\r\nexport interface SignOutWithXSResult {\r\n action: SignOutAction;\r\n revokedCurrent: boolean;\r\n remainingCount: number;\r\n}\r\n\r\nconst SIGN_OUT_STATE_KEY = '__xs_sign_out_state';\r\n\r\nfunction popupWindowFeatures(width: number, height: number): string {\r\n const win = window;\r\n const outerW = win.outerWidth > 0 ? win.outerWidth : win.innerWidth;\r\n const outerH = win.outerHeight > 0 ? win.outerHeight : win.innerHeight;\r\n const screenX = win.screenX ?? win.screenLeft ?? 0;\r\n const screenY = win.screenY ?? win.screenTop ?? 0;\r\n const left = Math.round(screenX + Math.max(0, (outerW - width) / 2));\r\n const top = Math.round(screenY + Math.max(0, (outerH - height) / 2));\r\n return `width=${width},height=${height},left=${left},top=${top},resizable=yes,scrollbars=yes`;\r\n}\r\n\r\nfunction randomState(): string {\r\n const bytes = new Uint8Array(32);\r\n crypto.getRandomValues(bytes);\r\n let binary = '';\r\n for (let i = 0; i < bytes.length; i++) {\r\n binary += String.fromCharCode(bytes[i]!);\r\n }\r\n return btoa(binary).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/u, '');\r\n}\r\n\r\nfunction parseSignOutResult(raw: SignOutAction, data: Record<string, unknown>): SignOutWithXSResult {\r\n return {\r\n action: raw,\r\n revokedCurrent: data.revokedCurrent === true,\r\n remainingCount:\r\n typeof data.remainingCount === 'number' && Number.isFinite(data.remainingCount)\r\n ? Math.max(0, data.remainingCount)\r\n : 0,\r\n };\r\n}\r\n\r\n/**\r\n * Opens a centered XS Auth popup to sign out of one or all browser SSO accounts\r\n * (Google-style account manager on the Auth-Server domain).\r\n */\r\nexport async function signOutWithXS(\r\n opts: SignOutWithXSOptions,\r\n authBaseUrl: string,\r\n): Promise<SignOutWithXSResult> {\r\n const parentOrigin = (opts.parentOrigin ?? globalThis.location?.origin) as string | undefined;\r\n if (!parentOrigin || typeof window === 'undefined') {\r\n throw new Error(\r\n 'signOutWithXS requires a browser Window and explicit parentOrigin (or window.location).',\r\n );\r\n }\r\n\r\n const normalizedBase = new URL(authBaseUrl);\r\n const authOrigin = normalizedBase.origin;\r\n const state = randomState();\r\n sessionStorage.setItem(SIGN_OUT_STATE_KEY, state);\r\n\r\n const params = new URLSearchParams({\r\n client_id: opts.clientId,\r\n parent_origin: parentOrigin,\r\n state,\r\n });\r\n if (opts.activeUserId?.trim()) {\r\n params.set('active_user_id', opts.activeUserId.trim());\r\n }\r\n\r\n const url = `${normalizedBase.href.replace(/\\/?$/u, '')}/session/sign-out?${params.toString()}`;\r\n const popup = window.open(\r\n url,\r\n `xs-auth-signout-${crypto.randomUUID()}`,\r\n popupWindowFeatures(480, 640),\r\n );\r\n if (!popup) throw new PopupBlockedError();\r\n\r\n const timeoutMs = opts.timeoutMs !== undefined ? opts.timeoutMs : 120_000;\r\n\r\n return await new Promise<SignOutWithXSResult>((resolve, reject) => {\r\n let cleaned = false;\r\n\r\n const teardown = (): void => {\r\n if (cleaned) return;\r\n cleaned = true;\r\n window.removeEventListener('message', handleMessage as EventListener);\r\n clearInterval(closePoll);\r\n clearTimeout(timer);\r\n sessionStorage.removeItem(SIGN_OUT_STATE_KEY);\r\n try {\r\n popup.close();\r\n } catch {\r\n // ignore\r\n }\r\n };\r\n\r\n const fail = (error: Error): void => {\r\n teardown();\r\n reject(error);\r\n };\r\n\r\n const timer = window.setTimeout(() => {\r\n fail(new LoginBridgeTimeoutError());\r\n }, timeoutMs);\r\n\r\n const handleMessage = (event: MessageEvent): void => {\r\n if (event.origin !== authOrigin) return;\r\n const d = event.data as Partial<Record<string, unknown>>;\r\n if (d?.source !== 'xs-auth') return;\r\n\r\n const st = typeof d.state === 'string' ? d.state : '';\r\n if (!st || st !== sessionStorage.getItem(SIGN_OUT_STATE_KEY)) return;\r\n\r\n if (d.type === 'sign_out_cancelled') {\r\n teardown();\r\n resolve(parseSignOutResult('cancelled', d));\r\n return;\r\n }\r\n\r\n if (d.type === 'sign_out_complete') {\r\n teardown();\r\n const actionRaw = typeof d.action === 'string' ? d.action : 'revoked_one';\r\n const action: SignOutAction =\r\n actionRaw === 'revoked_all'\r\n ? 'revoked_all'\r\n : actionRaw === 'cancelled'\r\n ? 'cancelled'\r\n : 'revoked_one';\r\n resolve(parseSignOutResult(action, d));\r\n }\r\n };\r\n\r\n window.addEventListener('message', handleMessage as EventListener);\r\n\r\n const closePoll = window.setInterval(() => {\r\n if (!popup.closed) return;\r\n if (cleaned) return;\r\n if (!sessionStorage.getItem(SIGN_OUT_STATE_KEY)) return;\r\n fail(new PopupClosedError());\r\n }, 280);\r\n });\r\n}\r\n"],"mappings":"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","names":["openSessionBridge","signOutWithXS","openSessionBridge","signOutWithXS","popupWindowFeatures"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/errors.ts","../src/session-bridge.ts","../src/sign-out.ts"],"sourcesContent":["import {\r\n LoginTimeoutError,\r\n PopupBlockedError,\r\n PopupClosedError,\r\n XSAuthDeniedError,\r\n} from './errors';\r\nimport {\r\n isPrimaryAccountError,\r\n openSessionBridge as openSessionBridgeInternal,\r\n SessionBridgeError,\r\n type OpenSessionBridgeOptions,\r\n type SessionBridge,\r\n type XSBrowserAccount,\r\n} from './session-bridge';\r\n\r\nimport {\r\n signOutWithXS as signOutWithXSInternal,\r\n type SignOutAction,\r\n type SignOutWithXSOptions,\r\n type SignOutWithXSResult,\r\n} from './sign-out';\r\n\r\nexport {\r\n LoginBridgeTimeoutError,\r\n LoginTimeoutError,\r\n PopupBlockedError,\r\n PopupClosedError,\r\n XSAuthDeniedError,\r\n} from './errors';\r\n\r\nexport {\r\n isPrimaryAccountError,\r\n SessionBridgeError,\r\n type OpenSessionBridgeOptions,\r\n type SessionBridge,\r\n type XSBrowserAccount,\r\n};\r\n\r\nexport {\r\n type SignOutAction,\r\n type SignOutWithXSOptions,\r\n type SignOutWithXSResult,\r\n};\r\n\r\n/** XS Auth server — baked in at build time (local vs production). */\r\nconst XS_AUTH_BASE_URL = __XS_AUTH_BASE_URL__;\r\n\r\n/** Opens the Auth-Server session bridge popup (multi-account sign-out). */\r\nexport function openSessionBridge(\r\n opts: OpenSessionBridgeOptions,\r\n): Promise<SessionBridge> {\r\n return openSessionBridgeInternal(opts, XS_AUTH_BASE_URL);\r\n}\r\n\r\n/** Google-style sign-out popup on the Auth-Server domain. */\r\nexport function signOutWithXS(opts: SignOutWithXSOptions): Promise<SignOutWithXSResult> {\r\n const authBase = opts.authBaseUrl?.trim() || XS_AUTH_BASE_URL;\r\n return signOutWithXSInternal(opts, authBase);\r\n}\r\n\r\n/** Signed-in user profile from XS Auth. */\r\nexport interface XSAuthUser {\r\n email: string;\r\n firstName?: string;\r\n lastName?: string;\r\n}\r\n\r\nexport interface LoginWithXSOptions {\r\n /** Your app's public client id from Xino Solutions. */\r\n clientId: string;\r\n /** Must be on your XS Auth client's allowed domains list (normally `window.location.origin`). */\r\n parentOrigin?: string;\r\n /**\r\n * Sign-in timeout in ms. Defaults to 180s to allow MFA verification in the Auth-Server popup.\r\n */\r\n timeoutMs?: number;\r\n scope?: string;\r\n /**\r\n * Request a `nonce` inside `idToken` — your backend should verify it matches when validating the JWT.\r\n */\r\n useNonce?: boolean;\r\n /**\r\n * OAuth-style prompt for multi-account SSO on the Auth-Server domain.\r\n * - `none`: silent sign-in with the primary browser session (fails with `login_required` if absent)\r\n * - `select_account`: always show the account chooser when sessions exist\r\n * - `login`: force email/password (add another account)\r\n */\r\n prompt?: 'none' | 'select_account' | 'login';\r\n /** Prefer a specific XS Auth user id (`sub`) when continuing an existing browser session. */\r\n accountId?: string;\r\n /** When true and `prompt` is unset, defaults to `none` instead of account chooser. */\r\n preferPrimary?: boolean;\r\n /** Override Auth-Server base URL (e.g. same-origin `/xs-auth` proxy in local dev). */\r\n authBaseUrl?: string;\r\n}\r\n\r\nexport interface LoginWithXSResult {\r\n user: XSAuthUser;\r\n /** Short-lived signed JWT — send to your backend to create a session. */\r\n idToken: string;\r\n /** True when the user completed MFA during this sign-in (`amr` includes `mfa`). */\r\n mfaVerified: boolean;\r\n}\r\n\r\nfunction bytesBuffer(len: number): Uint8Array {\r\n const out = new Uint8Array(len);\r\n crypto.getRandomValues(out);\r\n return out;\r\n}\r\n\r\nfunction base64UrlEncode(buf: Uint8Array | ArrayBuffer): string {\r\n const bytes = buf instanceof Uint8Array ? buf : new Uint8Array(buf);\r\n let binary = '';\r\n const chunkSize = 0x8000;\r\n for (let i = 0; i < bytes.length; i += chunkSize) {\r\n binary += String.fromCharCode(...bytes.subarray(i, i + chunkSize));\r\n }\r\n const b64 = btoa(binary);\r\n return b64.replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/u, '');\r\n}\r\n\r\nasync function pkceVerifierAndChallenge(): Promise<{\r\n verifier: string;\r\n challenge: string;\r\n}> {\r\n const verifier = base64UrlEncode(bytesBuffer(64));\r\n const data = new TextEncoder().encode(verifier);\r\n const digest = await crypto.subtle.digest('SHA-256', data);\r\n const challenge = base64UrlEncode(digest);\r\n return { verifier, challenge };\r\n}\r\n\r\n/** PKCE helpers for tests / custom callers. */\r\nexport async function createPkcePair(): Promise<{\r\n verifier: string;\r\n challenge: string;\r\n}> {\r\n return pkceVerifierAndChallenge();\r\n}\r\n\r\nconst STATE_KEY_STORAGE = '__xs_login_state';\r\n\r\nfunction parseSdkUser(raw: unknown): XSAuthUser | null {\r\n if (!raw || typeof raw !== 'object') return null;\r\n const u = raw as Record<string, unknown>;\r\n const email = typeof u.email === 'string' ? u.email.trim() : '';\r\n if (!email) return null;\r\n const user: XSAuthUser = { email };\r\n const firstName =\r\n typeof u.firstName === 'string' ? u.firstName.trim() : '';\r\n const lastName = typeof u.lastName === 'string' ? u.lastName.trim() : '';\r\n if (firstName) user.firstName = firstName;\r\n if (lastName) user.lastName = lastName;\r\n return user;\r\n}\r\n\r\nfunction resolvePrompt(opts: LoginWithXSOptions): string | undefined {\r\n if (opts.prompt) return opts.prompt;\r\n if (opts.preferPrimary) return 'none';\r\n return undefined;\r\n}\r\n\r\nfunction authPublicPathFromBase(authBaseUrl: string): string {\r\n try {\r\n const pathname = new URL(authBaseUrl).pathname.replace(/\\/$/u, '');\r\n return pathname === '/' ? '' : pathname;\r\n } catch {\r\n return '';\r\n }\r\n}\r\n\r\nfunction maybeSetPublicPath(params: URLSearchParams, authBaseUrl: string): void {\r\n const publicPath = authPublicPathFromBase(authBaseUrl);\r\n if (publicPath) params.set('public_path', publicPath);\r\n}\r\n\r\n/**\r\n * Opens the XS Auth sign-in popup and returns the signed-in user plus a verifiable `idToken`.\r\n *\r\n * All Auth-Server HTTP calls happen inside the popup (same origin). The host app only\r\n * opens the popup and exchanges postMessages with the PKCE verifier — no fetch to Auth-Server.\r\n */\r\nexport async function loginWithXS(\r\n opts: LoginWithXSOptions,\r\n): Promise<LoginWithXSResult> {\r\n const authBase = opts.authBaseUrl?.trim() || XS_AUTH_BASE_URL;\r\n const normalizedBase = normalizeBaseUrl(authBase);\r\n const authOrigin = normalizedBase.origin;\r\n const parentOrigin = (opts.parentOrigin ?? globalThis.location?.origin) as\r\n | string\r\n | undefined;\r\n if (!parentOrigin || typeof window === 'undefined') {\r\n throw new Error(\r\n 'loginWithXS requires a browser Window and explicit parentOrigin (or window.location).',\r\n );\r\n }\r\n\r\n const timeoutMs =\r\n opts.timeoutMs !== undefined ? opts.timeoutMs : 180_000;\r\n\r\n const state = randomBase64State();\r\n sessionStorage.setItem(STATE_KEY_STORAGE, state);\r\n\r\n const nonce = opts.useNonce ? randomBase64State() : undefined;\r\n const pair = await pkceVerifierAndChallenge();\r\n\r\n const params = new URLSearchParams({\r\n client_id: opts.clientId,\r\n state,\r\n code_challenge: pair.challenge,\r\n code_challenge_method: 'S256',\r\n parent_origin: parentOrigin,\r\n response_mode: 'popup',\r\n });\r\n if (opts.scope?.trim()) params.set('scope', opts.scope.trim());\r\n if (nonce) params.set('nonce', nonce);\r\n const prompt = resolvePrompt(opts);\r\n if (prompt) params.set('prompt', prompt);\r\n if (opts.accountId?.trim()) params.set('account_id', opts.accountId.trim());\r\n maybeSetPublicPath(params, authBase);\r\n\r\n const authorizeUrl = `${normalizedBase.href.replace(/\\/?$/u, '')}/authorize?${params.toString()}`;\r\n\r\n const popupWidth = prompt === 'none' ? 420 : 480;\r\n const popupHeight = prompt === 'none' ? 120 : 640;\r\n const popup = window.open(\r\n authorizeUrl,\r\n `xs-auth-${crypto.randomUUID()}`,\r\n popupWindowFeatures(popupWidth, popupHeight),\r\n );\r\n if (!popup) throw new PopupBlockedError();\r\n\r\n return await new Promise<LoginWithXSResult>((resolve, reject) => {\r\n let cleaned = false;\r\n const teardown = (): void => {\r\n if (cleaned) return;\r\n cleaned = true;\r\n window.removeEventListener('message', handleMessage as EventListener);\r\n clearInterval(closePoll);\r\n clearTimeout(timer);\r\n try {\r\n popup.close();\r\n } catch {\r\n // ignore\r\n }\r\n };\r\n\r\n const fail = (e: unknown): void => {\r\n teardown();\r\n reject(e instanceof Error ? e : new Error(String(e)));\r\n };\r\n\r\n const timer = window.setTimeout(() => {\r\n fail(new LoginTimeoutError());\r\n }, timeoutMs);\r\n\r\n const handleMessage = (event: MessageEvent): void => {\r\n if (event.origin !== authOrigin) return;\r\n const d = event.data as Partial<Record<string, unknown>>;\r\n if (d?.source !== 'xs-auth') return;\r\n\r\n const st = typeof d.state === 'string' ? d.state : '';\r\n if (!st || st !== sessionStorage.getItem(STATE_KEY_STORAGE)) return;\r\n\r\n if (typeof d.error === 'string' && d.error.length > 0) {\r\n teardown();\r\n reject(\r\n new XSAuthDeniedError(\r\n String(d.error),\r\n typeof d.error_description === 'string'\r\n ? d.error_description\r\n : '',\r\n ),\r\n );\r\n return;\r\n }\r\n\r\n if (d.type === 'need_verifier') {\r\n try {\r\n popup.postMessage(\r\n {\r\n source: 'xs-auth-opener',\r\n state: st,\r\n code_verifier: pair.verifier,\r\n client_id: opts.clientId,\r\n },\r\n authOrigin,\r\n );\r\n } catch {\r\n fail(new XSAuthDeniedError('exchange_failed', 'Sign in could not be completed.'));\r\n }\r\n return;\r\n }\r\n\r\n const idToken =\r\n typeof d.id_token === 'string'\r\n ? d.id_token\r\n : typeof d.idToken === 'string'\r\n ? d.idToken\r\n : '';\r\n const user = parseSdkUser(d.user);\r\n if (!idToken || !user) return;\r\n\r\n sessionStorage.removeItem(STATE_KEY_STORAGE);\r\n clearTimeout(timer);\r\n window.removeEventListener('message', handleMessage as EventListener);\r\n clearInterval(closePoll);\r\n cleaned = true;\r\n\r\n resolve({ user, idToken, mfaVerified: idTokenIncludesMfa(idToken) });\r\n\r\n try {\r\n popup.close();\r\n } catch {\r\n // ignore\r\n }\r\n };\r\n\r\n window.addEventListener('message', handleMessage as EventListener);\r\n\r\n const closePoll = window.setInterval(() => {\r\n if (!popup.closed) return;\r\n if (cleaned) return;\r\n const pending = sessionStorage.getItem(STATE_KEY_STORAGE);\r\n if (!pending) return;\r\n fail(new PopupClosedError());\r\n }, 280);\r\n });\r\n}\r\n\r\n/** True when an XS Auth idToken indicates MFA was completed at sign-in. */\r\nexport function idTokenIncludesMfa(idToken: string): boolean {\r\n const amr = parseIdTokenAmr(idToken);\r\n return Array.isArray(amr) && amr.includes('mfa');\r\n}\r\n\r\n/** Read the `amr` claim from an XS Auth idToken payload (no signature verification). */\r\nexport function parseIdTokenAmr(idToken: string): string[] | null {\r\n const payload = parseJwtPayload(idToken);\r\n if (!payload || !('amr' in payload)) return null;\r\n const amr = payload.amr;\r\n if (Array.isArray(amr)) {\r\n return amr.filter((v): v is string => typeof v === 'string');\r\n }\r\n if (typeof amr === 'string' && amr.trim()) return [amr.trim()];\r\n return null;\r\n}\r\n\r\nfunction parseJwtPayload(token: string): Record<string, unknown> | null {\r\n const parts = token.split('.');\r\n if (parts.length < 2) return null;\r\n try {\r\n const json = atob(parts[1].replace(/-/g, '+').replace(/_/g, '/'));\r\n const parsed: unknown = JSON.parse(json);\r\n return parsed && typeof parsed === 'object' ? (parsed as Record<string, unknown>) : null;\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\nfunction randomBase64State(): string {\r\n return base64UrlEncode(bytesBuffer(32));\r\n}\r\n\r\nfunction normalizeBaseUrl(s: string): URL {\r\n return new URL(s);\r\n}\r\n\r\n/** Center popup over the opener window (falls back to screen center). */\r\nfunction popupWindowFeatures(width: number, height: number): string {\r\n const win = window;\r\n const outerW = win.outerWidth > 0 ? win.outerWidth : win.innerWidth;\r\n const outerH = win.outerHeight > 0 ? win.outerHeight : win.innerHeight;\r\n const screenX = win.screenX ?? win.screenLeft ?? 0;\r\n const screenY = win.screenY ?? win.screenTop ?? 0;\r\n const left = Math.round(screenX + Math.max(0, (outerW - width) / 2));\r\n const top = Math.round(screenY + Math.max(0, (outerH - height) / 2));\r\n return `width=${width},height=${height},left=${left},top=${top},resizable=yes,scrollbars=yes`;\r\n}\r\n\r\n/** True when Auth-Server has no active browser session for silent sign-in. */\r\nexport function isLoginRequiredError(error: unknown): boolean {\r\n return error instanceof XSAuthDeniedError && error.errorCode === 'login_required';\r\n}\r\n","/** Popup was blocked by the browser or environment. */\r\nexport class PopupBlockedError extends Error {\r\n readonly name = 'PopupBlockedError';\r\n}\r\n\r\n/** User closed the popup before completing login. */\r\nexport class PopupClosedError extends Error {\r\n readonly name = 'PopupClosedError';\r\n}\r\n\r\n/** XS Auth popup did not complete within timeout. */\r\nexport class LoginTimeoutError extends Error {\r\n readonly name = 'LoginTimeoutError';\r\n}\r\n\r\n/** XS Auth returned an OAuth-style error inside postMessage. */\r\nexport class XSAuthDeniedError extends Error {\r\n readonly name = 'XSAuthDeniedError';\r\n readonly errorCode: string;\r\n readonly description: string;\r\n\r\n constructor(errorCode: string, description: string) {\r\n super(description || errorCode || 'xs_auth_denied');\r\n this.errorCode = errorCode;\r\n this.description = description;\r\n }\r\n}\r\n\r\n/** Session bridge did not respond within timeout. */\r\nexport class LoginBridgeTimeoutError extends Error {\r\n readonly name = 'LoginBridgeTimeoutError';\r\n}\r\n","import {\r\n LoginBridgeTimeoutError,\r\n PopupBlockedError,\r\n PopupClosedError,\r\n} from './errors';\r\n\r\n/** XS Auth browser session account (multi-account SSO on the Auth-Server domain). */\r\nexport interface XSBrowserAccount {\r\n sessionId: string;\r\n userId: string;\r\n email: string;\r\n name: string;\r\n isPrimary: boolean;\r\n}\r\n\r\nexport interface OpenSessionBridgeOptions {\r\n clientId: string;\r\n parentOrigin?: string;\r\n timeoutMs?: number;\r\n}\r\n\r\nexport interface SessionBridge {\r\n listAccounts(): Promise<XSBrowserAccount[]>;\r\n revokeAccount(sessionId: string): Promise<{ accounts: XSBrowserAccount[]; remainingCount: number }>;\r\n revokeAll(): Promise<void>;\r\n setPrimary(sessionId: string): Promise<XSBrowserAccount[]>;\r\n close(): void;\r\n}\r\n\r\nexport class SessionBridgeError extends Error {\r\n readonly name = 'SessionBridgeError';\r\n readonly errorCode: string;\r\n\r\n constructor(errorCode: string, message: string) {\r\n super(message || errorCode);\r\n this.errorCode = errorCode;\r\n }\r\n}\r\n\r\ntype BridgeMessage = Partial<Record<string, unknown>>;\r\n\r\nconst BRIDGE_STATE_KEY = '__xs_bridge_state';\r\n\r\nfunction parseAccounts(raw: unknown): XSBrowserAccount[] {\r\n if (!Array.isArray(raw)) return [];\r\n return raw\r\n .map((item) => {\r\n if (!item || typeof item !== 'object') return null;\r\n const row = item as Record<string, unknown>;\r\n const sessionId =\r\n typeof row.sessionId === 'string'\r\n ? row.sessionId\r\n : typeof row.session_id === 'string'\r\n ? row.session_id\r\n : '';\r\n const userId =\r\n typeof row.userId === 'string'\r\n ? row.userId\r\n : typeof row.user_id === 'string'\r\n ? row.user_id\r\n : '';\r\n const email = typeof row.email === 'string' ? row.email : '';\r\n const name = typeof row.name === 'string' ? row.name : email;\r\n if (!sessionId || !email) return null;\r\n return {\r\n sessionId,\r\n userId,\r\n email,\r\n name,\r\n isPrimary: row.isPrimary === true || row.is_primary === true,\r\n };\r\n })\r\n .filter((x): x is XSBrowserAccount => x !== null);\r\n}\r\n\r\nfunction hiddenBridgePopupFeatures(): string {\r\n return 'width=1,height=1,left=-10000,top=-10000,resizable=no,scrollbars=no';\r\n}\r\n\r\nfunction randomBridgeState(): string {\r\n const bytes = new Uint8Array(32);\r\n crypto.getRandomValues(bytes);\r\n let binary = '';\r\n for (let i = 0; i < bytes.length; i++) {\r\n binary += String.fromCharCode(bytes[i]!);\r\n }\r\n return btoa(binary).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/u, '');\r\n}\r\n\r\n/**\r\n * Opens a same-origin Auth-Server popup bridge so the host app can list and revoke\r\n * browser SSO sessions without cross-origin cookie access.\r\n */\r\nexport async function openSessionBridge(\r\n opts: OpenSessionBridgeOptions,\r\n authBaseUrl: string,\r\n): Promise<SessionBridge> {\r\n const parentOrigin = (opts.parentOrigin ?? globalThis.location?.origin) as string | undefined;\r\n if (!parentOrigin || typeof window === 'undefined') {\r\n throw new Error(\r\n 'openSessionBridge requires a browser Window and explicit parentOrigin (or window.location).',\r\n );\r\n }\r\n\r\n const normalizedBase = new URL(authBaseUrl);\r\n const authOrigin = normalizedBase.origin;\r\n const state = randomBridgeState();\r\n sessionStorage.setItem(BRIDGE_STATE_KEY, state);\r\n\r\n const params = new URLSearchParams({\r\n client_id: opts.clientId,\r\n parent_origin: parentOrigin,\r\n state,\r\n });\r\n\r\n const bridgeUrl = `${normalizedBase.href.replace(/\\/?$/u, '')}/session/bridge?${params.toString()}`;\r\n const popup = window.open(\r\n bridgeUrl,\r\n `xs-auth-bridge-${crypto.randomUUID()}`,\r\n hiddenBridgePopupFeatures(),\r\n );\r\n if (!popup) throw new PopupBlockedError();\r\n\r\n const timeoutMs = opts.timeoutMs !== undefined ? opts.timeoutMs : 120_000;\r\n let cleaned = false;\r\n let closePoll: ReturnType<typeof setInterval> | undefined;\r\n\r\n const teardown = (): void => {\r\n if (cleaned) return;\r\n cleaned = true;\r\n window.removeEventListener('message', handleMessage as EventListener);\r\n if (closePoll !== undefined) clearInterval(closePoll);\r\n sessionStorage.removeItem(BRIDGE_STATE_KEY);\r\n try {\r\n popup.close();\r\n } catch {\r\n // ignore\r\n }\r\n };\r\n\r\n const pending = new Map<\r\n string,\r\n {\r\n resolve: (value: BridgeMessage) => void;\r\n reject: (error: Error) => void;\r\n }\r\n >();\r\n\r\n let bridgeReady = false;\r\n let readyResolve: (() => void) | null = null;\r\n let readyReject: ((error: Error) => void) | null = null;\r\n\r\n const readyPromise = new Promise<void>((resolve, reject) => {\r\n readyResolve = resolve;\r\n readyReject = reject;\r\n });\r\n\r\n const handleMessage = (event: MessageEvent): void => {\r\n if (event.origin !== authOrigin) return;\r\n const d = event.data as BridgeMessage;\r\n if (d?.source !== 'xs-auth') return;\r\n\r\n const st = typeof d.state === 'string' ? d.state : '';\r\n if (!st || st !== sessionStorage.getItem(BRIDGE_STATE_KEY)) return;\r\n\r\n if (d.type === 'bridge_ready') {\r\n bridgeReady = true;\r\n readyResolve?.();\r\n return;\r\n }\r\n\r\n const requestId = typeof d.requestId === 'string' ? d.requestId : '';\r\n if (!requestId) return;\r\n\r\n const entry = pending.get(requestId);\r\n if (!entry) return;\r\n\r\n pending.delete(requestId);\r\n\r\n if (typeof d.error === 'string' && d.error.length > 0) {\r\n entry.reject(\r\n new SessionBridgeError(\r\n String(d.error),\r\n typeof d.error_description === 'string' ? d.error_description : '',\r\n ),\r\n );\r\n return;\r\n }\r\n\r\n if (d.type === 'result') {\r\n entry.resolve(d);\r\n }\r\n };\r\n\r\n window.addEventListener('message', handleMessage as EventListener);\r\n\r\n closePoll = window.setInterval(() => {\r\n if (!popup.closed) return;\r\n if (cleaned) return;\r\n for (const [, entry] of pending) {\r\n entry.reject(new PopupClosedError());\r\n }\r\n pending.clear();\r\n readyReject?.(new PopupClosedError());\r\n teardown();\r\n }, 280);\r\n\r\n const readyTimer = window.setTimeout(() => {\r\n if (bridgeReady) return;\r\n readyReject?.(new LoginBridgeTimeoutError());\r\n teardown();\r\n }, timeoutMs);\r\n\r\n try {\r\n await readyPromise;\r\n } catch (error) {\r\n clearTimeout(readyTimer);\r\n throw error;\r\n }\r\n clearTimeout(readyTimer);\r\n\r\n const sendRequest = (type: string, extra: Record<string, unknown> = {}): Promise<BridgeMessage> => {\r\n if (popup.closed) {\r\n return Promise.reject(new PopupClosedError());\r\n }\r\n\r\n const requestId = crypto.randomUUID();\r\n return new Promise<BridgeMessage>((resolve, reject) => {\r\n const timer = window.setTimeout(() => {\r\n pending.delete(requestId);\r\n reject(new LoginBridgeTimeoutError());\r\n }, timeoutMs);\r\n\r\n pending.set(requestId, {\r\n resolve: (value) => {\r\n clearTimeout(timer);\r\n resolve(value);\r\n },\r\n reject: (error) => {\r\n clearTimeout(timer);\r\n reject(error);\r\n },\r\n });\r\n\r\n try {\r\n popup.postMessage(\r\n {\r\n source: 'xs-auth-opener',\r\n state,\r\n client_id: opts.clientId,\r\n requestId,\r\n type,\r\n ...extra,\r\n },\r\n authOrigin,\r\n );\r\n } catch {\r\n pending.delete(requestId);\r\n clearTimeout(timer);\r\n reject(new SessionBridgeError('post_message_failed', 'Could not reach the session bridge.'));\r\n }\r\n });\r\n };\r\n\r\n return {\r\n async listAccounts() {\r\n const result = await sendRequest('list_accounts');\r\n return parseAccounts(result.accounts);\r\n },\r\n\r\n async revokeAccount(sessionId: string) {\r\n const result = await sendRequest('revoke', { session_id: sessionId.trim() });\r\n const accounts = parseAccounts(result.accounts);\r\n const remainingCount =\r\n typeof result.remainingCount === 'number' ? result.remainingCount : accounts.length;\r\n return { accounts, remainingCount };\r\n },\r\n\r\n async revokeAll() {\r\n await sendRequest('revoke_all');\r\n },\r\n\r\n async setPrimary(sessionId: string) {\r\n const result = await sendRequest('set_primary', { session_id: sessionId.trim() });\r\n return parseAccounts(result.accounts);\r\n },\r\n\r\n close() {\r\n teardown();\r\n },\r\n };\r\n}\r\n\r\n/** True when the user must pick another primary account before signing out. */\r\nexport function isPrimaryAccountError(error: unknown): boolean {\r\n return error instanceof SessionBridgeError && error.errorCode === 'primary_account';\r\n}\r\n","import {\r\n LoginBridgeTimeoutError,\r\n PopupBlockedError,\r\n PopupClosedError,\r\n} from './errors';\r\n\r\nexport interface SignOutWithXSOptions {\r\n clientId: string;\r\n parentOrigin?: string;\r\n /** XS Auth user id (`sub`) for the account active in the host app. */\r\n activeUserId?: string;\r\n timeoutMs?: number;\r\n /** Override Auth-Server base URL (e.g. same-origin `/xs-auth` proxy in local dev). */\r\n authBaseUrl?: string;\r\n}\r\n\r\nexport type SignOutAction = 'revoked_one' | 'revoked_all' | 'cancelled';\r\n\r\nexport interface SignOutWithXSResult {\r\n action: SignOutAction;\r\n revokedCurrent: boolean;\r\n remainingCount: number;\r\n}\r\n\r\nconst SIGN_OUT_STATE_KEY = '__xs_sign_out_state';\r\n\r\nfunction popupWindowFeatures(width: number, height: number): string {\r\n const win = window;\r\n const outerW = win.outerWidth > 0 ? win.outerWidth : win.innerWidth;\r\n const outerH = win.outerHeight > 0 ? win.outerHeight : win.innerHeight;\r\n const screenX = win.screenX ?? win.screenLeft ?? 0;\r\n const screenY = win.screenY ?? win.screenTop ?? 0;\r\n const left = Math.round(screenX + Math.max(0, (outerW - width) / 2));\r\n const top = Math.round(screenY + Math.max(0, (outerH - height) / 2));\r\n return `width=${width},height=${height},left=${left},top=${top},resizable=yes,scrollbars=yes`;\r\n}\r\n\r\nfunction randomState(): string {\r\n const bytes = new Uint8Array(32);\r\n crypto.getRandomValues(bytes);\r\n let binary = '';\r\n for (let i = 0; i < bytes.length; i++) {\r\n binary += String.fromCharCode(bytes[i]!);\r\n }\r\n return btoa(binary).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/u, '');\r\n}\r\n\r\nfunction parseSignOutResult(raw: SignOutAction, data: Record<string, unknown>): SignOutWithXSResult {\r\n return {\r\n action: raw,\r\n revokedCurrent: data.revokedCurrent === true,\r\n remainingCount:\r\n typeof data.remainingCount === 'number' && Number.isFinite(data.remainingCount)\r\n ? Math.max(0, data.remainingCount)\r\n : 0,\r\n };\r\n}\r\n\r\n/**\r\n * Opens a centered XS Auth popup to sign out of one or all browser SSO accounts\r\n * (Google-style account manager on the Auth-Server domain).\r\n */\r\nexport async function signOutWithXS(\r\n opts: SignOutWithXSOptions,\r\n authBaseUrl: string,\r\n): Promise<SignOutWithXSResult> {\r\n const parentOrigin = (opts.parentOrigin ?? globalThis.location?.origin) as string | undefined;\r\n if (!parentOrigin || typeof window === 'undefined') {\r\n throw new Error(\r\n 'signOutWithXS requires a browser Window and explicit parentOrigin (or window.location).',\r\n );\r\n }\r\n\r\n const normalizedBase = new URL(authBaseUrl);\r\n const authOrigin = normalizedBase.origin;\r\n const state = randomState();\r\n sessionStorage.setItem(SIGN_OUT_STATE_KEY, state);\r\n\r\n const params = new URLSearchParams({\r\n client_id: opts.clientId,\r\n parent_origin: parentOrigin,\r\n state,\r\n });\r\n if (opts.activeUserId?.trim()) {\r\n params.set('active_user_id', opts.activeUserId.trim());\r\n }\r\n\r\n const url = `${normalizedBase.href.replace(/\\/?$/u, '')}/session/sign-out?${params.toString()}`;\r\n const popup = window.open(\r\n url,\r\n `xs-auth-signout-${crypto.randomUUID()}`,\r\n popupWindowFeatures(480, 640),\r\n );\r\n if (!popup) throw new PopupBlockedError();\r\n\r\n const timeoutMs = opts.timeoutMs !== undefined ? opts.timeoutMs : 120_000;\r\n\r\n return await new Promise<SignOutWithXSResult>((resolve, reject) => {\r\n let cleaned = false;\r\n\r\n const teardown = (): void => {\r\n if (cleaned) return;\r\n cleaned = true;\r\n window.removeEventListener('message', handleMessage as EventListener);\r\n clearInterval(closePoll);\r\n clearTimeout(timer);\r\n sessionStorage.removeItem(SIGN_OUT_STATE_KEY);\r\n try {\r\n popup.close();\r\n } catch {\r\n // ignore\r\n }\r\n };\r\n\r\n const fail = (error: Error): void => {\r\n teardown();\r\n reject(error);\r\n };\r\n\r\n const timer = window.setTimeout(() => {\r\n fail(new LoginBridgeTimeoutError());\r\n }, timeoutMs);\r\n\r\n const handleMessage = (event: MessageEvent): void => {\r\n if (event.origin !== authOrigin) return;\r\n const d = event.data as Partial<Record<string, unknown>>;\r\n if (d?.source !== 'xs-auth') return;\r\n\r\n const st = typeof d.state === 'string' ? d.state : '';\r\n if (!st || st !== sessionStorage.getItem(SIGN_OUT_STATE_KEY)) return;\r\n\r\n if (d.type === 'sign_out_cancelled') {\r\n teardown();\r\n resolve(parseSignOutResult('cancelled', d));\r\n return;\r\n }\r\n\r\n if (d.type === 'sign_out_complete') {\r\n teardown();\r\n const actionRaw = typeof d.action === 'string' ? d.action : 'revoked_one';\r\n const action: SignOutAction =\r\n actionRaw === 'revoked_all'\r\n ? 'revoked_all'\r\n : actionRaw === 'cancelled'\r\n ? 'cancelled'\r\n : 'revoked_one';\r\n resolve(parseSignOutResult(action, d));\r\n }\r\n };\r\n\r\n window.addEventListener('message', handleMessage as EventListener);\r\n\r\n const closePoll = window.setInterval(() => {\r\n if (!popup.closed) return;\r\n if (cleaned) return;\r\n if (!sessionStorage.getItem(SIGN_OUT_STATE_KEY)) return;\r\n fail(new PopupClosedError());\r\n }, 280);\r\n });\r\n}\r\n"],"mappings":"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","names":["openSessionBridge","signOutWithXS","openSessionBridge","signOutWithXS","popupWindowFeatures"]}
package/dist/index.d.cts CHANGED
@@ -84,6 +84,9 @@ interface LoginWithXSOptions {
84
84
  clientId: string;
85
85
  /** Must be on your XS Auth client's allowed domains list (normally `window.location.origin`). */
86
86
  parentOrigin?: string;
87
+ /**
88
+ * Sign-in timeout in ms. Defaults to 180s to allow MFA verification in the Auth-Server popup.
89
+ */
87
90
  timeoutMs?: number;
88
91
  scope?: string;
89
92
  /**
@@ -108,6 +111,8 @@ interface LoginWithXSResult {
108
111
  user: XSAuthUser;
109
112
  /** Short-lived signed JWT — send to your backend to create a session. */
110
113
  idToken: string;
114
+ /** True when the user completed MFA during this sign-in (`amr` includes `mfa`). */
115
+ mfaVerified: boolean;
111
116
  }
112
117
  /** PKCE helpers for tests / custom callers. */
113
118
  declare function createPkcePair(): Promise<{
@@ -121,7 +126,11 @@ declare function createPkcePair(): Promise<{
121
126
  * opens the popup and exchanges postMessages with the PKCE verifier — no fetch to Auth-Server.
122
127
  */
123
128
  declare function loginWithXS(opts: LoginWithXSOptions): Promise<LoginWithXSResult>;
129
+ /** True when an XS Auth idToken indicates MFA was completed at sign-in. */
130
+ declare function idTokenIncludesMfa(idToken: string): boolean;
131
+ /** Read the `amr` claim from an XS Auth idToken payload (no signature verification). */
132
+ declare function parseIdTokenAmr(idToken: string): string[] | null;
124
133
  /** True when Auth-Server has no active browser session for silent sign-in. */
125
134
  declare function isLoginRequiredError(error: unknown): boolean;
126
135
 
127
- export { LoginBridgeTimeoutError, LoginTimeoutError, type LoginWithXSOptions, type LoginWithXSResult, type OpenSessionBridgeOptions, PopupBlockedError, PopupClosedError, type SessionBridge, SessionBridgeError, type SignOutAction, type SignOutWithXSOptions, type SignOutWithXSResult, XSAuthDeniedError, type XSAuthUser, type XSBrowserAccount, createPkcePair, isLoginRequiredError, isPrimaryAccountError, loginWithXS, openSessionBridge, signOutWithXS };
136
+ export { LoginBridgeTimeoutError, LoginTimeoutError, type LoginWithXSOptions, type LoginWithXSResult, type OpenSessionBridgeOptions, PopupBlockedError, PopupClosedError, type SessionBridge, SessionBridgeError, type SignOutAction, type SignOutWithXSOptions, type SignOutWithXSResult, XSAuthDeniedError, type XSAuthUser, type XSBrowserAccount, createPkcePair, idTokenIncludesMfa, isLoginRequiredError, isPrimaryAccountError, loginWithXS, openSessionBridge, parseIdTokenAmr, signOutWithXS };
package/dist/index.d.ts CHANGED
@@ -84,6 +84,9 @@ interface LoginWithXSOptions {
84
84
  clientId: string;
85
85
  /** Must be on your XS Auth client's allowed domains list (normally `window.location.origin`). */
86
86
  parentOrigin?: string;
87
+ /**
88
+ * Sign-in timeout in ms. Defaults to 180s to allow MFA verification in the Auth-Server popup.
89
+ */
87
90
  timeoutMs?: number;
88
91
  scope?: string;
89
92
  /**
@@ -108,6 +111,8 @@ interface LoginWithXSResult {
108
111
  user: XSAuthUser;
109
112
  /** Short-lived signed JWT — send to your backend to create a session. */
110
113
  idToken: string;
114
+ /** True when the user completed MFA during this sign-in (`amr` includes `mfa`). */
115
+ mfaVerified: boolean;
111
116
  }
112
117
  /** PKCE helpers for tests / custom callers. */
113
118
  declare function createPkcePair(): Promise<{
@@ -121,7 +126,11 @@ declare function createPkcePair(): Promise<{
121
126
  * opens the popup and exchanges postMessages with the PKCE verifier — no fetch to Auth-Server.
122
127
  */
123
128
  declare function loginWithXS(opts: LoginWithXSOptions): Promise<LoginWithXSResult>;
129
+ /** True when an XS Auth idToken indicates MFA was completed at sign-in. */
130
+ declare function idTokenIncludesMfa(idToken: string): boolean;
131
+ /** Read the `amr` claim from an XS Auth idToken payload (no signature verification). */
132
+ declare function parseIdTokenAmr(idToken: string): string[] | null;
124
133
  /** True when Auth-Server has no active browser session for silent sign-in. */
125
134
  declare function isLoginRequiredError(error: unknown): boolean;
126
135
 
127
- export { LoginBridgeTimeoutError, LoginTimeoutError, type LoginWithXSOptions, type LoginWithXSResult, type OpenSessionBridgeOptions, PopupBlockedError, PopupClosedError, type SessionBridge, SessionBridgeError, type SignOutAction, type SignOutWithXSOptions, type SignOutWithXSResult, XSAuthDeniedError, type XSAuthUser, type XSBrowserAccount, createPkcePair, isLoginRequiredError, isPrimaryAccountError, loginWithXS, openSessionBridge, signOutWithXS };
136
+ export { LoginBridgeTimeoutError, LoginTimeoutError, type LoginWithXSOptions, type LoginWithXSResult, type OpenSessionBridgeOptions, PopupBlockedError, PopupClosedError, type SessionBridge, SessionBridgeError, type SignOutAction, type SignOutWithXSOptions, type SignOutWithXSResult, XSAuthDeniedError, type XSAuthUser, type XSBrowserAccount, createPkcePair, idTokenIncludesMfa, isLoginRequiredError, isPrimaryAccountError, loginWithXS, openSessionBridge, parseIdTokenAmr, signOutWithXS };
package/dist/index.js CHANGED
@@ -404,7 +404,7 @@ async function loginWithXS(opts) {
404
404
  "loginWithXS requires a browser Window and explicit parentOrigin (or window.location)."
405
405
  );
406
406
  }
407
- const timeoutMs = opts.timeoutMs !== void 0 ? opts.timeoutMs : 12e4;
407
+ const timeoutMs = opts.timeoutMs !== void 0 ? opts.timeoutMs : 18e4;
408
408
  const state = randomBase64State();
409
409
  sessionStorage.setItem(STATE_KEY_STORAGE, state);
410
410
  const nonce = opts.useNonce ? randomBase64State() : void 0;
@@ -492,7 +492,7 @@ async function loginWithXS(opts) {
492
492
  window.removeEventListener("message", handleMessage);
493
493
  clearInterval(closePoll);
494
494
  cleaned = true;
495
- resolve({ user, idToken });
495
+ resolve({ user, idToken, mfaVerified: idTokenIncludesMfa(idToken) });
496
496
  try {
497
497
  popup.close();
498
498
  } catch {
@@ -508,6 +508,31 @@ async function loginWithXS(opts) {
508
508
  }, 280);
509
509
  });
510
510
  }
511
+ function idTokenIncludesMfa(idToken) {
512
+ const amr = parseIdTokenAmr(idToken);
513
+ return Array.isArray(amr) && amr.includes("mfa");
514
+ }
515
+ function parseIdTokenAmr(idToken) {
516
+ const payload = parseJwtPayload(idToken);
517
+ if (!payload || !("amr" in payload)) return null;
518
+ const amr = payload.amr;
519
+ if (Array.isArray(amr)) {
520
+ return amr.filter((v) => typeof v === "string");
521
+ }
522
+ if (typeof amr === "string" && amr.trim()) return [amr.trim()];
523
+ return null;
524
+ }
525
+ function parseJwtPayload(token) {
526
+ const parts = token.split(".");
527
+ if (parts.length < 2) return null;
528
+ try {
529
+ const json = atob(parts[1].replace(/-/g, "+").replace(/_/g, "/"));
530
+ const parsed = JSON.parse(json);
531
+ return parsed && typeof parsed === "object" ? parsed : null;
532
+ } catch {
533
+ return null;
534
+ }
535
+ }
511
536
  function randomBase64State() {
512
537
  return base64UrlEncode(bytesBuffer(32));
513
538
  }
@@ -535,10 +560,12 @@ export {
535
560
  SessionBridgeError,
536
561
  XSAuthDeniedError,
537
562
  createPkcePair,
563
+ idTokenIncludesMfa,
538
564
  isLoginRequiredError,
539
565
  isPrimaryAccountError,
540
566
  loginWithXS,
541
567
  openSessionBridge2 as openSessionBridge,
568
+ parseIdTokenAmr,
542
569
  signOutWithXS2 as signOutWithXS
543
570
  };
544
571
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/errors.ts","../src/session-bridge.ts","../src/sign-out.ts","../src/index.ts"],"sourcesContent":["/** Popup was blocked by the browser or environment. */\r\nexport class PopupBlockedError extends Error {\r\n readonly name = 'PopupBlockedError';\r\n}\r\n\r\n/** User closed the popup before completing login. */\r\nexport class PopupClosedError extends Error {\r\n readonly name = 'PopupClosedError';\r\n}\r\n\r\n/** XS Auth popup did not complete within timeout. */\r\nexport class LoginTimeoutError extends Error {\r\n readonly name = 'LoginTimeoutError';\r\n}\r\n\r\n/** XS Auth returned an OAuth-style error inside postMessage. */\r\nexport class XSAuthDeniedError extends Error {\r\n readonly name = 'XSAuthDeniedError';\r\n readonly errorCode: string;\r\n readonly description: string;\r\n\r\n constructor(errorCode: string, description: string) {\r\n super(description || errorCode || 'xs_auth_denied');\r\n this.errorCode = errorCode;\r\n this.description = description;\r\n }\r\n}\r\n\r\n/** Session bridge did not respond within timeout. */\r\nexport class LoginBridgeTimeoutError extends Error {\r\n readonly name = 'LoginBridgeTimeoutError';\r\n}\r\n","import {\r\n LoginBridgeTimeoutError,\r\n PopupBlockedError,\r\n PopupClosedError,\r\n} from './errors';\r\n\r\n/** XS Auth browser session account (multi-account SSO on the Auth-Server domain). */\r\nexport interface XSBrowserAccount {\r\n sessionId: string;\r\n userId: string;\r\n email: string;\r\n name: string;\r\n isPrimary: boolean;\r\n}\r\n\r\nexport interface OpenSessionBridgeOptions {\r\n clientId: string;\r\n parentOrigin?: string;\r\n timeoutMs?: number;\r\n}\r\n\r\nexport interface SessionBridge {\r\n listAccounts(): Promise<XSBrowserAccount[]>;\r\n revokeAccount(sessionId: string): Promise<{ accounts: XSBrowserAccount[]; remainingCount: number }>;\r\n revokeAll(): Promise<void>;\r\n setPrimary(sessionId: string): Promise<XSBrowserAccount[]>;\r\n close(): void;\r\n}\r\n\r\nexport class SessionBridgeError extends Error {\r\n readonly name = 'SessionBridgeError';\r\n readonly errorCode: string;\r\n\r\n constructor(errorCode: string, message: string) {\r\n super(message || errorCode);\r\n this.errorCode = errorCode;\r\n }\r\n}\r\n\r\ntype BridgeMessage = Partial<Record<string, unknown>>;\r\n\r\nconst BRIDGE_STATE_KEY = '__xs_bridge_state';\r\n\r\nfunction parseAccounts(raw: unknown): XSBrowserAccount[] {\r\n if (!Array.isArray(raw)) return [];\r\n return raw\r\n .map((item) => {\r\n if (!item || typeof item !== 'object') return null;\r\n const row = item as Record<string, unknown>;\r\n const sessionId =\r\n typeof row.sessionId === 'string'\r\n ? row.sessionId\r\n : typeof row.session_id === 'string'\r\n ? row.session_id\r\n : '';\r\n const userId =\r\n typeof row.userId === 'string'\r\n ? row.userId\r\n : typeof row.user_id === 'string'\r\n ? row.user_id\r\n : '';\r\n const email = typeof row.email === 'string' ? row.email : '';\r\n const name = typeof row.name === 'string' ? row.name : email;\r\n if (!sessionId || !email) return null;\r\n return {\r\n sessionId,\r\n userId,\r\n email,\r\n name,\r\n isPrimary: row.isPrimary === true || row.is_primary === true,\r\n };\r\n })\r\n .filter((x): x is XSBrowserAccount => x !== null);\r\n}\r\n\r\nfunction hiddenBridgePopupFeatures(): string {\r\n return 'width=1,height=1,left=-10000,top=-10000,resizable=no,scrollbars=no';\r\n}\r\n\r\nfunction randomBridgeState(): string {\r\n const bytes = new Uint8Array(32);\r\n crypto.getRandomValues(bytes);\r\n let binary = '';\r\n for (let i = 0; i < bytes.length; i++) {\r\n binary += String.fromCharCode(bytes[i]!);\r\n }\r\n return btoa(binary).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/u, '');\r\n}\r\n\r\n/**\r\n * Opens a same-origin Auth-Server popup bridge so the host app can list and revoke\r\n * browser SSO sessions without cross-origin cookie access.\r\n */\r\nexport async function openSessionBridge(\r\n opts: OpenSessionBridgeOptions,\r\n authBaseUrl: string,\r\n): Promise<SessionBridge> {\r\n const parentOrigin = (opts.parentOrigin ?? globalThis.location?.origin) as string | undefined;\r\n if (!parentOrigin || typeof window === 'undefined') {\r\n throw new Error(\r\n 'openSessionBridge requires a browser Window and explicit parentOrigin (or window.location).',\r\n );\r\n }\r\n\r\n const normalizedBase = new URL(authBaseUrl);\r\n const authOrigin = normalizedBase.origin;\r\n const state = randomBridgeState();\r\n sessionStorage.setItem(BRIDGE_STATE_KEY, state);\r\n\r\n const params = new URLSearchParams({\r\n client_id: opts.clientId,\r\n parent_origin: parentOrigin,\r\n state,\r\n });\r\n\r\n const bridgeUrl = `${normalizedBase.href.replace(/\\/?$/u, '')}/session/bridge?${params.toString()}`;\r\n const popup = window.open(\r\n bridgeUrl,\r\n `xs-auth-bridge-${crypto.randomUUID()}`,\r\n hiddenBridgePopupFeatures(),\r\n );\r\n if (!popup) throw new PopupBlockedError();\r\n\r\n const timeoutMs = opts.timeoutMs !== undefined ? opts.timeoutMs : 120_000;\r\n let cleaned = false;\r\n let closePoll: ReturnType<typeof setInterval> | undefined;\r\n\r\n const teardown = (): void => {\r\n if (cleaned) return;\r\n cleaned = true;\r\n window.removeEventListener('message', handleMessage as EventListener);\r\n if (closePoll !== undefined) clearInterval(closePoll);\r\n sessionStorage.removeItem(BRIDGE_STATE_KEY);\r\n try {\r\n popup.close();\r\n } catch {\r\n // ignore\r\n }\r\n };\r\n\r\n const pending = new Map<\r\n string,\r\n {\r\n resolve: (value: BridgeMessage) => void;\r\n reject: (error: Error) => void;\r\n }\r\n >();\r\n\r\n let bridgeReady = false;\r\n let readyResolve: (() => void) | null = null;\r\n let readyReject: ((error: Error) => void) | null = null;\r\n\r\n const readyPromise = new Promise<void>((resolve, reject) => {\r\n readyResolve = resolve;\r\n readyReject = reject;\r\n });\r\n\r\n const handleMessage = (event: MessageEvent): void => {\r\n if (event.origin !== authOrigin) return;\r\n const d = event.data as BridgeMessage;\r\n if (d?.source !== 'xs-auth') return;\r\n\r\n const st = typeof d.state === 'string' ? d.state : '';\r\n if (!st || st !== sessionStorage.getItem(BRIDGE_STATE_KEY)) return;\r\n\r\n if (d.type === 'bridge_ready') {\r\n bridgeReady = true;\r\n readyResolve?.();\r\n return;\r\n }\r\n\r\n const requestId = typeof d.requestId === 'string' ? d.requestId : '';\r\n if (!requestId) return;\r\n\r\n const entry = pending.get(requestId);\r\n if (!entry) return;\r\n\r\n pending.delete(requestId);\r\n\r\n if (typeof d.error === 'string' && d.error.length > 0) {\r\n entry.reject(\r\n new SessionBridgeError(\r\n String(d.error),\r\n typeof d.error_description === 'string' ? d.error_description : '',\r\n ),\r\n );\r\n return;\r\n }\r\n\r\n if (d.type === 'result') {\r\n entry.resolve(d);\r\n }\r\n };\r\n\r\n window.addEventListener('message', handleMessage as EventListener);\r\n\r\n closePoll = window.setInterval(() => {\r\n if (!popup.closed) return;\r\n if (cleaned) return;\r\n for (const [, entry] of pending) {\r\n entry.reject(new PopupClosedError());\r\n }\r\n pending.clear();\r\n readyReject?.(new PopupClosedError());\r\n teardown();\r\n }, 280);\r\n\r\n const readyTimer = window.setTimeout(() => {\r\n if (bridgeReady) return;\r\n readyReject?.(new LoginBridgeTimeoutError());\r\n teardown();\r\n }, timeoutMs);\r\n\r\n try {\r\n await readyPromise;\r\n } catch (error) {\r\n clearTimeout(readyTimer);\r\n throw error;\r\n }\r\n clearTimeout(readyTimer);\r\n\r\n const sendRequest = (type: string, extra: Record<string, unknown> = {}): Promise<BridgeMessage> => {\r\n if (popup.closed) {\r\n return Promise.reject(new PopupClosedError());\r\n }\r\n\r\n const requestId = crypto.randomUUID();\r\n return new Promise<BridgeMessage>((resolve, reject) => {\r\n const timer = window.setTimeout(() => {\r\n pending.delete(requestId);\r\n reject(new LoginBridgeTimeoutError());\r\n }, timeoutMs);\r\n\r\n pending.set(requestId, {\r\n resolve: (value) => {\r\n clearTimeout(timer);\r\n resolve(value);\r\n },\r\n reject: (error) => {\r\n clearTimeout(timer);\r\n reject(error);\r\n },\r\n });\r\n\r\n try {\r\n popup.postMessage(\r\n {\r\n source: 'xs-auth-opener',\r\n state,\r\n client_id: opts.clientId,\r\n requestId,\r\n type,\r\n ...extra,\r\n },\r\n authOrigin,\r\n );\r\n } catch {\r\n pending.delete(requestId);\r\n clearTimeout(timer);\r\n reject(new SessionBridgeError('post_message_failed', 'Could not reach the session bridge.'));\r\n }\r\n });\r\n };\r\n\r\n return {\r\n async listAccounts() {\r\n const result = await sendRequest('list_accounts');\r\n return parseAccounts(result.accounts);\r\n },\r\n\r\n async revokeAccount(sessionId: string) {\r\n const result = await sendRequest('revoke', { session_id: sessionId.trim() });\r\n const accounts = parseAccounts(result.accounts);\r\n const remainingCount =\r\n typeof result.remainingCount === 'number' ? result.remainingCount : accounts.length;\r\n return { accounts, remainingCount };\r\n },\r\n\r\n async revokeAll() {\r\n await sendRequest('revoke_all');\r\n },\r\n\r\n async setPrimary(sessionId: string) {\r\n const result = await sendRequest('set_primary', { session_id: sessionId.trim() });\r\n return parseAccounts(result.accounts);\r\n },\r\n\r\n close() {\r\n teardown();\r\n },\r\n };\r\n}\r\n\r\n/** True when the user must pick another primary account before signing out. */\r\nexport function isPrimaryAccountError(error: unknown): boolean {\r\n return error instanceof SessionBridgeError && error.errorCode === 'primary_account';\r\n}\r\n","import {\r\n LoginBridgeTimeoutError,\r\n PopupBlockedError,\r\n PopupClosedError,\r\n} from './errors';\r\n\r\nexport interface SignOutWithXSOptions {\r\n clientId: string;\r\n parentOrigin?: string;\r\n /** XS Auth user id (`sub`) for the account active in the host app. */\r\n activeUserId?: string;\r\n timeoutMs?: number;\r\n /** Override Auth-Server base URL (e.g. same-origin `/xs-auth` proxy in local dev). */\r\n authBaseUrl?: string;\r\n}\r\n\r\nexport type SignOutAction = 'revoked_one' | 'revoked_all' | 'cancelled';\r\n\r\nexport interface SignOutWithXSResult {\r\n action: SignOutAction;\r\n revokedCurrent: boolean;\r\n remainingCount: number;\r\n}\r\n\r\nconst SIGN_OUT_STATE_KEY = '__xs_sign_out_state';\r\n\r\nfunction popupWindowFeatures(width: number, height: number): string {\r\n const win = window;\r\n const outerW = win.outerWidth > 0 ? win.outerWidth : win.innerWidth;\r\n const outerH = win.outerHeight > 0 ? win.outerHeight : win.innerHeight;\r\n const screenX = win.screenX ?? win.screenLeft ?? 0;\r\n const screenY = win.screenY ?? win.screenTop ?? 0;\r\n const left = Math.round(screenX + Math.max(0, (outerW - width) / 2));\r\n const top = Math.round(screenY + Math.max(0, (outerH - height) / 2));\r\n return `width=${width},height=${height},left=${left},top=${top},resizable=yes,scrollbars=yes`;\r\n}\r\n\r\nfunction randomState(): string {\r\n const bytes = new Uint8Array(32);\r\n crypto.getRandomValues(bytes);\r\n let binary = '';\r\n for (let i = 0; i < bytes.length; i++) {\r\n binary += String.fromCharCode(bytes[i]!);\r\n }\r\n return btoa(binary).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/u, '');\r\n}\r\n\r\nfunction parseSignOutResult(raw: SignOutAction, data: Record<string, unknown>): SignOutWithXSResult {\r\n return {\r\n action: raw,\r\n revokedCurrent: data.revokedCurrent === true,\r\n remainingCount:\r\n typeof data.remainingCount === 'number' && Number.isFinite(data.remainingCount)\r\n ? Math.max(0, data.remainingCount)\r\n : 0,\r\n };\r\n}\r\n\r\n/**\r\n * Opens a centered XS Auth popup to sign out of one or all browser SSO accounts\r\n * (Google-style account manager on the Auth-Server domain).\r\n */\r\nexport async function signOutWithXS(\r\n opts: SignOutWithXSOptions,\r\n authBaseUrl: string,\r\n): Promise<SignOutWithXSResult> {\r\n const parentOrigin = (opts.parentOrigin ?? globalThis.location?.origin) as string | undefined;\r\n if (!parentOrigin || typeof window === 'undefined') {\r\n throw new Error(\r\n 'signOutWithXS requires a browser Window and explicit parentOrigin (or window.location).',\r\n );\r\n }\r\n\r\n const normalizedBase = new URL(authBaseUrl);\r\n const authOrigin = normalizedBase.origin;\r\n const state = randomState();\r\n sessionStorage.setItem(SIGN_OUT_STATE_KEY, state);\r\n\r\n const params = new URLSearchParams({\r\n client_id: opts.clientId,\r\n parent_origin: parentOrigin,\r\n state,\r\n });\r\n if (opts.activeUserId?.trim()) {\r\n params.set('active_user_id', opts.activeUserId.trim());\r\n }\r\n\r\n const url = `${normalizedBase.href.replace(/\\/?$/u, '')}/session/sign-out?${params.toString()}`;\r\n const popup = window.open(\r\n url,\r\n `xs-auth-signout-${crypto.randomUUID()}`,\r\n popupWindowFeatures(480, 640),\r\n );\r\n if (!popup) throw new PopupBlockedError();\r\n\r\n const timeoutMs = opts.timeoutMs !== undefined ? opts.timeoutMs : 120_000;\r\n\r\n return await new Promise<SignOutWithXSResult>((resolve, reject) => {\r\n let cleaned = false;\r\n\r\n const teardown = (): void => {\r\n if (cleaned) return;\r\n cleaned = true;\r\n window.removeEventListener('message', handleMessage as EventListener);\r\n clearInterval(closePoll);\r\n clearTimeout(timer);\r\n sessionStorage.removeItem(SIGN_OUT_STATE_KEY);\r\n try {\r\n popup.close();\r\n } catch {\r\n // ignore\r\n }\r\n };\r\n\r\n const fail = (error: Error): void => {\r\n teardown();\r\n reject(error);\r\n };\r\n\r\n const timer = window.setTimeout(() => {\r\n fail(new LoginBridgeTimeoutError());\r\n }, timeoutMs);\r\n\r\n const handleMessage = (event: MessageEvent): void => {\r\n if (event.origin !== authOrigin) return;\r\n const d = event.data as Partial<Record<string, unknown>>;\r\n if (d?.source !== 'xs-auth') return;\r\n\r\n const st = typeof d.state === 'string' ? d.state : '';\r\n if (!st || st !== sessionStorage.getItem(SIGN_OUT_STATE_KEY)) return;\r\n\r\n if (d.type === 'sign_out_cancelled') {\r\n teardown();\r\n resolve(parseSignOutResult('cancelled', d));\r\n return;\r\n }\r\n\r\n if (d.type === 'sign_out_complete') {\r\n teardown();\r\n const actionRaw = typeof d.action === 'string' ? d.action : 'revoked_one';\r\n const action: SignOutAction =\r\n actionRaw === 'revoked_all'\r\n ? 'revoked_all'\r\n : actionRaw === 'cancelled'\r\n ? 'cancelled'\r\n : 'revoked_one';\r\n resolve(parseSignOutResult(action, d));\r\n }\r\n };\r\n\r\n window.addEventListener('message', handleMessage as EventListener);\r\n\r\n const closePoll = window.setInterval(() => {\r\n if (!popup.closed) return;\r\n if (cleaned) return;\r\n if (!sessionStorage.getItem(SIGN_OUT_STATE_KEY)) return;\r\n fail(new PopupClosedError());\r\n }, 280);\r\n });\r\n}\r\n","import {\r\n LoginTimeoutError,\r\n PopupBlockedError,\r\n PopupClosedError,\r\n XSAuthDeniedError,\r\n} from './errors';\r\nimport {\r\n isPrimaryAccountError,\r\n openSessionBridge as openSessionBridgeInternal,\r\n SessionBridgeError,\r\n type OpenSessionBridgeOptions,\r\n type SessionBridge,\r\n type XSBrowserAccount,\r\n} from './session-bridge';\r\n\r\nimport {\r\n signOutWithXS as signOutWithXSInternal,\r\n type SignOutAction,\r\n type SignOutWithXSOptions,\r\n type SignOutWithXSResult,\r\n} from './sign-out';\r\n\r\nexport {\r\n LoginBridgeTimeoutError,\r\n LoginTimeoutError,\r\n PopupBlockedError,\r\n PopupClosedError,\r\n XSAuthDeniedError,\r\n} from './errors';\r\n\r\nexport {\r\n isPrimaryAccountError,\r\n SessionBridgeError,\r\n type OpenSessionBridgeOptions,\r\n type SessionBridge,\r\n type XSBrowserAccount,\r\n};\r\n\r\nexport {\r\n type SignOutAction,\r\n type SignOutWithXSOptions,\r\n type SignOutWithXSResult,\r\n};\r\n\r\n/** XS Auth server — baked in at build time (local vs production). */\r\nconst XS_AUTH_BASE_URL = __XS_AUTH_BASE_URL__;\r\n\r\n/** Opens the Auth-Server session bridge popup (multi-account sign-out). */\r\nexport function openSessionBridge(\r\n opts: OpenSessionBridgeOptions,\r\n): Promise<SessionBridge> {\r\n return openSessionBridgeInternal(opts, XS_AUTH_BASE_URL);\r\n}\r\n\r\n/** Google-style sign-out popup on the Auth-Server domain. */\r\nexport function signOutWithXS(opts: SignOutWithXSOptions): Promise<SignOutWithXSResult> {\r\n const authBase = opts.authBaseUrl?.trim() || XS_AUTH_BASE_URL;\r\n return signOutWithXSInternal(opts, authBase);\r\n}\r\n\r\n/** Signed-in user profile from XS Auth. */\r\nexport interface XSAuthUser {\r\n email: string;\r\n firstName?: string;\r\n lastName?: string;\r\n}\r\n\r\nexport interface LoginWithXSOptions {\r\n /** Your app's public client id from Xino Solutions. */\r\n clientId: string;\r\n /** Must be on your XS Auth client's allowed domains list (normally `window.location.origin`). */\r\n parentOrigin?: string;\r\n timeoutMs?: number;\r\n scope?: string;\r\n /**\r\n * Request a `nonce` inside `idToken` — your backend should verify it matches when validating the JWT.\r\n */\r\n useNonce?: boolean;\r\n /**\r\n * OAuth-style prompt for multi-account SSO on the Auth-Server domain.\r\n * - `none`: silent sign-in with the primary browser session (fails with `login_required` if absent)\r\n * - `select_account`: always show the account chooser when sessions exist\r\n * - `login`: force email/password (add another account)\r\n */\r\n prompt?: 'none' | 'select_account' | 'login';\r\n /** Prefer a specific XS Auth user id (`sub`) when continuing an existing browser session. */\r\n accountId?: string;\r\n /** When true and `prompt` is unset, defaults to `none` instead of account chooser. */\r\n preferPrimary?: boolean;\r\n /** Override Auth-Server base URL (e.g. same-origin `/xs-auth` proxy in local dev). */\r\n authBaseUrl?: string;\r\n}\r\n\r\nexport interface LoginWithXSResult {\r\n user: XSAuthUser;\r\n /** Short-lived signed JWT — send to your backend to create a session. */\r\n idToken: string;\r\n}\r\n\r\nfunction bytesBuffer(len: number): Uint8Array {\r\n const out = new Uint8Array(len);\r\n crypto.getRandomValues(out);\r\n return out;\r\n}\r\n\r\nfunction base64UrlEncode(buf: Uint8Array | ArrayBuffer): string {\r\n const bytes = buf instanceof Uint8Array ? buf : new Uint8Array(buf);\r\n let binary = '';\r\n const chunkSize = 0x8000;\r\n for (let i = 0; i < bytes.length; i += chunkSize) {\r\n binary += String.fromCharCode(...bytes.subarray(i, i + chunkSize));\r\n }\r\n const b64 = btoa(binary);\r\n return b64.replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/u, '');\r\n}\r\n\r\nasync function pkceVerifierAndChallenge(): Promise<{\r\n verifier: string;\r\n challenge: string;\r\n}> {\r\n const verifier = base64UrlEncode(bytesBuffer(64));\r\n const data = new TextEncoder().encode(verifier);\r\n const digest = await crypto.subtle.digest('SHA-256', data);\r\n const challenge = base64UrlEncode(digest);\r\n return { verifier, challenge };\r\n}\r\n\r\n/** PKCE helpers for tests / custom callers. */\r\nexport async function createPkcePair(): Promise<{\r\n verifier: string;\r\n challenge: string;\r\n}> {\r\n return pkceVerifierAndChallenge();\r\n}\r\n\r\nconst STATE_KEY_STORAGE = '__xs_login_state';\r\n\r\nfunction parseSdkUser(raw: unknown): XSAuthUser | null {\r\n if (!raw || typeof raw !== 'object') return null;\r\n const u = raw as Record<string, unknown>;\r\n const email = typeof u.email === 'string' ? u.email.trim() : '';\r\n if (!email) return null;\r\n const user: XSAuthUser = { email };\r\n const firstName =\r\n typeof u.firstName === 'string' ? u.firstName.trim() : '';\r\n const lastName = typeof u.lastName === 'string' ? u.lastName.trim() : '';\r\n if (firstName) user.firstName = firstName;\r\n if (lastName) user.lastName = lastName;\r\n return user;\r\n}\r\n\r\nfunction resolvePrompt(opts: LoginWithXSOptions): string | undefined {\r\n if (opts.prompt) return opts.prompt;\r\n if (opts.preferPrimary) return 'none';\r\n return undefined;\r\n}\r\n\r\nfunction authPublicPathFromBase(authBaseUrl: string): string {\r\n try {\r\n const pathname = new URL(authBaseUrl).pathname.replace(/\\/$/u, '');\r\n return pathname === '/' ? '' : pathname;\r\n } catch {\r\n return '';\r\n }\r\n}\r\n\r\nfunction maybeSetPublicPath(params: URLSearchParams, authBaseUrl: string): void {\r\n const publicPath = authPublicPathFromBase(authBaseUrl);\r\n if (publicPath) params.set('public_path', publicPath);\r\n}\r\n\r\n/**\r\n * Opens the XS Auth sign-in popup and returns the signed-in user plus a verifiable `idToken`.\r\n *\r\n * All Auth-Server HTTP calls happen inside the popup (same origin). The host app only\r\n * opens the popup and exchanges postMessages with the PKCE verifier — no fetch to Auth-Server.\r\n */\r\nexport async function loginWithXS(\r\n opts: LoginWithXSOptions,\r\n): Promise<LoginWithXSResult> {\r\n const authBase = opts.authBaseUrl?.trim() || XS_AUTH_BASE_URL;\r\n const normalizedBase = normalizeBaseUrl(authBase);\r\n const authOrigin = normalizedBase.origin;\r\n const parentOrigin = (opts.parentOrigin ?? globalThis.location?.origin) as\r\n | string\r\n | undefined;\r\n if (!parentOrigin || typeof window === 'undefined') {\r\n throw new Error(\r\n 'loginWithXS requires a browser Window and explicit parentOrigin (or window.location).',\r\n );\r\n }\r\n\r\n const timeoutMs =\r\n opts.timeoutMs !== undefined ? opts.timeoutMs : 120_000;\r\n\r\n const state = randomBase64State();\r\n sessionStorage.setItem(STATE_KEY_STORAGE, state);\r\n\r\n const nonce = opts.useNonce ? randomBase64State() : undefined;\r\n const pair = await pkceVerifierAndChallenge();\r\n\r\n const params = new URLSearchParams({\r\n client_id: opts.clientId,\r\n state,\r\n code_challenge: pair.challenge,\r\n code_challenge_method: 'S256',\r\n parent_origin: parentOrigin,\r\n response_mode: 'popup',\r\n });\r\n if (opts.scope?.trim()) params.set('scope', opts.scope.trim());\r\n if (nonce) params.set('nonce', nonce);\r\n const prompt = resolvePrompt(opts);\r\n if (prompt) params.set('prompt', prompt);\r\n if (opts.accountId?.trim()) params.set('account_id', opts.accountId.trim());\r\n maybeSetPublicPath(params, authBase);\r\n\r\n const authorizeUrl = `${normalizedBase.href.replace(/\\/?$/u, '')}/authorize?${params.toString()}`;\r\n\r\n const popupWidth = prompt === 'none' ? 420 : 480;\r\n const popupHeight = prompt === 'none' ? 120 : 640;\r\n const popup = window.open(\r\n authorizeUrl,\r\n `xs-auth-${crypto.randomUUID()}`,\r\n popupWindowFeatures(popupWidth, popupHeight),\r\n );\r\n if (!popup) throw new PopupBlockedError();\r\n\r\n return await new Promise<LoginWithXSResult>((resolve, reject) => {\r\n let cleaned = false;\r\n const teardown = (): void => {\r\n if (cleaned) return;\r\n cleaned = true;\r\n window.removeEventListener('message', handleMessage as EventListener);\r\n clearInterval(closePoll);\r\n clearTimeout(timer);\r\n try {\r\n popup.close();\r\n } catch {\r\n // ignore\r\n }\r\n };\r\n\r\n const fail = (e: unknown): void => {\r\n teardown();\r\n reject(e instanceof Error ? e : new Error(String(e)));\r\n };\r\n\r\n const timer = window.setTimeout(() => {\r\n fail(new LoginTimeoutError());\r\n }, timeoutMs);\r\n\r\n const handleMessage = (event: MessageEvent): void => {\r\n if (event.origin !== authOrigin) return;\r\n const d = event.data as Partial<Record<string, unknown>>;\r\n if (d?.source !== 'xs-auth') return;\r\n\r\n const st = typeof d.state === 'string' ? d.state : '';\r\n if (!st || st !== sessionStorage.getItem(STATE_KEY_STORAGE)) return;\r\n\r\n if (typeof d.error === 'string' && d.error.length > 0) {\r\n teardown();\r\n reject(\r\n new XSAuthDeniedError(\r\n String(d.error),\r\n typeof d.error_description === 'string'\r\n ? d.error_description\r\n : '',\r\n ),\r\n );\r\n return;\r\n }\r\n\r\n if (d.type === 'need_verifier') {\r\n try {\r\n popup.postMessage(\r\n {\r\n source: 'xs-auth-opener',\r\n state: st,\r\n code_verifier: pair.verifier,\r\n client_id: opts.clientId,\r\n },\r\n authOrigin,\r\n );\r\n } catch {\r\n fail(new XSAuthDeniedError('exchange_failed', 'Sign in could not be completed.'));\r\n }\r\n return;\r\n }\r\n\r\n const idToken =\r\n typeof d.id_token === 'string'\r\n ? d.id_token\r\n : typeof d.idToken === 'string'\r\n ? d.idToken\r\n : '';\r\n const user = parseSdkUser(d.user);\r\n if (!idToken || !user) return;\r\n\r\n sessionStorage.removeItem(STATE_KEY_STORAGE);\r\n clearTimeout(timer);\r\n window.removeEventListener('message', handleMessage as EventListener);\r\n clearInterval(closePoll);\r\n cleaned = true;\r\n\r\n resolve({ user, idToken });\r\n\r\n try {\r\n popup.close();\r\n } catch {\r\n // ignore\r\n }\r\n };\r\n\r\n window.addEventListener('message', handleMessage as EventListener);\r\n\r\n const closePoll = window.setInterval(() => {\r\n if (!popup.closed) return;\r\n if (cleaned) return;\r\n const pending = sessionStorage.getItem(STATE_KEY_STORAGE);\r\n if (!pending) return;\r\n fail(new PopupClosedError());\r\n }, 280);\r\n });\r\n}\r\n\r\nfunction randomBase64State(): string {\r\n return base64UrlEncode(bytesBuffer(32));\r\n}\r\n\r\nfunction normalizeBaseUrl(s: string): URL {\r\n return new URL(s);\r\n}\r\n\r\n/** Center popup over the opener window (falls back to screen center). */\r\nfunction popupWindowFeatures(width: number, height: number): string {\r\n const win = window;\r\n const outerW = win.outerWidth > 0 ? win.outerWidth : win.innerWidth;\r\n const outerH = win.outerHeight > 0 ? win.outerHeight : win.innerHeight;\r\n const screenX = win.screenX ?? win.screenLeft ?? 0;\r\n const screenY = win.screenY ?? win.screenTop ?? 0;\r\n const left = Math.round(screenX + Math.max(0, (outerW - width) / 2));\r\n const top = Math.round(screenY + Math.max(0, (outerH - height) / 2));\r\n return `width=${width},height=${height},left=${left},top=${top},resizable=yes,scrollbars=yes`;\r\n}\r\n\r\n/** True when Auth-Server has no active browser session for silent sign-in. */\r\nexport function isLoginRequiredError(error: unknown): boolean {\r\n return error instanceof XSAuthDeniedError && error.errorCode === 'login_required';\r\n}\r\n"],"mappings":"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","names":["openSessionBridge","signOutWithXS","popupWindowFeatures"]}
1
+ {"version":3,"sources":["../src/errors.ts","../src/session-bridge.ts","../src/sign-out.ts","../src/index.ts"],"sourcesContent":["/** Popup was blocked by the browser or environment. */\r\nexport class PopupBlockedError extends Error {\r\n readonly name = 'PopupBlockedError';\r\n}\r\n\r\n/** User closed the popup before completing login. */\r\nexport class PopupClosedError extends Error {\r\n readonly name = 'PopupClosedError';\r\n}\r\n\r\n/** XS Auth popup did not complete within timeout. */\r\nexport class LoginTimeoutError extends Error {\r\n readonly name = 'LoginTimeoutError';\r\n}\r\n\r\n/** XS Auth returned an OAuth-style error inside postMessage. */\r\nexport class XSAuthDeniedError extends Error {\r\n readonly name = 'XSAuthDeniedError';\r\n readonly errorCode: string;\r\n readonly description: string;\r\n\r\n constructor(errorCode: string, description: string) {\r\n super(description || errorCode || 'xs_auth_denied');\r\n this.errorCode = errorCode;\r\n this.description = description;\r\n }\r\n}\r\n\r\n/** Session bridge did not respond within timeout. */\r\nexport class LoginBridgeTimeoutError extends Error {\r\n readonly name = 'LoginBridgeTimeoutError';\r\n}\r\n","import {\r\n LoginBridgeTimeoutError,\r\n PopupBlockedError,\r\n PopupClosedError,\r\n} from './errors';\r\n\r\n/** XS Auth browser session account (multi-account SSO on the Auth-Server domain). */\r\nexport interface XSBrowserAccount {\r\n sessionId: string;\r\n userId: string;\r\n email: string;\r\n name: string;\r\n isPrimary: boolean;\r\n}\r\n\r\nexport interface OpenSessionBridgeOptions {\r\n clientId: string;\r\n parentOrigin?: string;\r\n timeoutMs?: number;\r\n}\r\n\r\nexport interface SessionBridge {\r\n listAccounts(): Promise<XSBrowserAccount[]>;\r\n revokeAccount(sessionId: string): Promise<{ accounts: XSBrowserAccount[]; remainingCount: number }>;\r\n revokeAll(): Promise<void>;\r\n setPrimary(sessionId: string): Promise<XSBrowserAccount[]>;\r\n close(): void;\r\n}\r\n\r\nexport class SessionBridgeError extends Error {\r\n readonly name = 'SessionBridgeError';\r\n readonly errorCode: string;\r\n\r\n constructor(errorCode: string, message: string) {\r\n super(message || errorCode);\r\n this.errorCode = errorCode;\r\n }\r\n}\r\n\r\ntype BridgeMessage = Partial<Record<string, unknown>>;\r\n\r\nconst BRIDGE_STATE_KEY = '__xs_bridge_state';\r\n\r\nfunction parseAccounts(raw: unknown): XSBrowserAccount[] {\r\n if (!Array.isArray(raw)) return [];\r\n return raw\r\n .map((item) => {\r\n if (!item || typeof item !== 'object') return null;\r\n const row = item as Record<string, unknown>;\r\n const sessionId =\r\n typeof row.sessionId === 'string'\r\n ? row.sessionId\r\n : typeof row.session_id === 'string'\r\n ? row.session_id\r\n : '';\r\n const userId =\r\n typeof row.userId === 'string'\r\n ? row.userId\r\n : typeof row.user_id === 'string'\r\n ? row.user_id\r\n : '';\r\n const email = typeof row.email === 'string' ? row.email : '';\r\n const name = typeof row.name === 'string' ? row.name : email;\r\n if (!sessionId || !email) return null;\r\n return {\r\n sessionId,\r\n userId,\r\n email,\r\n name,\r\n isPrimary: row.isPrimary === true || row.is_primary === true,\r\n };\r\n })\r\n .filter((x): x is XSBrowserAccount => x !== null);\r\n}\r\n\r\nfunction hiddenBridgePopupFeatures(): string {\r\n return 'width=1,height=1,left=-10000,top=-10000,resizable=no,scrollbars=no';\r\n}\r\n\r\nfunction randomBridgeState(): string {\r\n const bytes = new Uint8Array(32);\r\n crypto.getRandomValues(bytes);\r\n let binary = '';\r\n for (let i = 0; i < bytes.length; i++) {\r\n binary += String.fromCharCode(bytes[i]!);\r\n }\r\n return btoa(binary).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/u, '');\r\n}\r\n\r\n/**\r\n * Opens a same-origin Auth-Server popup bridge so the host app can list and revoke\r\n * browser SSO sessions without cross-origin cookie access.\r\n */\r\nexport async function openSessionBridge(\r\n opts: OpenSessionBridgeOptions,\r\n authBaseUrl: string,\r\n): Promise<SessionBridge> {\r\n const parentOrigin = (opts.parentOrigin ?? globalThis.location?.origin) as string | undefined;\r\n if (!parentOrigin || typeof window === 'undefined') {\r\n throw new Error(\r\n 'openSessionBridge requires a browser Window and explicit parentOrigin (or window.location).',\r\n );\r\n }\r\n\r\n const normalizedBase = new URL(authBaseUrl);\r\n const authOrigin = normalizedBase.origin;\r\n const state = randomBridgeState();\r\n sessionStorage.setItem(BRIDGE_STATE_KEY, state);\r\n\r\n const params = new URLSearchParams({\r\n client_id: opts.clientId,\r\n parent_origin: parentOrigin,\r\n state,\r\n });\r\n\r\n const bridgeUrl = `${normalizedBase.href.replace(/\\/?$/u, '')}/session/bridge?${params.toString()}`;\r\n const popup = window.open(\r\n bridgeUrl,\r\n `xs-auth-bridge-${crypto.randomUUID()}`,\r\n hiddenBridgePopupFeatures(),\r\n );\r\n if (!popup) throw new PopupBlockedError();\r\n\r\n const timeoutMs = opts.timeoutMs !== undefined ? opts.timeoutMs : 120_000;\r\n let cleaned = false;\r\n let closePoll: ReturnType<typeof setInterval> | undefined;\r\n\r\n const teardown = (): void => {\r\n if (cleaned) return;\r\n cleaned = true;\r\n window.removeEventListener('message', handleMessage as EventListener);\r\n if (closePoll !== undefined) clearInterval(closePoll);\r\n sessionStorage.removeItem(BRIDGE_STATE_KEY);\r\n try {\r\n popup.close();\r\n } catch {\r\n // ignore\r\n }\r\n };\r\n\r\n const pending = new Map<\r\n string,\r\n {\r\n resolve: (value: BridgeMessage) => void;\r\n reject: (error: Error) => void;\r\n }\r\n >();\r\n\r\n let bridgeReady = false;\r\n let readyResolve: (() => void) | null = null;\r\n let readyReject: ((error: Error) => void) | null = null;\r\n\r\n const readyPromise = new Promise<void>((resolve, reject) => {\r\n readyResolve = resolve;\r\n readyReject = reject;\r\n });\r\n\r\n const handleMessage = (event: MessageEvent): void => {\r\n if (event.origin !== authOrigin) return;\r\n const d = event.data as BridgeMessage;\r\n if (d?.source !== 'xs-auth') return;\r\n\r\n const st = typeof d.state === 'string' ? d.state : '';\r\n if (!st || st !== sessionStorage.getItem(BRIDGE_STATE_KEY)) return;\r\n\r\n if (d.type === 'bridge_ready') {\r\n bridgeReady = true;\r\n readyResolve?.();\r\n return;\r\n }\r\n\r\n const requestId = typeof d.requestId === 'string' ? d.requestId : '';\r\n if (!requestId) return;\r\n\r\n const entry = pending.get(requestId);\r\n if (!entry) return;\r\n\r\n pending.delete(requestId);\r\n\r\n if (typeof d.error === 'string' && d.error.length > 0) {\r\n entry.reject(\r\n new SessionBridgeError(\r\n String(d.error),\r\n typeof d.error_description === 'string' ? d.error_description : '',\r\n ),\r\n );\r\n return;\r\n }\r\n\r\n if (d.type === 'result') {\r\n entry.resolve(d);\r\n }\r\n };\r\n\r\n window.addEventListener('message', handleMessage as EventListener);\r\n\r\n closePoll = window.setInterval(() => {\r\n if (!popup.closed) return;\r\n if (cleaned) return;\r\n for (const [, entry] of pending) {\r\n entry.reject(new PopupClosedError());\r\n }\r\n pending.clear();\r\n readyReject?.(new PopupClosedError());\r\n teardown();\r\n }, 280);\r\n\r\n const readyTimer = window.setTimeout(() => {\r\n if (bridgeReady) return;\r\n readyReject?.(new LoginBridgeTimeoutError());\r\n teardown();\r\n }, timeoutMs);\r\n\r\n try {\r\n await readyPromise;\r\n } catch (error) {\r\n clearTimeout(readyTimer);\r\n throw error;\r\n }\r\n clearTimeout(readyTimer);\r\n\r\n const sendRequest = (type: string, extra: Record<string, unknown> = {}): Promise<BridgeMessage> => {\r\n if (popup.closed) {\r\n return Promise.reject(new PopupClosedError());\r\n }\r\n\r\n const requestId = crypto.randomUUID();\r\n return new Promise<BridgeMessage>((resolve, reject) => {\r\n const timer = window.setTimeout(() => {\r\n pending.delete(requestId);\r\n reject(new LoginBridgeTimeoutError());\r\n }, timeoutMs);\r\n\r\n pending.set(requestId, {\r\n resolve: (value) => {\r\n clearTimeout(timer);\r\n resolve(value);\r\n },\r\n reject: (error) => {\r\n clearTimeout(timer);\r\n reject(error);\r\n },\r\n });\r\n\r\n try {\r\n popup.postMessage(\r\n {\r\n source: 'xs-auth-opener',\r\n state,\r\n client_id: opts.clientId,\r\n requestId,\r\n type,\r\n ...extra,\r\n },\r\n authOrigin,\r\n );\r\n } catch {\r\n pending.delete(requestId);\r\n clearTimeout(timer);\r\n reject(new SessionBridgeError('post_message_failed', 'Could not reach the session bridge.'));\r\n }\r\n });\r\n };\r\n\r\n return {\r\n async listAccounts() {\r\n const result = await sendRequest('list_accounts');\r\n return parseAccounts(result.accounts);\r\n },\r\n\r\n async revokeAccount(sessionId: string) {\r\n const result = await sendRequest('revoke', { session_id: sessionId.trim() });\r\n const accounts = parseAccounts(result.accounts);\r\n const remainingCount =\r\n typeof result.remainingCount === 'number' ? result.remainingCount : accounts.length;\r\n return { accounts, remainingCount };\r\n },\r\n\r\n async revokeAll() {\r\n await sendRequest('revoke_all');\r\n },\r\n\r\n async setPrimary(sessionId: string) {\r\n const result = await sendRequest('set_primary', { session_id: sessionId.trim() });\r\n return parseAccounts(result.accounts);\r\n },\r\n\r\n close() {\r\n teardown();\r\n },\r\n };\r\n}\r\n\r\n/** True when the user must pick another primary account before signing out. */\r\nexport function isPrimaryAccountError(error: unknown): boolean {\r\n return error instanceof SessionBridgeError && error.errorCode === 'primary_account';\r\n}\r\n","import {\r\n LoginBridgeTimeoutError,\r\n PopupBlockedError,\r\n PopupClosedError,\r\n} from './errors';\r\n\r\nexport interface SignOutWithXSOptions {\r\n clientId: string;\r\n parentOrigin?: string;\r\n /** XS Auth user id (`sub`) for the account active in the host app. */\r\n activeUserId?: string;\r\n timeoutMs?: number;\r\n /** Override Auth-Server base URL (e.g. same-origin `/xs-auth` proxy in local dev). */\r\n authBaseUrl?: string;\r\n}\r\n\r\nexport type SignOutAction = 'revoked_one' | 'revoked_all' | 'cancelled';\r\n\r\nexport interface SignOutWithXSResult {\r\n action: SignOutAction;\r\n revokedCurrent: boolean;\r\n remainingCount: number;\r\n}\r\n\r\nconst SIGN_OUT_STATE_KEY = '__xs_sign_out_state';\r\n\r\nfunction popupWindowFeatures(width: number, height: number): string {\r\n const win = window;\r\n const outerW = win.outerWidth > 0 ? win.outerWidth : win.innerWidth;\r\n const outerH = win.outerHeight > 0 ? win.outerHeight : win.innerHeight;\r\n const screenX = win.screenX ?? win.screenLeft ?? 0;\r\n const screenY = win.screenY ?? win.screenTop ?? 0;\r\n const left = Math.round(screenX + Math.max(0, (outerW - width) / 2));\r\n const top = Math.round(screenY + Math.max(0, (outerH - height) / 2));\r\n return `width=${width},height=${height},left=${left},top=${top},resizable=yes,scrollbars=yes`;\r\n}\r\n\r\nfunction randomState(): string {\r\n const bytes = new Uint8Array(32);\r\n crypto.getRandomValues(bytes);\r\n let binary = '';\r\n for (let i = 0; i < bytes.length; i++) {\r\n binary += String.fromCharCode(bytes[i]!);\r\n }\r\n return btoa(binary).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/u, '');\r\n}\r\n\r\nfunction parseSignOutResult(raw: SignOutAction, data: Record<string, unknown>): SignOutWithXSResult {\r\n return {\r\n action: raw,\r\n revokedCurrent: data.revokedCurrent === true,\r\n remainingCount:\r\n typeof data.remainingCount === 'number' && Number.isFinite(data.remainingCount)\r\n ? Math.max(0, data.remainingCount)\r\n : 0,\r\n };\r\n}\r\n\r\n/**\r\n * Opens a centered XS Auth popup to sign out of one or all browser SSO accounts\r\n * (Google-style account manager on the Auth-Server domain).\r\n */\r\nexport async function signOutWithXS(\r\n opts: SignOutWithXSOptions,\r\n authBaseUrl: string,\r\n): Promise<SignOutWithXSResult> {\r\n const parentOrigin = (opts.parentOrigin ?? globalThis.location?.origin) as string | undefined;\r\n if (!parentOrigin || typeof window === 'undefined') {\r\n throw new Error(\r\n 'signOutWithXS requires a browser Window and explicit parentOrigin (or window.location).',\r\n );\r\n }\r\n\r\n const normalizedBase = new URL(authBaseUrl);\r\n const authOrigin = normalizedBase.origin;\r\n const state = randomState();\r\n sessionStorage.setItem(SIGN_OUT_STATE_KEY, state);\r\n\r\n const params = new URLSearchParams({\r\n client_id: opts.clientId,\r\n parent_origin: parentOrigin,\r\n state,\r\n });\r\n if (opts.activeUserId?.trim()) {\r\n params.set('active_user_id', opts.activeUserId.trim());\r\n }\r\n\r\n const url = `${normalizedBase.href.replace(/\\/?$/u, '')}/session/sign-out?${params.toString()}`;\r\n const popup = window.open(\r\n url,\r\n `xs-auth-signout-${crypto.randomUUID()}`,\r\n popupWindowFeatures(480, 640),\r\n );\r\n if (!popup) throw new PopupBlockedError();\r\n\r\n const timeoutMs = opts.timeoutMs !== undefined ? opts.timeoutMs : 120_000;\r\n\r\n return await new Promise<SignOutWithXSResult>((resolve, reject) => {\r\n let cleaned = false;\r\n\r\n const teardown = (): void => {\r\n if (cleaned) return;\r\n cleaned = true;\r\n window.removeEventListener('message', handleMessage as EventListener);\r\n clearInterval(closePoll);\r\n clearTimeout(timer);\r\n sessionStorage.removeItem(SIGN_OUT_STATE_KEY);\r\n try {\r\n popup.close();\r\n } catch {\r\n // ignore\r\n }\r\n };\r\n\r\n const fail = (error: Error): void => {\r\n teardown();\r\n reject(error);\r\n };\r\n\r\n const timer = window.setTimeout(() => {\r\n fail(new LoginBridgeTimeoutError());\r\n }, timeoutMs);\r\n\r\n const handleMessage = (event: MessageEvent): void => {\r\n if (event.origin !== authOrigin) return;\r\n const d = event.data as Partial<Record<string, unknown>>;\r\n if (d?.source !== 'xs-auth') return;\r\n\r\n const st = typeof d.state === 'string' ? d.state : '';\r\n if (!st || st !== sessionStorage.getItem(SIGN_OUT_STATE_KEY)) return;\r\n\r\n if (d.type === 'sign_out_cancelled') {\r\n teardown();\r\n resolve(parseSignOutResult('cancelled', d));\r\n return;\r\n }\r\n\r\n if (d.type === 'sign_out_complete') {\r\n teardown();\r\n const actionRaw = typeof d.action === 'string' ? d.action : 'revoked_one';\r\n const action: SignOutAction =\r\n actionRaw === 'revoked_all'\r\n ? 'revoked_all'\r\n : actionRaw === 'cancelled'\r\n ? 'cancelled'\r\n : 'revoked_one';\r\n resolve(parseSignOutResult(action, d));\r\n }\r\n };\r\n\r\n window.addEventListener('message', handleMessage as EventListener);\r\n\r\n const closePoll = window.setInterval(() => {\r\n if (!popup.closed) return;\r\n if (cleaned) return;\r\n if (!sessionStorage.getItem(SIGN_OUT_STATE_KEY)) return;\r\n fail(new PopupClosedError());\r\n }, 280);\r\n });\r\n}\r\n","import {\r\n LoginTimeoutError,\r\n PopupBlockedError,\r\n PopupClosedError,\r\n XSAuthDeniedError,\r\n} from './errors';\r\nimport {\r\n isPrimaryAccountError,\r\n openSessionBridge as openSessionBridgeInternal,\r\n SessionBridgeError,\r\n type OpenSessionBridgeOptions,\r\n type SessionBridge,\r\n type XSBrowserAccount,\r\n} from './session-bridge';\r\n\r\nimport {\r\n signOutWithXS as signOutWithXSInternal,\r\n type SignOutAction,\r\n type SignOutWithXSOptions,\r\n type SignOutWithXSResult,\r\n} from './sign-out';\r\n\r\nexport {\r\n LoginBridgeTimeoutError,\r\n LoginTimeoutError,\r\n PopupBlockedError,\r\n PopupClosedError,\r\n XSAuthDeniedError,\r\n} from './errors';\r\n\r\nexport {\r\n isPrimaryAccountError,\r\n SessionBridgeError,\r\n type OpenSessionBridgeOptions,\r\n type SessionBridge,\r\n type XSBrowserAccount,\r\n};\r\n\r\nexport {\r\n type SignOutAction,\r\n type SignOutWithXSOptions,\r\n type SignOutWithXSResult,\r\n};\r\n\r\n/** XS Auth server — baked in at build time (local vs production). */\r\nconst XS_AUTH_BASE_URL = __XS_AUTH_BASE_URL__;\r\n\r\n/** Opens the Auth-Server session bridge popup (multi-account sign-out). */\r\nexport function openSessionBridge(\r\n opts: OpenSessionBridgeOptions,\r\n): Promise<SessionBridge> {\r\n return openSessionBridgeInternal(opts, XS_AUTH_BASE_URL);\r\n}\r\n\r\n/** Google-style sign-out popup on the Auth-Server domain. */\r\nexport function signOutWithXS(opts: SignOutWithXSOptions): Promise<SignOutWithXSResult> {\r\n const authBase = opts.authBaseUrl?.trim() || XS_AUTH_BASE_URL;\r\n return signOutWithXSInternal(opts, authBase);\r\n}\r\n\r\n/** Signed-in user profile from XS Auth. */\r\nexport interface XSAuthUser {\r\n email: string;\r\n firstName?: string;\r\n lastName?: string;\r\n}\r\n\r\nexport interface LoginWithXSOptions {\r\n /** Your app's public client id from Xino Solutions. */\r\n clientId: string;\r\n /** Must be on your XS Auth client's allowed domains list (normally `window.location.origin`). */\r\n parentOrigin?: string;\r\n /**\r\n * Sign-in timeout in ms. Defaults to 180s to allow MFA verification in the Auth-Server popup.\r\n */\r\n timeoutMs?: number;\r\n scope?: string;\r\n /**\r\n * Request a `nonce` inside `idToken` — your backend should verify it matches when validating the JWT.\r\n */\r\n useNonce?: boolean;\r\n /**\r\n * OAuth-style prompt for multi-account SSO on the Auth-Server domain.\r\n * - `none`: silent sign-in with the primary browser session (fails with `login_required` if absent)\r\n * - `select_account`: always show the account chooser when sessions exist\r\n * - `login`: force email/password (add another account)\r\n */\r\n prompt?: 'none' | 'select_account' | 'login';\r\n /** Prefer a specific XS Auth user id (`sub`) when continuing an existing browser session. */\r\n accountId?: string;\r\n /** When true and `prompt` is unset, defaults to `none` instead of account chooser. */\r\n preferPrimary?: boolean;\r\n /** Override Auth-Server base URL (e.g. same-origin `/xs-auth` proxy in local dev). */\r\n authBaseUrl?: string;\r\n}\r\n\r\nexport interface LoginWithXSResult {\r\n user: XSAuthUser;\r\n /** Short-lived signed JWT — send to your backend to create a session. */\r\n idToken: string;\r\n /** True when the user completed MFA during this sign-in (`amr` includes `mfa`). */\r\n mfaVerified: boolean;\r\n}\r\n\r\nfunction bytesBuffer(len: number): Uint8Array {\r\n const out = new Uint8Array(len);\r\n crypto.getRandomValues(out);\r\n return out;\r\n}\r\n\r\nfunction base64UrlEncode(buf: Uint8Array | ArrayBuffer): string {\r\n const bytes = buf instanceof Uint8Array ? buf : new Uint8Array(buf);\r\n let binary = '';\r\n const chunkSize = 0x8000;\r\n for (let i = 0; i < bytes.length; i += chunkSize) {\r\n binary += String.fromCharCode(...bytes.subarray(i, i + chunkSize));\r\n }\r\n const b64 = btoa(binary);\r\n return b64.replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/u, '');\r\n}\r\n\r\nasync function pkceVerifierAndChallenge(): Promise<{\r\n verifier: string;\r\n challenge: string;\r\n}> {\r\n const verifier = base64UrlEncode(bytesBuffer(64));\r\n const data = new TextEncoder().encode(verifier);\r\n const digest = await crypto.subtle.digest('SHA-256', data);\r\n const challenge = base64UrlEncode(digest);\r\n return { verifier, challenge };\r\n}\r\n\r\n/** PKCE helpers for tests / custom callers. */\r\nexport async function createPkcePair(): Promise<{\r\n verifier: string;\r\n challenge: string;\r\n}> {\r\n return pkceVerifierAndChallenge();\r\n}\r\n\r\nconst STATE_KEY_STORAGE = '__xs_login_state';\r\n\r\nfunction parseSdkUser(raw: unknown): XSAuthUser | null {\r\n if (!raw || typeof raw !== 'object') return null;\r\n const u = raw as Record<string, unknown>;\r\n const email = typeof u.email === 'string' ? u.email.trim() : '';\r\n if (!email) return null;\r\n const user: XSAuthUser = { email };\r\n const firstName =\r\n typeof u.firstName === 'string' ? u.firstName.trim() : '';\r\n const lastName = typeof u.lastName === 'string' ? u.lastName.trim() : '';\r\n if (firstName) user.firstName = firstName;\r\n if (lastName) user.lastName = lastName;\r\n return user;\r\n}\r\n\r\nfunction resolvePrompt(opts: LoginWithXSOptions): string | undefined {\r\n if (opts.prompt) return opts.prompt;\r\n if (opts.preferPrimary) return 'none';\r\n return undefined;\r\n}\r\n\r\nfunction authPublicPathFromBase(authBaseUrl: string): string {\r\n try {\r\n const pathname = new URL(authBaseUrl).pathname.replace(/\\/$/u, '');\r\n return pathname === '/' ? '' : pathname;\r\n } catch {\r\n return '';\r\n }\r\n}\r\n\r\nfunction maybeSetPublicPath(params: URLSearchParams, authBaseUrl: string): void {\r\n const publicPath = authPublicPathFromBase(authBaseUrl);\r\n if (publicPath) params.set('public_path', publicPath);\r\n}\r\n\r\n/**\r\n * Opens the XS Auth sign-in popup and returns the signed-in user plus a verifiable `idToken`.\r\n *\r\n * All Auth-Server HTTP calls happen inside the popup (same origin). The host app only\r\n * opens the popup and exchanges postMessages with the PKCE verifier — no fetch to Auth-Server.\r\n */\r\nexport async function loginWithXS(\r\n opts: LoginWithXSOptions,\r\n): Promise<LoginWithXSResult> {\r\n const authBase = opts.authBaseUrl?.trim() || XS_AUTH_BASE_URL;\r\n const normalizedBase = normalizeBaseUrl(authBase);\r\n const authOrigin = normalizedBase.origin;\r\n const parentOrigin = (opts.parentOrigin ?? globalThis.location?.origin) as\r\n | string\r\n | undefined;\r\n if (!parentOrigin || typeof window === 'undefined') {\r\n throw new Error(\r\n 'loginWithXS requires a browser Window and explicit parentOrigin (or window.location).',\r\n );\r\n }\r\n\r\n const timeoutMs =\r\n opts.timeoutMs !== undefined ? opts.timeoutMs : 180_000;\r\n\r\n const state = randomBase64State();\r\n sessionStorage.setItem(STATE_KEY_STORAGE, state);\r\n\r\n const nonce = opts.useNonce ? randomBase64State() : undefined;\r\n const pair = await pkceVerifierAndChallenge();\r\n\r\n const params = new URLSearchParams({\r\n client_id: opts.clientId,\r\n state,\r\n code_challenge: pair.challenge,\r\n code_challenge_method: 'S256',\r\n parent_origin: parentOrigin,\r\n response_mode: 'popup',\r\n });\r\n if (opts.scope?.trim()) params.set('scope', opts.scope.trim());\r\n if (nonce) params.set('nonce', nonce);\r\n const prompt = resolvePrompt(opts);\r\n if (prompt) params.set('prompt', prompt);\r\n if (opts.accountId?.trim()) params.set('account_id', opts.accountId.trim());\r\n maybeSetPublicPath(params, authBase);\r\n\r\n const authorizeUrl = `${normalizedBase.href.replace(/\\/?$/u, '')}/authorize?${params.toString()}`;\r\n\r\n const popupWidth = prompt === 'none' ? 420 : 480;\r\n const popupHeight = prompt === 'none' ? 120 : 640;\r\n const popup = window.open(\r\n authorizeUrl,\r\n `xs-auth-${crypto.randomUUID()}`,\r\n popupWindowFeatures(popupWidth, popupHeight),\r\n );\r\n if (!popup) throw new PopupBlockedError();\r\n\r\n return await new Promise<LoginWithXSResult>((resolve, reject) => {\r\n let cleaned = false;\r\n const teardown = (): void => {\r\n if (cleaned) return;\r\n cleaned = true;\r\n window.removeEventListener('message', handleMessage as EventListener);\r\n clearInterval(closePoll);\r\n clearTimeout(timer);\r\n try {\r\n popup.close();\r\n } catch {\r\n // ignore\r\n }\r\n };\r\n\r\n const fail = (e: unknown): void => {\r\n teardown();\r\n reject(e instanceof Error ? e : new Error(String(e)));\r\n };\r\n\r\n const timer = window.setTimeout(() => {\r\n fail(new LoginTimeoutError());\r\n }, timeoutMs);\r\n\r\n const handleMessage = (event: MessageEvent): void => {\r\n if (event.origin !== authOrigin) return;\r\n const d = event.data as Partial<Record<string, unknown>>;\r\n if (d?.source !== 'xs-auth') return;\r\n\r\n const st = typeof d.state === 'string' ? d.state : '';\r\n if (!st || st !== sessionStorage.getItem(STATE_KEY_STORAGE)) return;\r\n\r\n if (typeof d.error === 'string' && d.error.length > 0) {\r\n teardown();\r\n reject(\r\n new XSAuthDeniedError(\r\n String(d.error),\r\n typeof d.error_description === 'string'\r\n ? d.error_description\r\n : '',\r\n ),\r\n );\r\n return;\r\n }\r\n\r\n if (d.type === 'need_verifier') {\r\n try {\r\n popup.postMessage(\r\n {\r\n source: 'xs-auth-opener',\r\n state: st,\r\n code_verifier: pair.verifier,\r\n client_id: opts.clientId,\r\n },\r\n authOrigin,\r\n );\r\n } catch {\r\n fail(new XSAuthDeniedError('exchange_failed', 'Sign in could not be completed.'));\r\n }\r\n return;\r\n }\r\n\r\n const idToken =\r\n typeof d.id_token === 'string'\r\n ? d.id_token\r\n : typeof d.idToken === 'string'\r\n ? d.idToken\r\n : '';\r\n const user = parseSdkUser(d.user);\r\n if (!idToken || !user) return;\r\n\r\n sessionStorage.removeItem(STATE_KEY_STORAGE);\r\n clearTimeout(timer);\r\n window.removeEventListener('message', handleMessage as EventListener);\r\n clearInterval(closePoll);\r\n cleaned = true;\r\n\r\n resolve({ user, idToken, mfaVerified: idTokenIncludesMfa(idToken) });\r\n\r\n try {\r\n popup.close();\r\n } catch {\r\n // ignore\r\n }\r\n };\r\n\r\n window.addEventListener('message', handleMessage as EventListener);\r\n\r\n const closePoll = window.setInterval(() => {\r\n if (!popup.closed) return;\r\n if (cleaned) return;\r\n const pending = sessionStorage.getItem(STATE_KEY_STORAGE);\r\n if (!pending) return;\r\n fail(new PopupClosedError());\r\n }, 280);\r\n });\r\n}\r\n\r\n/** True when an XS Auth idToken indicates MFA was completed at sign-in. */\r\nexport function idTokenIncludesMfa(idToken: string): boolean {\r\n const amr = parseIdTokenAmr(idToken);\r\n return Array.isArray(amr) && amr.includes('mfa');\r\n}\r\n\r\n/** Read the `amr` claim from an XS Auth idToken payload (no signature verification). */\r\nexport function parseIdTokenAmr(idToken: string): string[] | null {\r\n const payload = parseJwtPayload(idToken);\r\n if (!payload || !('amr' in payload)) return null;\r\n const amr = payload.amr;\r\n if (Array.isArray(amr)) {\r\n return amr.filter((v): v is string => typeof v === 'string');\r\n }\r\n if (typeof amr === 'string' && amr.trim()) return [amr.trim()];\r\n return null;\r\n}\r\n\r\nfunction parseJwtPayload(token: string): Record<string, unknown> | null {\r\n const parts = token.split('.');\r\n if (parts.length < 2) return null;\r\n try {\r\n const json = atob(parts[1].replace(/-/g, '+').replace(/_/g, '/'));\r\n const parsed: unknown = JSON.parse(json);\r\n return parsed && typeof parsed === 'object' ? (parsed as Record<string, unknown>) : null;\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\nfunction randomBase64State(): string {\r\n return base64UrlEncode(bytesBuffer(32));\r\n}\r\n\r\nfunction normalizeBaseUrl(s: string): URL {\r\n return new URL(s);\r\n}\r\n\r\n/** Center popup over the opener window (falls back to screen center). */\r\nfunction popupWindowFeatures(width: number, height: number): string {\r\n const win = window;\r\n const outerW = win.outerWidth > 0 ? win.outerWidth : win.innerWidth;\r\n const outerH = win.outerHeight > 0 ? win.outerHeight : win.innerHeight;\r\n const screenX = win.screenX ?? win.screenLeft ?? 0;\r\n const screenY = win.screenY ?? win.screenTop ?? 0;\r\n const left = Math.round(screenX + Math.max(0, (outerW - width) / 2));\r\n const top = Math.round(screenY + Math.max(0, (outerH - height) / 2));\r\n return `width=${width},height=${height},left=${left},top=${top},resizable=yes,scrollbars=yes`;\r\n}\r\n\r\n/** True when Auth-Server has no active browser session for silent sign-in. */\r\nexport function isLoginRequiredError(error: unknown): boolean {\r\n return error instanceof XSAuthDeniedError && error.errorCode === 'login_required';\r\n}\r\n"],"mappings":"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","names":["openSessionBridge","signOutWithXS","popupWindowFeatures"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xinosolutions/auth-sdk",
3
- "version": "0.3.0",
3
+ "version": "0.3.1",
4
4
  "private": false,
5
5
  "description": "Login with XS Auth — popup sign-in returning user profile and signed idToken.",
6
6
  "type": "module",