@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 +31 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +10 -1
- package/dist/index.d.ts +10 -1
- package/dist/index.js +29 -2
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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 :
|
|
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
|
package/dist/index.cjs.map
CHANGED
|
@@ -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 :
|
|
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"]}
|