{"version":3,"file":"ad-token-handler.mjs","sources":["../../../../src/lib/auth/active-directory/ad-token-handler.ts"],"sourcesContent":["/**\n * Active Directory Token Handler\n *\n * Manages token acquisition, caching, and refresh for AD authentication.\n * Provides both MSAL-compatible and custom OAuth implementations.\n *\n * @module auth/active-directory/ad-token-handler\n */\n\nimport type { ADAuthError, ADConfig, ADTokens, TokenAcquisitionRequest, TokenRefreshResult, } from './types';\nimport { getAuthorityUrl, getConfiguredScopes } from './ad-config';\nimport {\n  createSecureLocalStorage,\n  createSecureSessionStorage,\n  isSecureStorageAvailable,\n  type SecureStorage,\n} from '@/lib/security/secure-storage';\n\n// =============================================================================\n// Constants\n// =============================================================================\n\nconst TOKEN_CACHE_PREFIX = 'ad_token_';\nconst DEFAULT_TOKEN_LIFETIME = 3600; // 1 hour in seconds\nconst REFRESH_BUFFER_MS = 300000; // 5 minutes before expiry\n\n/**\n * Session encryption key for AD token storage.\n *\n * SECURITY: The encryption key is generated using cryptographically secure\n * random bytes via the Web Crypto API. This key is:\n * - Generated fresh per session/initialization\n * - Stored only in memory (never persisted)\n * - Used for encrypting AD tokens at rest\n */\nlet adSessionEncryptionKey: string | null = null;\n\n/**\n * Generates a cryptographically secure encryption key for AD tokens.\n *\n * SECURITY: Uses crypto.getRandomValues() for true cryptographic randomness.\n * The key is 256 bits (32 bytes) encoded as base64.\n *\n * @returns A base64-encoded 256-bit random key\n */\nfunction generateADSessionKey(): string {\n  const keyBytes = new Uint8Array(32);\n  crypto.getRandomValues(keyBytes);\n  return btoa(String.fromCharCode(...keyBytes));\n}\n\n/**\n * Gets or creates the AD session encryption key.\n */\nfunction getADSessionEncryptionKey(): string {\n  adSessionEncryptionKey ??= generateADSessionKey();\n  return adSessionEncryptionKey;\n}\n\n// =============================================================================\n// Types\n// =============================================================================\n\n/**\n * Token cache entry structure.\n */\ninterface TokenCacheEntry {\n  tokens: ADTokens;\n  accountId: string;\n  scopes: string[];\n  cachedAt: number;\n}\n\n/**\n * Token handler options.\n */\nexport interface TokenHandlerOptions {\n  /** Cache location for tokens */\n  cacheLocation?: 'memory' | 'sessionStorage' | 'localStorage';\n  /** Enable automatic silent refresh */\n  autoRefresh?: boolean;\n  /** Refresh buffer in milliseconds */\n  refreshBuffer?: number;\n  /** Callback when tokens are refreshed */\n  onTokenRefresh?: (tokens: ADTokens) => void;\n  /** Callback when refresh fails */\n  onRefreshFailed?: (error: ADAuthError) => void;\n  /** Enable debug logging */\n  debug?: boolean;\n}\n\n/**\n * Token acquisition options for different flows.\n */\nexport interface AcquisitionOptions extends TokenAcquisitionRequest {\n  /** Use popup instead of redirect */\n  usePopup?: boolean;\n  /** Timeout for popup window */\n  popupTimeout?: number;\n  /** Custom state parameter */\n  state?: string;\n  /** Nonce for ID token validation */\n  nonce?: string;\n}\n\n// =============================================================================\n// Token Handler Class\n// =============================================================================\n\n/**\n * AD Token Handler for managing authentication tokens.\n *\n * Provides a unified interface for token acquisition, caching, and refresh\n * across different AD providers. Supports both interactive and silent\n * token acquisition flows.\n *\n * @example\n * ```typescript\n * const handler = new ADTokenHandler(config, {\n *   cacheLocation: 'sessionStorage',\n *   autoRefresh: true,\n *   onTokenRefresh: (tokens) => console.log('Tokens refreshed'),\n * });\n *\n * // Acquire token silently\n * const tokens = await handler.acquireTokenSilent({\n *   scopes: ['User.Read'],\n * });\n *\n * // Force interactive acquisition\n * const interactiveTokens = await handler.acquireTokenInteractive({\n *   scopes: ['User.Read', 'GroupMember.Read.All'],\n *   prompt: 'consent',\n * });\n * ```\n */\nexport class ADTokenHandler {\n  private readonly config: ADConfig;\n  private options: Required<TokenHandlerOptions>;\n  private memoryCache: Map<string, TokenCacheEntry>;\n  private refreshPromises: Map<string, Promise<TokenRefreshResult>>;\n  private refreshTimer: ReturnType<typeof setTimeout> | null = null;\n  private currentAccountId: string | null = null;\n\n  /**\n   * Secure storage instance for encrypted token persistence.\n   *\n   * SECURITY: Tokens are encrypted using AES-GCM before being stored\n   * in sessionStorage or localStorage. The encryption key is\n   * cryptographically random and stored only in memory.\n   */\n  private secureStorage: SecureStorage | null = null;\n\n  /**\n   * Create a new token handler.\n   *\n   * @param config - AD configuration\n   * @param options - Handler options\n   */\n  constructor(config: ADConfig, options: TokenHandlerOptions = {}) {\n    this.config = config;\n    this.options = {\n      cacheLocation: options.cacheLocation ?? 'sessionStorage',\n      autoRefresh: options.autoRefresh ?? true,\n      refreshBuffer: options.refreshBuffer ?? REFRESH_BUFFER_MS,\n      onTokenRefresh: options.onTokenRefresh ?? (() => {}),\n      onRefreshFailed: options.onRefreshFailed ?? (() => {}),\n      debug: options.debug ?? config.debug ?? false,\n    };\n    this.memoryCache = new Map();\n    this.refreshPromises = new Map();\n\n    // Initialize secure storage if persistent storage is configured\n    this.initializeSecureStorage();\n  }\n\n  /**\n   * Acquire token silently using cached tokens or refresh token.\n   *\n   * SECURITY: Tokens are retrieved from encrypted storage when available.\n   *\n   * @param request - Token acquisition request\n   * @returns Tokens if successful, null if interaction required\n   */\n  async acquireTokenSilent(\n    request: TokenAcquisitionRequest\n  ): Promise<ADTokens | null> {\n    const cacheKey = this.getCacheKey(request.scopes, request.account);\n\n    // Check cache first (async to support encrypted storage)\n    const cached = await this.getFromCache(cacheKey);\n    if (cached !== undefined && cached !== null && !this.isTokenExpired(cached.tokens)) {\n      this.log('Returning cached token');\n      return cached.tokens;\n    }\n\n    // Try to refresh if we have a refresh token\n    if (cached?.tokens.refreshToken !== undefined && cached?.tokens.refreshToken !== null) {\n      const refreshResult = await this.refreshToken(cached.tokens.refreshToken, request);\n      if (refreshResult.success && refreshResult.tokens !== undefined && refreshResult.tokens !== null) {\n        return refreshResult.tokens;\n      }\n\n      if (refreshResult.requiresInteraction === true) {\n        return null;\n      }\n    }\n\n    // No cached token and no refresh token\n    return null;\n  }\n\n  // ===========================================================================\n  // Token Acquisition Methods\n  // ===========================================================================\n\n  /**\n   * Acquire token interactively (redirect or popup).\n   *\n   * @param request - Token acquisition options\n   * @returns Acquired tokens\n   */\n  async acquireTokenInteractive(\n    request: AcquisitionOptions\n  ): Promise<ADTokens> {\n    const authority = getAuthorityUrl(this.config);\n    if (authority == null || authority === '') {\n      throw new Error('No authority URL configured');\n    }\n\n    const authUrl = this.buildAuthorizationUrl(request);\n\n    if (request.usePopup === true) {\n      return this.acquireTokenPopup(authUrl, request);\n    }\n\n    return this.acquireTokenRedirect(authUrl, request);\n  }\n\n  /**\n   * Handle redirect response after authentication.\n   *\n   * SECURITY: Tokens are encrypted before storage.\n   *\n   * @returns Tokens if redirect was handled, null otherwise\n   */\n  async handleRedirectResponse(): Promise<ADTokens | null> {\n    const {hash} = window.location;\n    if ((hash === undefined || hash === null || hash === '') || !hash.startsWith('#')) {\n      return null;\n    }\n\n    const urlParams = new URLSearchParams(hash.substring(1));\n\n    // Check for error\n    const error = urlParams.get('error');\n    if (error != null && error !== '') {\n      const errorDescription = urlParams.get('error_description') ?? 'Authentication failed';\n      throw new Error(errorDescription);\n    }\n\n    // Validate state\n    const state = urlParams.get('state');\n    const storedState = sessionStorage.getItem('ad_auth_state');\n    if (state !== storedState) {\n      throw new Error('State parameter does not match');\n    }\n\n    // Parse tokens\n    const tokens = this.parseTokenResponse(urlParams);\n    if (tokens == null) {\n      throw new Error('Failed to parse token response');\n    }\n\n    // Get stored scopes for caching\n    const scopesJson = sessionStorage.getItem('ad_auth_scopes');\n    const scopes = (scopesJson != null && scopesJson !== '') ? JSON.parse(scopesJson) as string[] : [];\n\n    // Cache tokens (encrypted)\n    await this.cacheTokens(tokens, scopes);\n\n    // Clean up\n    sessionStorage.removeItem('ad_auth_state');\n    sessionStorage.removeItem('ad_auth_nonce');\n    sessionStorage.removeItem('ad_auth_scopes');\n\n    // Clear hash from URL\n    window.history.replaceState(null, '', window.location.pathname + window.location.search);\n\n    return tokens;\n  }\n\n  /**\n   * Refresh tokens using refresh token.\n   *\n   * @param refreshToken - The refresh token\n   * @param request - Original token request for scope context\n   * @returns Refresh result\n   */\n  async refreshToken(\n    refreshToken: string,\n    request?: TokenAcquisitionRequest\n  ): Promise<TokenRefreshResult> {\n    const cacheKey = this.getCacheKey(\n      request?.scopes ?? getConfiguredScopes(this.config),\n      request?.account\n    );\n\n    // Check for existing refresh promise\n    const existingPromise = this.refreshPromises.get(cacheKey);\n    if (existingPromise != null) {\n      return existingPromise;\n    }\n\n    const refreshPromise = this.performRefresh(refreshToken, request);\n    this.refreshPromises.set(cacheKey, refreshPromise);\n\n    try {\n\n      return await refreshPromise;\n    } finally {\n      this.refreshPromises.delete(cacheKey);\n    }\n  }\n\n  /**\n   * Clear all cached tokens from memory and secure storage.\n   *\n   * SECURITY: Clears tokens from both encrypted and unencrypted storage\n   * to ensure complete cleanup during logout.\n   */\n  clearCache(): void {\n    // Clear memory cache\n    this.memoryCache.clear();\n\n    // Clear persistent storage\n    if (this.options.cacheLocation !== 'memory') {\n      // Clear from secure storage if available\n      if (this.secureStorage !== undefined && this.secureStorage !== null) {\n        try {\n          void this.secureStorage.clear();\n        } catch (error) {\n          this.log('Error clearing secure storage:', error);\n        }\n      }\n\n      // Also clear raw storage (for any unencrypted entries)\n      const storage = this.getStorage();\n      const keysToRemove: string[] = [];\n\n      for (let i = 0; i < storage.length; i++) {\n        const key = storage.key(i);\n        if (key?.startsWith(TOKEN_CACHE_PREFIX) === true) {\n          keysToRemove.push(key);\n        }\n      }\n\n      keysToRemove.forEach(key => storage.removeItem(key));\n    }\n\n    // Clear refresh timer\n    if (this.refreshTimer !== undefined && this.refreshTimer !== null) {\n      clearTimeout(this.refreshTimer);\n      this.refreshTimer = null;\n    }\n\n    this.currentAccountId = null;\n  }\n\n  /**\n   * Get cached tokens for current account.\n   *\n   * SECURITY: Retrieves tokens from encrypted storage when available.\n   */\n  async getCachedTokens(): Promise<ADTokens | null> {\n    if (this.currentAccountId === undefined || this.currentAccountId === null) {\n      return null;\n    }\n\n    const cacheKey = this.getCacheKey(\n      getConfiguredScopes(this.config),\n      this.currentAccountId\n    );\n    const entry = await this.getFromCache(cacheKey);\n\n    return entry?.tokens ?? null;\n  }\n\n  // ===========================================================================\n  // Token Refresh Methods\n  // ===========================================================================\n\n  /**\n   * Get cached tokens synchronously (memory only).\n   *\n   * SECURITY NOTE: This only returns tokens from in-memory cache.\n   * Use getCachedTokens() for full encrypted storage support.\n   */\n  getCachedTokensSync(): ADTokens | null {\n    if (this.currentAccountId === undefined || this.currentAccountId === null) {\n      return null;\n    }\n\n    const cacheKey = this.getCacheKey(\n      getConfiguredScopes(this.config),\n      this.currentAccountId\n    );\n    const entry = this.getFromCacheSync(cacheKey);\n\n    return entry?.tokens ?? null;\n  }\n\n  /**\n   * Cleanup resources.\n   */\n  dispose(): void {\n    if (this.refreshTimer !== undefined && this.refreshTimer !== null) {\n      clearTimeout(this.refreshTimer);\n      this.refreshTimer = null;\n    }\n    this.refreshPromises.clear();\n  }\n\n  /**\n   * Initializes secure storage for encrypted token persistence.\n   *\n   * SECURITY: Creates a SecureStorage instance with a cryptographically\n   * random session key. Falls back to raw storage if secure storage\n   * is unavailable (SSR or unsupported browser).\n   */\n  private initializeSecureStorage(): void {\n    if (this.options.cacheLocation === 'memory') {\n      return; // No persistent storage needed\n    }\n\n    if (!isSecureStorageAvailable()) {\n      this.log('Secure storage unavailable, falling back to unencrypted storage');\n      return;\n    }\n\n    try {\n      const encryptionKey = getADSessionEncryptionKey();\n      this.secureStorage = this.options.cacheLocation === 'localStorage'\n        ? createSecureLocalStorage(encryptionKey)\n        : createSecureSessionStorage(encryptionKey);\n      this.log('Secure storage initialized for AD tokens');\n    } catch (error) {\n      this.log('Failed to initialize secure storage:', error);\n      this.secureStorage = null;\n    }\n  }\n\n  // ===========================================================================\n  // Cache Management\n  // ===========================================================================\n\n  /**\n   * Acquire token using popup window.\n   *\n   * SECURITY: Tokens are encrypted before storage.\n   */\n  private async acquireTokenPopup(\n    authUrl: string,\n    request: AcquisitionOptions\n  ): Promise<ADTokens> {\n    return new Promise((resolve, reject) => {\n      const width = 500;\n      const height = 600;\n      const left = window.screenX + (window.outerWidth - width) / 2;\n      const top = window.screenY + (window.outerHeight - height) / 2;\n\n      const popup = window.open(\n        authUrl,\n        'adauth',\n        `width=${width},height=${height},left=${left},top=${top},scrollbars=yes`\n      );\n\n      if (popup == null) {\n        reject(new Error('Popup window was blocked'));\n        return;\n      }\n\n      const timeout = request.popupTimeout ?? 120000; // 2 minute default\n      const timeoutId = setTimeout(() => {\n        popup.close();\n        reject(new Error('Authentication timed out'));\n      }, timeout);\n\n      // Poll for redirect completion\n      const pollTimer = setInterval(() => {\n        void (async (): Promise<void> => {\n        try {\n          if (popup.closed) {\n            clearInterval(pollTimer);\n            clearTimeout(timeoutId);\n            reject(new Error('Popup was closed before authentication completed'));\n            return;\n          }\n\n          // Check if we're back at our redirect URI\n          if (popup.location.href.startsWith(this.getRedirectUri())) {\n            clearInterval(pollTimer);\n            clearTimeout(timeoutId);\n\n            const urlParams = new URLSearchParams(popup.location.hash.substring(1));\n            popup.close();\n\n            const tokens = this.parseTokenResponse(urlParams);\n            if (tokens != null) {\n              await this.cacheTokens(tokens, request.scopes);\n              resolve(tokens);\n            } else {\n              reject(new Error('Failed to parse token response'));\n            }\n          }\n        } catch {\n          // Cross-origin error - popup is on different domain, keep polling\n        }\n        })();\n      }, 100);\n    });\n  }\n\n  /**\n   * Acquire token using redirect flow.\n   */\n  private async acquireTokenRedirect(\n    authUrl: string,\n    request: AcquisitionOptions\n  ): Promise<ADTokens> {\n    // Store request state for handling the redirect response\n    const state = request.state ?? this.generateRandomString(32);\n    const nonce = request.nonce ?? this.generateRandomString(32);\n\n    sessionStorage.setItem('ad_auth_state', state);\n    sessionStorage.setItem('ad_auth_nonce', nonce);\n    sessionStorage.setItem('ad_auth_scopes', JSON.stringify(request.scopes));\n\n    // This will redirect, so we return a never-resolving promise\n    // The actual token handling happens in handleRedirectResponse\n    window.location.href = authUrl;\n\n    return new Promise(() => {});\n  }\n\n  /**\n   * Perform the actual token refresh.\n   */\n  private async performRefresh(\n    refreshToken: string,\n    request?: TokenAcquisitionRequest\n  ): Promise<TokenRefreshResult> {\n    const authority = getAuthorityUrl(this.config);\n    if (authority == null || authority === '') {\n      return {\n        success: false,\n        error: this.createError('config_error', 'No authority URL configured'),\n      };\n    }\n\n    try {\n      const tokenEndpoint = `${authority}/oauth2/v2.0/token`;\n      const scopes = request?.scopes ?? getConfiguredScopes(this.config);\n\n      const response = await fetch(tokenEndpoint, {\n        method: 'POST',\n        headers: {\n          'Content-Type': 'application/x-www-form-urlencoded',\n        },\n        body: new URLSearchParams({\n          grant_type: 'refresh_token',\n          refresh_token: refreshToken,\n          client_id: this.getClientId(),\n          scope: scopes.join(' '),\n        }),\n      });\n\n      if (!response.ok) {\n        const errorData = await response.json().catch(() => ({ error: undefined, error_description: undefined })) as { error?: string; error_description?: string };\n\n        const error = this.createError(\n          (errorData.error != null && errorData.error !== '') ? errorData.error : 'refresh_failed',\n          (errorData.error_description != null && errorData.error_description !== '') ? errorData.error_description : 'Token refresh failed'\n        );\n\n        // Check if interaction is required\n        const requiresInteraction = errorData.error != null && [\n          'invalid_grant',\n          'interaction_required',\n          'consent_required',\n        ].includes(errorData.error);\n\n        this.options.onRefreshFailed?.(error);\n\n        return {\n          success: false,\n          error,\n          requiresInteraction,\n        };\n      }\n\n      const data = await response.json() as {\n        access_token: string;\n        id_token: string;\n        refresh_token?: string;\n        expires_in: number;\n        scope?: string;\n        token_type?: string;\n      };\n      const tokens: ADTokens = {\n        accessToken: data.access_token,\n        idToken: data.id_token,\n        refreshToken: (data.refresh_token != null && data.refresh_token !== '') ? data.refresh_token : refreshToken,\n        expiresAt: Date.now() + (data.expires_in * 1000),\n        scopes: (data.scope != null && data.scope !== '') ? data.scope.split(' ') : scopes,\n        tokenType: (data.token_type != null && data.token_type !== '') ? data.token_type : 'Bearer',\n      };\n\n      // Cache (encrypted) and notify\n      await this.cacheTokens(tokens, scopes);\n      this.options.onTokenRefresh?.(tokens);\n      this.scheduleRefresh(tokens);\n\n      return { success: true, tokens };\n    } catch (error) {\n      const authError = this.createError(\n        'network_error',\n        'Network error during token refresh',\n        error\n      );\n\n      this.options.onRefreshFailed?.(authError);\n\n      return { success: false, error: authError };\n    }\n  }\n\n  /**\n   * Schedule automatic token refresh before expiry.\n   */\n  private scheduleRefresh(tokens: ADTokens): void {\n    if (!this.options.autoRefresh || (tokens.refreshToken === undefined || tokens.refreshToken === null)) {\n      return;\n    }\n\n    // Clear any existing timer\n    if (this.refreshTimer !== undefined && this.refreshTimer !== null) {\n      clearTimeout(this.refreshTimer);\n    }\n\n    // Calculate refresh time\n    const expiresIn = tokens.expiresAt - Date.now();\n    const refreshIn = Math.max(0, expiresIn - this.options.refreshBuffer);\n\n    this.log(`Scheduling token refresh in ${refreshIn}ms`);\n\n    this.refreshTimer = setTimeout(() => {\n      this.log('Auto-refreshing token');\n      const { refreshToken } = tokens;\n      if (refreshToken != null) {\n        void this.refreshToken(refreshToken);\n      }\n    }, refreshIn);\n  }\n\n  /**\n   * Cache tokens with encryption for persistent storage.\n   *\n   * SECURITY: When storing to persistent storage (sessionStorage/localStorage),\n   * tokens are encrypted using AES-GCM before being written. The encryption\n   * key is cryptographically random and stored only in memory, providing\n   * defense-in-depth against:\n   * - XSS attacks reading raw tokens from storage\n   * - Browser extension access to storage\n   * - Debugging tools inspecting storage\n   */\n  private async cacheTokens(tokens: ADTokens, scopes: string[]): Promise<void> {\n    const cacheKey = this.getCacheKey(scopes, tokens.accountId);\n    const entry: TokenCacheEntry = {\n      tokens,\n      accountId: tokens.accountId ?? '',\n      scopes,\n      cachedAt: Date.now(),\n    };\n\n    // Store in memory\n    this.memoryCache.set(cacheKey, entry);\n\n    // Store in persistent storage if configured\n    if (this.options.cacheLocation !== 'memory') {\n      const storageKey = `${TOKEN_CACHE_PREFIX}${cacheKey}`;\n\n      // Use secure storage if available\n      if (this.secureStorage !== undefined && this.secureStorage !== null) {\n        try {\n          const result = await this.secureStorage.setItem(storageKey, entry);\n          if (!result.success) {\n            this.log('Failed to store encrypted AD tokens:', result.error);\n            // Fall back to raw storage (logged warning)\n            this.fallbackStoreTokens(storageKey, entry);\n          }\n        } catch (error) {\n          this.log('Error encrypting AD tokens:', error);\n          this.fallbackStoreTokens(storageKey, entry);\n        }\n      } else {\n        // No secure storage available - use raw storage with warning\n        this.log('Warning: Storing AD tokens without encryption');\n        this.fallbackStoreTokens(storageKey, entry);\n      }\n    }\n\n    this.currentAccountId = (tokens.accountId != null && tokens.accountId !== '') ? tokens.accountId : null;\n  }\n\n  /**\n   * Fallback storage for when secure storage is unavailable.\n   *\n   * SECURITY WARNING: This stores tokens in plaintext. Only used when\n   * secure storage is not available (e.g., SSR, unsupported browser).\n   */\n  private fallbackStoreTokens(key: string, entry: TokenCacheEntry): void {\n    const storage = this.getStorage();\n    storage.setItem(key, JSON.stringify(entry));\n  }\n\n  /**\n   * Get tokens from cache with decryption support.\n   *\n   * SECURITY: When retrieving from persistent storage, attempts to decrypt\n   * using SecureStorage first. Falls back to raw storage for backwards\n   * compatibility with unencrypted entries.\n   */\n  private async getFromCache(cacheKey: string): Promise<TokenCacheEntry | null> {\n    // Check memory first\n    const memoryEntry = this.memoryCache.get(cacheKey);\n    if (memoryEntry !== undefined && memoryEntry !== null) {\n      return memoryEntry;\n    }\n\n    // Check persistent storage\n    if (this.options.cacheLocation !== 'memory') {\n      const storageKey = `${TOKEN_CACHE_PREFIX}${cacheKey}`;\n\n      // Try secure storage first\n      if (this.secureStorage !== undefined && this.secureStorage !== null) {\n        try {\n          const result = await this.secureStorage.getItem<TokenCacheEntry>(storageKey);\n          if (result.success && result.data !== undefined && result.data !== null) {\n            // Restore to memory cache\n            this.memoryCache.set(cacheKey, result.data);\n            return result.data;\n          }\n        } catch {\n          this.log('Failed to decrypt AD tokens, trying raw storage');\n        }\n      }\n\n      // Fall back to raw storage (for migration from unencrypted)\n      const storage = this.getStorage();\n      const stored = storage.getItem(storageKey);\n      if (stored !== undefined && stored !== null) {\n        try {\n          const entry = JSON.parse(stored) as TokenCacheEntry;\n          // Restore to memory cache\n          this.memoryCache.set(cacheKey, entry);\n\n          // Migrate to encrypted storage if available\n          if (this.secureStorage !== undefined && this.secureStorage !== null) {\n            this.log('Migrating unencrypted AD tokens to secure storage');\n            // Store encrypted version (don't await to not block)\n            void this.secureStorage.setItem(storageKey, entry).catch(() => {});\n            // Remove unencrypted version\n            storage.removeItem(storageKey);\n          }\n\n          return entry;\n        } catch {\n          // Invalid cache entry\n          storage.removeItem(storageKey);\n        }\n      }\n    }\n\n    return null;\n  }\n\n  // ===========================================================================\n  // Helper Methods\n  // ===========================================================================\n\n  /**\n   * Synchronous cache retrieval for backwards compatibility.\n   *\n   * SECURITY NOTE: This method only returns cached memory entries.\n   * For full support including encrypted persistent storage,\n   * use getFromCache (async) instead.\n   */\n  private getFromCacheSync(cacheKey: string): TokenCacheEntry | null {\n    return this.memoryCache.get(cacheKey) ?? null;\n  }\n\n  /**\n   * Build authorization URL for interactive flows.\n   */\n  private buildAuthorizationUrl(request: AcquisitionOptions): string {\n    const authority = getAuthorityUrl(this.config);\n    if (authority == null || authority === '') {\n      throw new Error('No authority URL configured');\n    }\n    const authorizeEndpoint = `${authority}/oauth2/v2.0/authorize`;\n\n    const state = request.state ?? this.generateRandomString(32);\n    const nonce = request.nonce ?? this.generateRandomString(32);\n\n    const params = new URLSearchParams({\n      client_id: this.getClientId(),\n      response_type: 'token id_token',\n      redirect_uri: this.getRedirectUri(),\n      scope: request.scopes.join(' '),\n      state,\n      nonce,\n      response_mode: 'fragment',\n    });\n\n    if (request.prompt !== undefined && request.prompt !== null) {\n      params.set('prompt', request.prompt);\n    }\n\n    if (request.loginHint !== undefined && request.loginHint !== null) {\n      params.set('login_hint', request.loginHint);\n    }\n\n    if (request.domainHint !== undefined && request.domainHint !== null) {\n      params.set('domain_hint', request.domainHint);\n    }\n\n    if (request.extraQueryParameters !== undefined && request.extraQueryParameters !== null) {\n      Object.entries(request.extraQueryParameters).forEach(([key, value]) => {\n        params.set(key, value);\n      });\n    }\n\n    return `${authorizeEndpoint}?${params.toString()}`;\n  }\n\n  /**\n   * Parse token response from URL parameters.\n   */\n  private parseTokenResponse(params: URLSearchParams): ADTokens | null {\n    const accessToken = params.get('access_token');\n    const idToken = params.get('id_token');\n\n    if ((accessToken === undefined || accessToken === null) || (idToken === undefined || idToken === null)) {\n      return null;\n    }\n\n    const expiresInParam = params.get('expires_in');\n    const expiresIn = parseInt(\n      (expiresInParam != null && expiresInParam !== '') ? expiresInParam : String(DEFAULT_TOKEN_LIFETIME),\n      10\n    );\n\n    const scopeParam = params.get('scope');\n    const tokenTypeParam = params.get('token_type');\n\n    return {\n      accessToken,\n      idToken,\n      expiresAt: Date.now() + (expiresIn * 1000),\n      scopes: (scopeParam != null && scopeParam !== '') ? scopeParam.split(' ') : [],\n      tokenType: (tokenTypeParam != null && tokenTypeParam !== '') ? tokenTypeParam : 'Bearer',\n    };\n  }\n\n  /**\n   * Check if token is expired.\n   */\n  private isTokenExpired(tokens: ADTokens): boolean {\n    return Date.now() >= tokens.expiresAt - this.options.refreshBuffer;\n  }\n\n  /**\n   * Generate cache key from scopes and account.\n   */\n  private getCacheKey(scopes: string[], account?: string): string {\n    const sortedScopes = [...scopes].sort().join('|');\n    const accountKey = (account != null && account !== '') ? account : 'default';\n    return `${accountKey}_${sortedScopes}`;\n  }\n\n  /**\n   * Get the appropriate storage object.\n   */\n  private getStorage(): Storage {\n    return this.options.cacheLocation === 'localStorage'\n      ? localStorage\n      : sessionStorage;\n  }\n\n  /**\n   * Get client ID from configuration.\n   */\n  private getClientId(): string {\n    switch (this.config.providerType) {\n      case 'azure-ad':\n        return this.config.azure?.clientId ?? '';\n      case 'azure-ad-b2c':\n        return this.config.azureB2C?.clientId ?? '';\n      case 'adfs':\n        return this.config.adfs?.clientId ?? '';\n      default:\n        return '';\n    }\n  }\n\n  /**\n   * Get redirect URI from configuration.\n   */\n  private getRedirectUri(): string {\n    switch (this.config.providerType) {\n      case 'azure-ad':\n        return this.config.azure?.redirectUri ?? '';\n      case 'azure-ad-b2c':\n        return this.config.azureB2C?.redirectUri ?? '';\n      case 'adfs':\n        return this.config.adfs?.redirectUri ?? '';\n      default:\n        return window.location.origin;\n    }\n  }\n\n  /**\n   * Generate random string for state/nonce.\n   */\n  private generateRandomString(length: number): string {\n    const array = new Uint8Array(length);\n    crypto.getRandomValues(array);\n    return Array.from(array, byte => byte.toString(16).padStart(2, '0')).join('');\n  }\n\n  /**\n   * Create error object.\n   */\n  private createError(\n    code: string,\n    message: string,\n    originalError?: unknown\n  ): ADAuthError {\n    return {\n      code,\n      message,\n      timestamp: Date.now(),\n      recoverable: !['config_error', 'state_mismatch'].includes(code),\n      originalError,\n    };\n  }\n\n  /**\n   * Log debug message.\n   */\n  private log(message: string, ...args: unknown[]): void {\n    if (this.options.debug) {\n      // eslint-disable-next-line no-console\n      console.log(`[ADTokenHandler] ${message}`, ...args);\n    }\n  }\n}\n\n// =============================================================================\n// Factory Function\n// =============================================================================\n\n/**\n * Create a new token handler.\n *\n * @param config - AD configuration\n * @param options - Handler options\n * @returns Configured ADTokenHandler\n */\nexport function createTokenHandler(\n  config: ADConfig,\n  options?: TokenHandlerOptions\n): ADTokenHandler {\n  return new ADTokenHandler(config, options);\n}\n"],"names":["TOKEN_CACHE_PREFIX","DEFAULT_TOKEN_LIFETIME","REFRESH_BUFFER_MS","adSessionEncryptionKey","generateADSessionKey","keyBytes","getADSessionEncryptionKey","ADTokenHandler","config","options","request","cacheKey","cached","refreshResult","authority","getAuthorityUrl","authUrl","hash","urlParams","error","errorDescription","state","storedState","tokens","scopesJson","scopes","refreshToken","getConfiguredScopes","existingPromise","refreshPromise","storage","keysToRemove","i","key","isSecureStorageAvailable","encryptionKey","createSecureLocalStorage","createSecureSessionStorage","resolve","reject","left","top","popup","timeout","timeoutId","pollTimer","nonce","tokenEndpoint","response","errorData","requiresInteraction","data","authError","expiresIn","refreshIn","entry","storageKey","result","memoryEntry","stored","authorizeEndpoint","params","value","accessToken","idToken","expiresInParam","scopeParam","tokenTypeParam","account","sortedScopes","length","array","byte","code","message","originalError","args","createTokenHandler"],"mappings":"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"}