/** * AuthBridgeClient - Cross-Domain Orchestrated Auth via Hidden iframe + postMessage * * This client manages a hidden iframe pointing to a session bridge page. * The bridge page runs on the auth domain and stores/retrieves tokens in * its own localStorage. Multiple app shells can embed this bridge to share * auth state across different origins. * * Architecture: * - Each app shell creates one AuthBridgeClient instance * - The bridge iframe is loaded from a configurable URL (e.g., /auth/session-bridge) * - Auth state changes are broadcast via postMessage to/from the bridge * - The bridge's localStorage is scoped to ITS origin, enabling cross-domain sharing * * Protocol Messages: * Parent -> Bridge: AUTH_INIT, AUTH_LOGIN, AUTH_LOGOUT, AUTH_LOGOUT_ALL, * AUTH_TOKEN_REFRESH, AUTH_ACCOUNT_ADD, AUTH_ACCOUNT_SWITCH * Bridge -> Parent: AUTH_STATE, AUTH_STATE_CHANGED */ export interface BridgeAuthState { user: Record | null; tokens: { accessToken: string; refreshToken?: string; expiresAt?: number; workspaceToken?: string; } | null; accounts?: Array>; activeAccountId?: string | null; profiles?: Array>; activeProfileId?: string | null; } export interface BridgeMessage { type: 'AUTH_INIT' | 'AUTH_STATE' | 'AUTH_LOGIN' | 'AUTH_LOGOUT' | 'AUTH_LOGOUT_ALL' | 'AUTH_TOKEN_REFRESH' | 'AUTH_ACCOUNT_ADD' | 'AUTH_ACCOUNT_SWITCH' | 'AUTH_STATE_CHANGED' | 'AUTH_BRIDGE_READY'; payload?: BridgeAuthState & { trigger?: string; accountId?: string; }; /** Unique message ID for request/response correlation */ messageId?: string; /** Per-client handshake nonce that bridge replies must echo */ nonce?: string; /** Source identifier */ source?: string; } export type AuthBridgeListener = (state: BridgeAuthState) => void; export interface AuthBridgeClientOptions { /** URL of the session bridge page */ bridgeUrl: string; /** @deprecated Parent accepts bridge replies only from bridgeUrl origin/source. */ allowedOrigins?: string | string[]; /** Callback when auth state changes from another app shell */ onStateChanged?: AuthBridgeListener; /** Enable debug logging */ debug?: boolean; } export declare class AuthBridgeClient { private iframe; private bridgeUrl; private onStateChanged?; private debug; private nonce; private ready; private readyReceived; private pendingMessages; private messageHandler; private destroyed; constructor(options: AuthBridgeClientOptions); /** * Initialize the bridge by creating the hidden iframe and setting up listeners */ init(): Promise; /** * Read current auth state from localStorage to include in AUTH_INIT. * This allows the bridge to store the parent's auth state for cross-domain SSO. */ private getCurrentAuthState; /** * Destroy the bridge — remove iframe and listeners * @param removeIframe - If false, keeps iframe in DOM for reuse (StrictMode compatibility) */ destroy(removeIframe?: boolean): void; /** * Notify bridge of a login event */ notifyLogin(state: BridgeAuthState): void; /** * Notify bridge of a logout event */ notifyLogout(): void; /** * Notify bridge to logout all accounts */ notifyLogoutAll(): void; /** * Notify bridge of a token refresh */ notifyTokenRefresh(tokens: BridgeAuthState['tokens']): void; /** * Notify bridge of an account switch */ notifyAccountSwitch(accountId: string): void; private handleMessage; private sendToBridge; private flushPendingMessages; private log; } export declare function initAuthBridge(options: AuthBridgeClientOptions): AuthBridgeClient; export declare function getAuthBridge(): AuthBridgeClient | null; /** * Check if the auth bridge has been initialized */ export declare function isAuthBridgeInitialized(): boolean; /** * Destroy the auth bridge * * By default, this is a no-op to handle React StrictMode correctly. * The bridge persists for the lifetime of the page. * * @param forceDestroy - If true, actually destroys the bridge (use on logout/app close) */ export declare function destroyAuthBridge(forceDestroy?: boolean): void; //# sourceMappingURL=AuthBridgeClient.d.ts.map