@civic/auth 0.10.0-beta.0 → 0.10.0-beta.10

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.
Files changed (142) hide show
  1. package/CHANGELOG.md +5 -0
  2. package/README.md +1 -0
  3. package/dist/browser/storage.d.ts +1 -0
  4. package/dist/browser/storage.d.ts.map +1 -1
  5. package/dist/browser/storage.js +3 -0
  6. package/dist/browser/storage.js.map +1 -1
  7. package/dist/lib/logger.d.ts +2 -0
  8. package/dist/lib/logger.d.ts.map +1 -1
  9. package/dist/lib/logger.js +2 -0
  10. package/dist/lib/logger.js.map +1 -1
  11. package/dist/nextjs/config.d.ts +35 -3
  12. package/dist/nextjs/config.d.ts.map +1 -1
  13. package/dist/nextjs/config.js +76 -25
  14. package/dist/nextjs/config.js.map +1 -1
  15. package/dist/nextjs/cookies.d.ts +2 -1
  16. package/dist/nextjs/cookies.d.ts.map +1 -1
  17. package/dist/nextjs/cookies.js +35 -5
  18. package/dist/nextjs/cookies.js.map +1 -1
  19. package/dist/nextjs/hooks/useInitialAuthConfig.d.ts.map +1 -1
  20. package/dist/nextjs/hooks/useInitialAuthConfig.js +36 -13
  21. package/dist/nextjs/hooks/useInitialAuthConfig.js.map +1 -1
  22. package/dist/nextjs/middleware.d.ts +2 -1
  23. package/dist/nextjs/middleware.d.ts.map +1 -1
  24. package/dist/nextjs/middleware.js +59 -59
  25. package/dist/nextjs/middleware.js.map +1 -1
  26. package/dist/nextjs/providers/NextAuthProvider.d.ts.map +1 -1
  27. package/dist/nextjs/providers/NextAuthProvider.js +8 -5
  28. package/dist/nextjs/providers/NextAuthProvider.js.map +1 -1
  29. package/dist/nextjs/providers/NextAuthProviderClient.d.ts +3 -2
  30. package/dist/nextjs/providers/NextAuthProviderClient.d.ts.map +1 -1
  31. package/dist/nextjs/providers/NextAuthProviderClient.js +3 -3
  32. package/dist/nextjs/providers/NextAuthProviderClient.js.map +1 -1
  33. package/dist/nextjs/providers/ServerUserContext.d.ts +6 -1
  34. package/dist/nextjs/providers/ServerUserContext.d.ts.map +1 -1
  35. package/dist/nextjs/providers/ServerUserContext.js.map +1 -1
  36. package/dist/nextjs/routeHandler.d.ts +3 -0
  37. package/dist/nextjs/routeHandler.d.ts.map +1 -1
  38. package/dist/nextjs/routeHandler.js +16 -20
  39. package/dist/nextjs/routeHandler.js.map +1 -1
  40. package/dist/nextjs/utils.d.ts +30 -6
  41. package/dist/nextjs/utils.d.ts.map +1 -1
  42. package/dist/nextjs/utils.js +159 -35
  43. package/dist/nextjs/utils.js.map +1 -1
  44. package/dist/reactjs/core/GlobalAuthManager.d.ts +6 -2
  45. package/dist/reactjs/core/GlobalAuthManager.d.ts.map +1 -1
  46. package/dist/reactjs/core/GlobalAuthManager.js +26 -7
  47. package/dist/reactjs/core/GlobalAuthManager.js.map +1 -1
  48. package/dist/reactjs/hooks/useUser.d.ts.map +1 -1
  49. package/dist/reactjs/hooks/useUser.js +83 -130
  50. package/dist/reactjs/hooks/useUser.js.map +1 -1
  51. package/dist/server/ServerAuthenticationResolver.d.ts +3 -2
  52. package/dist/server/ServerAuthenticationResolver.d.ts.map +1 -1
  53. package/dist/server/ServerAuthenticationResolver.js +23 -6
  54. package/dist/server/ServerAuthenticationResolver.js.map +1 -1
  55. package/dist/server/index.d.ts +1 -0
  56. package/dist/server/index.d.ts.map +1 -1
  57. package/dist/server/index.js.map +1 -1
  58. package/dist/server/login.d.ts +2 -1
  59. package/dist/server/login.d.ts.map +1 -1
  60. package/dist/server/login.js.map +1 -1
  61. package/dist/server/session.d.ts +4 -3
  62. package/dist/server/session.d.ts.map +1 -1
  63. package/dist/server/session.js.map +1 -1
  64. package/dist/server/users.d.ts +4 -3
  65. package/dist/server/users.d.ts.map +1 -1
  66. package/dist/server/users.js.map +1 -1
  67. package/dist/services/types.d.ts +1 -1
  68. package/dist/services/types.d.ts.map +1 -1
  69. package/dist/services/types.js.map +1 -1
  70. package/dist/shared/hooks/index.d.ts +0 -1
  71. package/dist/shared/hooks/index.d.ts.map +1 -1
  72. package/dist/shared/hooks/index.js +0 -1
  73. package/dist/shared/hooks/index.js.map +1 -1
  74. package/dist/shared/lib/BrowserAuthenticationRefresher.d.ts.map +1 -1
  75. package/dist/shared/lib/BrowserAuthenticationRefresher.js +14 -6
  76. package/dist/shared/lib/BrowserAuthenticationRefresher.js.map +1 -1
  77. package/dist/shared/lib/BrowserCookieStorage.d.ts.map +1 -1
  78. package/dist/shared/lib/BrowserCookieStorage.js +5 -1
  79. package/dist/shared/lib/BrowserCookieStorage.js.map +1 -1
  80. package/dist/shared/lib/GenericAuthenticationRefresher.d.ts +1 -0
  81. package/dist/shared/lib/GenericAuthenticationRefresher.d.ts.map +1 -1
  82. package/dist/shared/lib/GenericAuthenticationRefresher.js +2 -0
  83. package/dist/shared/lib/GenericAuthenticationRefresher.js.map +1 -1
  84. package/dist/shared/lib/UserSession.d.ts +4 -3
  85. package/dist/shared/lib/UserSession.d.ts.map +1 -1
  86. package/dist/shared/lib/UserSession.js +4 -0
  87. package/dist/shared/lib/UserSession.js.map +1 -1
  88. package/dist/shared/lib/cookieConfig.d.ts +1 -1
  89. package/dist/shared/lib/cookieConfig.d.ts.map +1 -1
  90. package/dist/shared/lib/cookieConfig.js +2 -1
  91. package/dist/shared/lib/cookieConfig.js.map +1 -1
  92. package/dist/shared/lib/cookieUtils.d.ts +6 -0
  93. package/dist/shared/lib/cookieUtils.d.ts.map +1 -0
  94. package/dist/shared/lib/cookieUtils.js +21 -0
  95. package/dist/shared/lib/cookieUtils.js.map +1 -0
  96. package/dist/shared/lib/session.d.ts +2 -1
  97. package/dist/shared/lib/session.d.ts.map +1 -1
  98. package/dist/shared/lib/session.js +11 -2
  99. package/dist/shared/lib/session.js.map +1 -1
  100. package/dist/shared/lib/util.d.ts +2 -2
  101. package/dist/shared/lib/util.d.ts.map +1 -1
  102. package/dist/shared/lib/util.js +4 -4
  103. package/dist/shared/lib/util.js.map +1 -1
  104. package/dist/shared/version.d.ts +1 -1
  105. package/dist/shared/version.d.ts.map +1 -1
  106. package/dist/shared/version.js +1 -1
  107. package/dist/shared/version.js.map +1 -1
  108. package/dist/types.d.ts +4 -0
  109. package/dist/types.d.ts.map +1 -1
  110. package/dist/types.js.map +1 -1
  111. package/dist/vanillajs/auth/BackendAuthenticationRefresher.d.ts +4 -3
  112. package/dist/vanillajs/auth/BackendAuthenticationRefresher.d.ts.map +1 -1
  113. package/dist/vanillajs/auth/BackendAuthenticationRefresher.js +42 -21
  114. package/dist/vanillajs/auth/BackendAuthenticationRefresher.js.map +1 -1
  115. package/dist/vanillajs/auth/CivicAuth.d.ts.map +1 -1
  116. package/dist/vanillajs/auth/CivicAuth.js +2 -2
  117. package/dist/vanillajs/auth/CivicAuth.js.map +1 -1
  118. package/dist/vanillajs/auth/SessionManager.d.ts.map +1 -1
  119. package/dist/vanillajs/auth/SessionManager.js +23 -16
  120. package/dist/vanillajs/auth/SessionManager.js.map +1 -1
  121. package/dist/vanillajs/auth/TokenRefresher.d.ts +3 -0
  122. package/dist/vanillajs/auth/TokenRefresher.d.ts.map +1 -1
  123. package/dist/vanillajs/auth/TokenRefresher.js +27 -4
  124. package/dist/vanillajs/auth/TokenRefresher.js.map +1 -1
  125. package/dist/vanillajs/auth/config/ConfigProcessor.d.ts.map +1 -1
  126. package/dist/vanillajs/auth/config/ConfigProcessor.js +3 -1
  127. package/dist/vanillajs/auth/config/ConfigProcessor.js.map +1 -1
  128. package/dist/vanillajs/auth/handlers/IframeAuthHandler.d.ts.map +1 -1
  129. package/dist/vanillajs/auth/handlers/IframeAuthHandler.js +18 -0
  130. package/dist/vanillajs/auth/handlers/IframeAuthHandler.js.map +1 -1
  131. package/dist/vanillajs/auth/types/AuthTypes.d.ts +3 -0
  132. package/dist/vanillajs/auth/types/AuthTypes.d.ts.map +1 -1
  133. package/dist/vanillajs/auth/types/AuthTypes.js.map +1 -1
  134. package/package.json +1 -1
  135. package/dist/nextjs/hooks/useRefresh.d.ts +0 -5
  136. package/dist/nextjs/hooks/useRefresh.d.ts.map +0 -1
  137. package/dist/nextjs/hooks/useRefresh.js +0 -57
  138. package/dist/nextjs/hooks/useRefresh.js.map +0 -1
  139. package/dist/shared/hooks/useRefresh.d.ts +0 -6
  140. package/dist/shared/hooks/useRefresh.d.ts.map +0 -1
  141. package/dist/shared/hooks/useRefresh.js +0 -47
  142. package/dist/shared/hooks/useRefresh.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"SessionManager.js","sourceRoot":"","sources":["../../../src/vanillajs/auth/SessionManager.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AuthStorage } from \"../../types.js\";\nimport type { AuthenticationEvents } from \"./AuthenticationEvents.js\";\nimport type { User, Session } from \"../types/index.js\"; // Assuming Session might be used internally\nimport { AuthEvent } from \"../types/index.js\";\nimport { createLogger } from \"../utils/logger.js\";\nimport { TokenRefresher } from \"./TokenRefresher.js\";\nimport type { AuthConfig } from \"../../server/config.js\";\nimport {\n retrieveTokens,\n clearTokens,\n getBackendEndpoints,\n resolveEndpointUrl,\n} from \"../../shared/lib/util.js\";\nimport { getUser } from \"../../shared/lib/session.js\";\nimport { GenericUserSession } from \"../../shared/lib/UserSession.js\";\nimport {\n AUTOREFRESH_TIMEOUT_NAME,\n REFRESH_IN_PROGRESS,\n} from \"../../constants.js\";\nimport { verify, type VerifyOptions } from \"@civic/auth-verify\";\nimport { OAuthTokenTypes } from \"@/shared/lib/types.js\";\nimport { addSlashIfNeeded } from \"@/lib/oauth.js\";\n\nexport class SessionManager {\n private storage: AuthStorage;\n private events: AuthenticationEvents;\n private tokenRefresher?: TokenRefresher;\n private logger = createLogger(\"session\");\n private config: AuthConfig;\n private initialUser?: User | null;\n\n // Simple cache for backend session check to avoid excessive API calls\n private backendSessionCache: {\n result: boolean;\n timestamp: number;\n } | null = null;\n private readonly CACHE_DURATION = 30 * 1000; // 30 seconds\n\n constructor(\n storageAdapter: AuthStorage,\n events: AuthenticationEvents,\n config: AuthConfig,\n initialUser?: User | null,\n ) {\n this.storage = storageAdapter;\n this.events = events;\n this.config = config as AuthConfig;\n this.initialUser = initialUser;\n this.logger.info(\n \"SessionManager initialized with shared lib token storage\",\n { hasInitialUser: !!initialUser },\n );\n }\n\n /**\n * Initialize the session manager with auth configuration to enable token refresh\n */\n async initializeWithAuthConfig(authConfig: AuthConfig): Promise<void> {\n try {\n // Initialize token refresher\n this.tokenRefresher = new TokenRefresher(\n this.storage,\n this.events,\n authConfig,\n );\n await this.tokenRefresher.initialize(authConfig);\n\n // Check current authentication state (this now includes token validation and refresh attempts)\n const isAuthenticated = await this.isAuthenticated();\n\n // Set authentication state on the token refresher\n // This will enable auto-refresh if the user is authenticated (including after successful refresh)\n this.tokenRefresher.setAuthenticationState(isAuthenticated);\n\n this.logger.info(\n \"SessionManager initialized with token refresh capability\",\n { isAuthenticated },\n );\n\n if (!isAuthenticated) {\n await this.clearSession();\n }\n } catch (error) {\n this.logger.error(\n \"Failed to initialize SessionManager with auth config:\",\n error,\n );\n this.events.emit(AuthEvent.TOKEN_REFRESH_ERROR, error);\n }\n }\n\n /**\n * Build current session from shared lib storage or backend API\n * For backend flows with httpOnly cookies, creates limited session when tokens aren't accessible\n */\n async getCurrentSession(): Promise<Session | null> {\n try {\n const tokens = await retrieveTokens(this.storage);\n\n const user = await this.getCurrentUser();\n\n // If we have tokens and user (normal flow), create full session\n if ((tokens?.id_token || tokens?.access_token) && user) {\n // Validate all available tokens\n const validationResults = await this.validateTokens({\n id_token: tokens.id_token,\n access_token: tokens.access_token,\n });\n\n // Check if any tokens failed validation\n if (\n !validationResults.idTokenValid ||\n !validationResults.accessTokenValid\n ) {\n this.logger.warn(\n \"Token validation failed in getCurrentSession, returning null\",\n );\n return null;\n }\n\n return {\n user,\n accessToken: tokens.access_token,\n idToken: tokens.id_token,\n refreshToken: tokens.refresh_token ?? undefined,\n expiresAt: tokens.oidc_session_expires_at ?? undefined,\n };\n }\n\n // If we have user but no accessible tokens (backend flow with httpOnly cookies),\n // create a limited session with just user info\n if (user && this.isBrowserCookieStorage()) {\n this.logger.debug(\n \"Creating limited session for backend flow (tokens in httpOnly cookies)\",\n );\n return {\n user,\n accessToken: undefined, // Not accessible in httpOnly cookies\n idToken: undefined, // Not accessible in httpOnly cookies\n refreshToken: undefined, // Not accessible in httpOnly cookies\n expiresAt: undefined, // Not accessible in httpOnly cookies\n };\n }\n\n this.logger.debug(\"No session available - no tokens or user found\");\n return null;\n } catch (error) {\n this.logger.error(\"Failed to load session:\", error);\n return null;\n }\n }\n\n /**\n * Check if user is authenticated using shared lib utilities\n * For backend flows with httpOnly cookies, falls back to API check\n *\n * This method now validates tokens on load and attempts refresh if:\n * - Tokens exist but are expired/invalid\n * - A refresh token is available\n */\n async isAuthenticated(): Promise<boolean> {\n try {\n // First, try the standard token-based check\n const tokens = await retrieveTokens(this.storage);\n\n // Normalize empty strings to null for consistent checking\n const hasIdToken = tokens?.id_token && tokens.id_token.trim() !== \"\";\n const hasRefreshToken =\n tokens?.refresh_token && tokens.refresh_token.trim() !== \"\";\n\n // If no tokens found, check for explicit initial user state in backend mode\n if (\n !hasIdToken &&\n this.config.loginUrl &&\n this.initialUser !== undefined\n ) {\n if (this.initialUser === null) {\n this.logger.debug(\n \"No tokens and initial user explicitly null in backend mode - not authenticated\",\n );\n return false;\n } else {\n this.logger.debug(\n \"No tokens but initial user provided in backend mode - considering authenticated\",\n { hasInitialUser: !!this.initialUser },\n );\n return true;\n }\n }\n\n // If no tokens found and we're using BrowserCookieStorage,\n // try checking backend session (for httpOnly cookies)\n if (!hasIdToken && this.isBrowserCookieStorage()) {\n this.logger.debug(\n \"No tokens accessible, checking backend session...\",\n await this.checkBackendSession(),\n );\n return await this.checkBackendSession();\n }\n\n // If we have tokens, validate them\n if (hasIdToken) {\n const validationResults = await this.validateTokens({\n id_token: tokens.id_token,\n access_token: tokens.access_token,\n });\n\n // Both tokens must be valid (if they exist) for authentication to be considered valid\n const allTokensValid =\n validationResults.idTokenValid && validationResults.accessTokenValid;\n\n if (allTokensValid) {\n this.logger.debug(\n \"All available tokens are valid, user is authenticated\",\n );\n return true;\n }\n\n // Some tokens are invalid/expired - attempt refresh if refresh token exists\n if (hasRefreshToken && this.tokenRefresher) {\n this.logger.info(\n \"Some tokens expired/invalid, attempting refresh with refresh token\",\n );\n\n try {\n // Attempt token refresh\n await this.tokenRefresher.refreshTokens();\n this.logger.info(\n \"Token refresh successful during authentication check\",\n );\n\n // Check if we now have valid tokens after refresh\n const refreshedTokens = await retrieveTokens(this.storage);\n const refreshedValidationResults = await this.validateTokens({\n id_token: refreshedTokens?.id_token,\n access_token: refreshedTokens?.access_token,\n });\n\n const allRefreshedTokensValid =\n refreshedValidationResults.idTokenValid &&\n refreshedValidationResults.accessTokenValid;\n\n if (allRefreshedTokensValid) {\n this.logger.info(\n \"Successfully restored session via refresh token\",\n );\n return true;\n }\n } catch (error) {\n this.logger.warn(\n \"Token refresh failed during authentication check:\",\n error,\n );\n // Clear invalid tokens and refresh token since refresh failed\n await clearTokens(this.storage);\n }\n } else {\n this.logger.warn(\n \"Some tokens invalid and no refresh token available, clearing tokens\",\n );\n await clearTokens(this.storage);\n }\n } else if (hasRefreshToken && this.tokenRefresher) {\n // No ID token but we have a refresh token - attempt to restore session\n this.logger.info(\n \"No ID token found but refresh token exists, attempting session restore\",\n );\n\n try {\n // Attempt token refresh\n await this.tokenRefresher.refreshTokens();\n this.logger.info(\"Token refresh successful during session restore\");\n\n // Check if we now have valid tokens after refresh\n const refreshedTokens = await retrieveTokens(this.storage);\n const refreshedValidationResults = await this.validateTokens({\n id_token: refreshedTokens?.id_token,\n access_token: refreshedTokens?.access_token,\n });\n\n const allRefreshedTokensValid =\n refreshedValidationResults.idTokenValid &&\n refreshedValidationResults.accessTokenValid;\n\n if (allRefreshedTokensValid) {\n this.logger.info(\n \"Successfully restored session from refresh token only\",\n );\n return true;\n }\n\n this.logger.info(\"Couldn't restore session from refresh token\");\n } catch (error) {\n this.logger.warn(\"Session restore from refresh token failed:\", error);\n // Clear invalid refresh token since refresh failed\n await clearTokens(this.storage);\n }\n }\n\n return false;\n } catch (error) {\n this.logger.error(\"Error checking authentication:\", error);\n return false;\n }\n }\n\n /**\n * Validate if a token is cryptographically valid and not expired\n * Uses proper JWT verification with signature validation using JWKS\n * @param token JWT token to validate\n * @param tokenType Type of token (for logging and cleanup purposes)\n * @returns true if token is valid, false if expired or invalid\n */\n private async validateToken(\n token: string,\n tokenType: \"id_token\" | \"access_token\" = \"id_token\",\n ): Promise<boolean> {\n try {\n // For backend flows with httpOnly cookies, we can't validate tokens client-side\n // since they're not accessible to JavaScript\n if (this.isBrowserCookieStorage()) {\n this.logger.debug(\n \"Backend flow: skipping client-side token validation\",\n );\n return true; // Backend will validate tokens server-side\n }\n\n // Configure verification options based on token type\n const verifyOptions: VerifyOptions = {\n issuer: addSlashIfNeeded(\n this.config.oauthServerBaseUrl ?? \"https://auth.civic.com/oauth/\",\n ),\n };\n\n // Set audience based on token type\n if (tokenType === \"id_token\" && this.config.clientId) {\n // ID tokens should have the client ID as audience for proper OIDC compliance\n verifyOptions.aud = this.config.clientId;\n } else if (tokenType === \"access_token\") {\n // Access tokens have \"civic\" as audience based on auth server configuration\n verifyOptions.aud = \"civic\";\n verifyOptions.clientId = this.config.clientId;\n }\n\n this.logger.debug(`Verifying ${tokenType} with options:`, verifyOptions);\n\n // Use the @civic/auth-verify package for proper JWT verification\n await verify(token, verifyOptions);\n\n this.logger.debug(`${tokenType} cryptographically verified and valid`);\n return true;\n } catch (error) {\n this.logger.warn(`${tokenType} validation failed`, error);\n // Clear the specific token that failed validation\n if (tokenType === \"id_token\") {\n this.storage.delete(OAuthTokenTypes.ID_TOKEN);\n } else if (tokenType === \"access_token\") {\n this.storage.delete(OAuthTokenTypes.ACCESS_TOKEN);\n }\n return false;\n }\n }\n\n /**\n * Validate both ID token and access token if they exist\n * @param tokens Token object containing id_token and access_token\n * @returns Object indicating which tokens are valid\n */\n private async validateTokens(tokens: {\n id_token?: string;\n access_token?: string;\n }): Promise<{\n idTokenValid: boolean;\n accessTokenValid: boolean;\n }> {\n const results = {\n idTokenValid: true, // Default to true if token doesn't exist\n accessTokenValid: true, // Default to true if token doesn't exist\n };\n\n // Validate ID token if it exists\n if (tokens.id_token && tokens.id_token.trim() !== \"\") {\n results.idTokenValid = await this.validateToken(\n tokens.id_token,\n \"id_token\",\n );\n }\n\n // Validate access token if it exists\n if (tokens.access_token && tokens.access_token.trim() !== \"\") {\n results.accessTokenValid = await this.validateToken(\n tokens.access_token,\n \"access_token\",\n );\n }\n\n return results;\n }\n\n /**\n * Check if we're using BrowserCookieStorage\n */\n private isBrowserCookieStorage(): boolean {\n return this.storage.constructor.name === \"BrowserCookieStorage\";\n }\n\n /**\n * Simple backend session check via API call (with caching)\n */\n private async checkBackendSession(): Promise<boolean> {\n try {\n // Check if we have a valid cached result\n if (this.backendSessionCache) {\n const age = Date.now() - this.backendSessionCache.timestamp;\n if (age < this.CACHE_DURATION) {\n this.logger.debug(\n `Using cached backend session result: ${this.backendSessionCache.result}`,\n );\n return this.backendSessionCache.result;\n }\n }\n\n if (!this.config.loginUrl) {\n return false;\n }\n\n const backendUrl = new URL(this.config.loginUrl).origin;\n const endpoints = getBackendEndpoints(this.config.backendEndpoints);\n const response = await fetch(\n resolveEndpointUrl(backendUrl, endpoints.user),\n {\n method: \"GET\",\n credentials: \"include\", // Send httpOnly cookies\n },\n );\n\n const result = response.ok;\n\n // Cache the result\n this.backendSessionCache = {\n result,\n timestamp: Date.now(),\n };\n\n this.logger.debug(\n `Backend session check: ${result} (cached for ${this.CACHE_DURATION / 1000}s)`,\n );\n return result;\n } catch (error) {\n this.logger.debug(\"Backend session check failed:\", error);\n\n // Cache negative result for shorter time\n this.backendSessionCache = {\n result: false,\n timestamp: Date.now(),\n };\n\n return false;\n }\n }\n\n /**\n * Get current user from shared lib storage, initial user, or backend API\n * For backend flows with httpOnly cookies, falls back to API check\n */\n async getCurrentUser(): Promise<User | null> {\n try {\n // First, try to get user from accessible tokens\n const user = await getUser(this.storage);\n if (user) {\n this.logger.debug(\"Found user from accessible tokens\");\n return user;\n }\n\n // If no user from tokens, check explicit initial user state\n if (this.initialUser !== undefined) {\n if (this.initialUser === null) {\n this.logger.debug(\n \"Initial user explicitly null - no user authenticated\",\n );\n return null;\n } else {\n this.logger.debug(\"Using initial user data to avoid backend call\");\n return this.initialUser;\n }\n }\n\n // If no user found and we're using BrowserCookieStorage,\n // try getting user from backend API (for httpOnly cookies)\n if (this.isBrowserCookieStorage()) {\n this.logger.debug(\n \"No user from tokens and no initial data, trying backend API...\",\n );\n return await this.getUserFromBackendApi();\n }\n\n this.logger.debug(\"No user found and not using browser cookie storage\");\n return null;\n } catch (error) {\n this.logger.error(\"Failed to get user from shared storage:\", error);\n return null;\n }\n }\n\n /**\n * Get user information from backend API (with caching)\n */\n private async getUserFromBackendApi(): Promise<User | null> {\n try {\n if (!this.config.loginUrl) {\n this.logger.debug(\"No backend URL available for user fetch\");\n return null;\n }\n\n this.logger.debug(\"Fetching user from backend API...\");\n\n const backendUrl = new URL(this.config.loginUrl).origin;\n const endpoints = getBackendEndpoints(this.config.backendEndpoints);\n const response = await fetch(\n resolveEndpointUrl(backendUrl, endpoints.user),\n {\n method: \"GET\",\n credentials: \"include\", // Send httpOnly cookies\n headers: { \"Content-Type\": \"application/json\" },\n },\n );\n\n if (response.ok) {\n const data = await response.json();\n const user = data.user;\n this.logger.debug(\"Successfully fetched user from backend API\");\n return user;\n } else {\n this.logger.debug(`Backend user fetch failed: ${response.status}`);\n return null;\n }\n } catch (error) {\n this.logger.debug(\"Backend user fetch failed:\", error);\n return null;\n }\n }\n\n /**\n * Clear all authentication data using shared lib utilities\n * @param preserveLogoutState - If true, preserves logout state for cleanup after redirect\n */\n async clearSession(preserveLogoutState: boolean = false): Promise<void> {\n try {\n if (preserveLogoutState) {\n // During logout, we need to preserve logout state for cleanup after redirect\n await this.clearTokensExceptLogoutState();\n } else {\n // Normal session clearing - clear everything\n await clearTokens(this.storage);\n }\n\n // Clear user session using shared utilities\n const userSession = new GenericUserSession(this.storage);\n await userSession.clear();\n\n // Clear backend session cache\n this.backendSessionCache = null;\n\n // Stop token refresher when session is cleared\n this.tokenRefresher?.setAuthenticationState(false);\n\n this.events.emit(AuthEvent.USER_SESSION_CHANGED, null);\n this.logger.info(\"Session cleared using shared lib utilities\");\n } catch (error) {\n this.logger.error(\"Failed to clear session:\", error);\n throw error;\n }\n }\n\n /**\n * Clear tokens from storage except logout state\n * This is needed during logout to preserve the logout state for cleanup after redirect\n */\n private async clearTokensExceptLogoutState(): Promise<void> {\n // Clear all token-related keys except LOGOUT_STATE\n // These are the OAuth token types from the constants\n const keysToDelete = [\n OAuthTokenTypes.ID_TOKEN,\n OAuthTokenTypes.ACCESS_TOKEN,\n OAuthTokenTypes.REFRESH_TOKEN,\n OAuthTokenTypes.OIDC_SESSION_EXPIRES_AT,\n REFRESH_IN_PROGRESS,\n AUTOREFRESH_TIMEOUT_NAME,\n // Note: NOT clearing LOGOUT_STATE here - it's needed for cleanup after redirect\n ];\n\n const clearPromises = keysToDelete.map(async (key) => {\n await this.storage.delete(key);\n });\n\n await Promise.all(clearPromises);\n }\n\n /**\n * Manually trigger token refresh\n */\n async refreshTokens(): Promise<void> {\n if (!this.tokenRefresher) {\n throw new Error(\n \"Token refresher not initialized. Call initializeWithAuthConfig first.\",\n );\n }\n\n return this.tokenRefresher.refreshTokens();\n }\n\n /**\n * Get token refresher state for debugging\n */\n getTokenRefresherState(): {\n isInitialized: boolean;\n isAuthenticated: boolean;\n isAutoRefreshActive: boolean;\n } | null {\n return this.tokenRefresher?.getState() || null;\n }\n\n /**\n * Clean up resources when session manager is destroyed\n */\n async destroy(): Promise<void> {\n await this.tokenRefresher?.destroy();\n this.tokenRefresher = undefined;\n this.logger.info(\"SessionManager destroyed\");\n }\n}\n"]}
1
+ {"version":3,"file":"SessionManager.js","sourceRoot":"","sources":["../../../src/vanillajs/auth/SessionManager.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AuthStorage } from \"../../types.js\";\nimport type { AuthenticationEvents } from \"./AuthenticationEvents.js\";\nimport type { User, Session } from \"../types/index.js\"; // Assuming Session might be used internally\nimport { AuthEvent } from \"../types/index.js\";\nimport { createLogger } from \"../utils/logger.js\";\nimport { TokenRefresher } from \"./TokenRefresher.js\";\nimport type { AuthConfig } from \"../../server/config.js\";\nimport {\n retrieveTokens,\n clearTokens,\n getBackendEndpoints,\n resolveEndpointUrl,\n} from \"../../shared/lib/util.js\";\nimport { getUser } from \"../../shared/lib/session.js\";\nimport { GenericUserSession } from \"../../shared/lib/UserSession.js\";\nimport {\n AUTOREFRESH_TIMEOUT_NAME,\n REFRESH_IN_PROGRESS,\n} from \"../../constants.js\";\nimport { verify, type VerifyOptions } from \"@civic/auth-verify\";\nimport { OAuthTokenTypes } from \"@/shared/lib/types.js\";\nimport { addSlashIfNeeded } from \"@/lib/oauth.js\";\n\nexport class SessionManager {\n private storage: AuthStorage;\n private events: AuthenticationEvents;\n private tokenRefresher?: TokenRefresher;\n private logger = createLogger(\"session\");\n private config: AuthConfig;\n private initialUser?: User | null;\n\n // Simple cache for backend session check to avoid excessive API calls\n private backendSessionCache: {\n result: boolean;\n timestamp: number;\n } | null = null;\n private readonly CACHE_DURATION = 30 * 1000; // 30 seconds\n\n constructor(\n storageAdapter: AuthStorage,\n events: AuthenticationEvents,\n config: AuthConfig,\n initialUser?: User | null,\n ) {\n this.storage = storageAdapter;\n this.events = events;\n this.config = config as AuthConfig;\n this.initialUser = initialUser;\n this.logger.info(\n \"SessionManager initialized with shared lib token storage\",\n { hasInitialUser: !!initialUser },\n );\n }\n\n /**\n * Initialize the session manager with auth configuration to enable token refresh\n */\n async initializeWithAuthConfig(authConfig: AuthConfig): Promise<void> {\n try {\n // Initialize token refresher\n this.tokenRefresher = new TokenRefresher(\n this.storage,\n this.events,\n authConfig,\n );\n await this.tokenRefresher.initialize(authConfig);\n\n // Check current authentication state (this now includes token validation and refresh attempts)\n const isAuthenticated = await this.isAuthenticated();\n\n // Set authentication state on the token refresher\n // This will enable auto-refresh if the user is authenticated (including after successful refresh)\n this.tokenRefresher.setAuthenticationState(isAuthenticated);\n\n this.logger.info(\n \"SessionManager initialized with token refresh capability\",\n { isAuthenticated },\n );\n\n if (!isAuthenticated) {\n await this.clearSession();\n }\n } catch (error) {\n this.logger.error(\n \"Failed to initialize SessionManager with auth config:\",\n error,\n );\n this.events.emit(AuthEvent.TOKEN_REFRESH_ERROR, error);\n }\n }\n\n /**\n * Build current session from shared lib storage or backend API\n * For backend flows with httpOnly cookies, creates limited session when tokens aren't accessible\n */\n async getCurrentSession(): Promise<Session | null> {\n try {\n const tokens = await retrieveTokens(this.storage);\n\n const user = await this.getCurrentUser();\n\n // If we have tokens and user (normal flow), create full session\n if ((tokens?.id_token || tokens?.access_token) && user) {\n // Validate all available tokens\n const validationResults = await this.validateTokens({\n id_token: tokens.id_token,\n access_token: tokens.access_token,\n });\n\n // Check if any tokens failed validation\n if (\n !validationResults.idTokenValid ||\n !validationResults.accessTokenValid\n ) {\n this.logger.warn(\n \"Token validation failed in getCurrentSession, returning null\",\n );\n return null;\n }\n\n return {\n user,\n accessToken: tokens.access_token,\n idToken: tokens.id_token,\n refreshToken: tokens.refresh_token ?? undefined,\n expiresAt: tokens.oidc_session_expires_at ?? undefined,\n };\n }\n\n // If we have user but no accessible tokens (backend flow with httpOnly cookies),\n // create a limited session with just user info\n if (user && this.isBrowserCookieStorage()) {\n this.logger.debug(\n \"Creating limited session for backend flow (tokens in httpOnly cookies)\",\n );\n return {\n user,\n accessToken: undefined, // Not accessible in httpOnly cookies\n idToken: undefined, // Not accessible in httpOnly cookies\n refreshToken: undefined, // Not accessible in httpOnly cookies\n expiresAt: undefined, // Not accessible in httpOnly cookies\n };\n }\n\n this.logger.debug(\"No session available - no tokens or user found\");\n return null;\n } catch (error) {\n this.logger.error(\"Failed to load session:\", error);\n return null;\n }\n }\n\n /**\n * Check if user is authenticated using shared lib utilities\n * For backend flows with httpOnly cookies, falls back to API check\n *\n * This method now validates tokens on load and attempts refresh if:\n * - Tokens exist but are expired/invalid\n * - A refresh token is available\n */\n async isAuthenticated(): Promise<boolean> {\n try {\n // First, try the standard token-based check\n const tokens = await retrieveTokens(this.storage);\n\n // Normalize empty strings to null for consistent checking\n const hasIdToken = tokens?.id_token && tokens.id_token.trim() !== \"\";\n const hasRefreshToken =\n tokens?.refresh_token && tokens.refresh_token.trim() !== \"\";\n\n // If no tokens found, check for explicit initial user state in backend mode\n if (!hasIdToken && this.config.loginUrl && this.initialUser) {\n this.logger.debug(\n \"No tokens and initial user explicitly null in backend mode - not authenticated\",\n );\n this.logger.debug(\n \"No tokens but initial user provided in backend mode - considering authenticated\",\n { hasInitialUser: !!this.initialUser },\n );\n return true;\n }\n\n // If no tokens found and we're using BrowserCookieStorage,\n // try checking backend session (for httpOnly cookies)\n if (!hasIdToken && this.isBrowserCookieStorage()) {\n const backendSession = await this.checkBackendSession();\n this.logger.debug(\"No tokens accessible, checking backend session...\", {\n backendSession,\n });\n if (backendSession) {\n this.events.emit(AuthEvent.TOKEN_REFRESH_COMPLETE, null);\n }\n return backendSession;\n }\n\n // If we have tokens, validate them\n if (hasIdToken) {\n const validationResults = await this.validateTokens({\n id_token: tokens.id_token,\n access_token: tokens.access_token,\n });\n\n // Both tokens must be valid (if they exist) for authentication to be considered valid\n const allTokensValid =\n validationResults.idTokenValid && validationResults.accessTokenValid;\n\n if (allTokensValid) {\n this.logger.debug(\n \"All available tokens are valid, user is authenticated\",\n );\n return true;\n }\n\n // Some tokens are invalid/expired - attempt refresh if refresh token exists\n if (hasRefreshToken && this.tokenRefresher) {\n this.logger.info(\n \"Some tokens expired/invalid, attempting refresh with refresh token\",\n );\n\n try {\n // Attempt token refresh\n await this.tokenRefresher.refreshTokens();\n this.logger.info(\n \"Token refresh successful during authentication check\",\n );\n\n // Check if we now have valid tokens after refresh\n const refreshedTokens = await retrieveTokens(this.storage);\n const refreshedValidationResults = await this.validateTokens({\n id_token: refreshedTokens?.id_token,\n access_token: refreshedTokens?.access_token,\n });\n\n const allRefreshedTokensValid =\n refreshedValidationResults.idTokenValid &&\n refreshedValidationResults.accessTokenValid;\n\n if (allRefreshedTokensValid) {\n this.logger.info(\n \"Successfully restored session via refresh token\",\n );\n return true;\n }\n } catch (error) {\n this.logger.warn(\n \"Token refresh failed during authentication check:\",\n error,\n );\n // Clear invalid tokens and refresh token since refresh failed\n await clearTokens(this.storage);\n }\n } else {\n this.logger.warn(\n \"Some tokens invalid and no refresh token available, clearing tokens\",\n );\n await clearTokens(this.storage);\n }\n } else if (hasRefreshToken && this.tokenRefresher) {\n // No ID token but we have a refresh token - attempt to restore session\n this.logger.info(\n \"No ID token found but refresh token exists, attempting session restore\",\n );\n\n try {\n // Attempt token refresh\n await this.tokenRefresher.refreshTokens();\n this.logger.info(\"Token refresh successful during session restore\");\n\n // Check if we now have valid tokens after refresh\n const refreshedTokens = await retrieveTokens(this.storage);\n const refreshedValidationResults = await this.validateTokens({\n id_token: refreshedTokens?.id_token,\n access_token: refreshedTokens?.access_token,\n });\n\n const allRefreshedTokensValid =\n refreshedValidationResults.idTokenValid &&\n refreshedValidationResults.accessTokenValid;\n\n if (allRefreshedTokensValid) {\n this.logger.info(\n \"Successfully restored session from refresh token only\",\n );\n return true;\n }\n\n this.logger.info(\"Couldn't restore session from refresh token\");\n } catch (error) {\n this.logger.warn(\"Session restore from refresh token failed:\", error);\n // Clear invalid refresh token since refresh failed\n await clearTokens(this.storage);\n }\n }\n\n return false;\n } catch (error) {\n this.logger.error(\"Error checking authentication:\", error);\n return false;\n }\n }\n\n /**\n * Validate if a token is cryptographically valid and not expired\n * Uses proper JWT verification with signature validation using JWKS\n * @param token JWT token to validate\n * @param tokenType Type of token (for logging and cleanup purposes)\n * @returns true if token is valid, false if expired or invalid\n */\n private async validateToken(\n token: string,\n tokenType: \"id_token\" | \"access_token\" = \"id_token\",\n ): Promise<boolean> {\n try {\n // For backend flows with httpOnly cookies, we can't validate tokens client-side\n // since they're not accessible to JavaScript\n if (this.isBrowserCookieStorage()) {\n this.logger.debug(\n \"Backend flow: skipping client-side token validation\",\n );\n return true; // Backend will validate tokens server-side\n }\n\n // Configure verification options based on token type\n const verifyOptions: VerifyOptions = {\n issuer: addSlashIfNeeded(\n this.config.oauthServerBaseUrl ?? \"https://auth.civic.com/oauth/\",\n ),\n };\n\n // Set audience based on token type\n if (tokenType === \"id_token\" && this.config.clientId) {\n // ID tokens should have the client ID as audience for proper OIDC compliance\n verifyOptions.aud = this.config.clientId;\n } else if (tokenType === \"access_token\") {\n // Access tokens have \"civic\" as audience based on auth server configuration\n verifyOptions.aud = \"civic\";\n verifyOptions.clientId = this.config.clientId;\n }\n\n this.logger.debug(`Verifying ${tokenType} with options:`, verifyOptions);\n\n // Use the @civic/auth-verify package for proper JWT verification\n await verify(token, verifyOptions);\n\n this.logger.debug(`${tokenType} cryptographically verified and valid`);\n return true;\n } catch (error) {\n this.logger.warn(`${tokenType} validation failed`, error);\n // Clear the specific token that failed validation\n if (tokenType === \"id_token\") {\n this.storage.delete(OAuthTokenTypes.ID_TOKEN);\n } else if (tokenType === \"access_token\") {\n this.storage.delete(OAuthTokenTypes.ACCESS_TOKEN);\n }\n return false;\n }\n }\n\n /**\n * Validate both ID token and access token if they exist\n * @param tokens Token object containing id_token and access_token\n * @returns Object indicating which tokens are valid\n */\n private async validateTokens(tokens: {\n id_token?: string;\n access_token?: string;\n }): Promise<{\n idTokenValid: boolean;\n accessTokenValid: boolean;\n }> {\n const results = {\n idTokenValid: true, // Default to true if token doesn't exist\n accessTokenValid: true, // Default to true if token doesn't exist\n };\n\n // Validate ID token if it exists\n if (tokens.id_token && tokens.id_token.trim() !== \"\") {\n results.idTokenValid = await this.validateToken(\n tokens.id_token,\n \"id_token\",\n );\n }\n\n // Validate access token if it exists\n if (tokens.access_token && tokens.access_token.trim() !== \"\") {\n results.accessTokenValid = await this.validateToken(\n tokens.access_token,\n \"access_token\",\n );\n }\n\n return results;\n }\n\n /**\n * Check if we're using BrowserCookieStorage\n */\n private isBrowserCookieStorage(): boolean {\n return this.storage.constructor.name === \"BrowserCookieStorage\";\n }\n\n /**\n * Simple backend session check via API call (with caching)\n */\n private async checkBackendSession(): Promise<boolean> {\n try {\n // Check if we have a valid cached result\n if (this.backendSessionCache) {\n const age = Date.now() - this.backendSessionCache.timestamp;\n if (age < this.CACHE_DURATION) {\n this.logger.debug(\n `Using cached backend session result: ${this.backendSessionCache.result}`,\n );\n return this.backendSessionCache.result;\n }\n }\n\n if (!this.config.loginUrl) {\n return false;\n }\n\n const backendUrl = new URL(this.config.loginUrl).origin;\n const endpoints = getBackendEndpoints(this.config.backendEndpoints);\n const response = await fetch(\n `${resolveEndpointUrl(backendUrl, endpoints.user)}?optimisticRehydration=true`,\n {\n method: \"GET\",\n credentials: \"include\", // Send httpOnly cookies\n },\n );\n\n const result = response.ok;\n const user = await response.json();\n if (response.status !== 200 || !user) {\n this.backendSessionCache = {\n result: false,\n timestamp: Date.now(),\n };\n\n return false;\n }\n // Cache the result\n this.backendSessionCache = {\n result,\n timestamp: Date.now(),\n };\n\n this.logger.debug(\n `Backend session check: ${result} (cached for ${this.CACHE_DURATION / 1000}s)`,\n );\n return result;\n } catch (error) {\n this.logger.debug(\"Backend session check failed:\", error);\n\n // Cache negative result for shorter time\n this.backendSessionCache = {\n result: false,\n timestamp: Date.now(),\n };\n\n return false;\n }\n }\n\n /**\n * Get current user from shared lib storage, initial user, or backend API\n * For backend flows with httpOnly cookies, falls back to API check\n */\n async getCurrentUser(): Promise<User | null> {\n try {\n // First, try to get user from accessible tokens\n const user = await getUser(this.storage);\n if (user) {\n this.logger.debug(\"Found user from accessible tokens\");\n return user;\n }\n\n // If no user from tokens, check explicit initial user state\n if (this.initialUser !== undefined) {\n if (this.initialUser === null) {\n this.logger.debug(\n \"Initial user explicitly null - no user authenticated\",\n );\n return null;\n } else {\n this.logger.debug(\"Using initial user data to avoid backend call\");\n return this.initialUser;\n }\n }\n\n // If no user found and we're using BrowserCookieStorage,\n // try getting user from backend API (for httpOnly cookies)\n if (this.isBrowserCookieStorage()) {\n this.logger.debug(\n \"No user from tokens and no initial data, trying backend API...\",\n );\n return await this.getUserFromBackendApi();\n }\n\n this.logger.debug(\"No user found and not using browser cookie storage\");\n return null;\n } catch (error) {\n this.logger.error(\"Failed to get user from shared storage:\", error);\n return null;\n }\n }\n\n /**\n * Get user information from backend API (with caching)\n */\n private async getUserFromBackendApi(): Promise<User | null> {\n try {\n if (!this.config.loginUrl) {\n this.logger.debug(\"No backend URL available for user fetch\");\n return null;\n }\n\n this.logger.debug(\"Fetching user from backend API...\");\n\n const backendUrl = new URL(this.config.loginUrl).origin;\n const endpoints = getBackendEndpoints(this.config.backendEndpoints);\n const response = await fetch(\n resolveEndpointUrl(backendUrl, endpoints.user),\n {\n method: \"GET\",\n credentials: \"include\", // Send httpOnly cookies\n headers: { \"Content-Type\": \"application/json\" },\n },\n );\n\n if (response.ok) {\n const data = await response.json();\n const user = data.user;\n this.logger.debug(\"Successfully fetched user from backend API\");\n return user;\n } else {\n this.logger.debug(`Backend user fetch failed: ${response.status}`);\n return null;\n }\n } catch (error) {\n this.logger.debug(\"Backend user fetch failed:\", error);\n return null;\n }\n }\n\n /**\n * Clear all authentication data using shared lib utilities\n * @param preserveLogoutState - If true, preserves logout state for cleanup after redirect\n */\n async clearSession(preserveLogoutState: boolean = false): Promise<void> {\n try {\n // Stop token refresher so that in-flight refreshes are cancelled\n this.tokenRefresher?.setAuthenticationState(false);\n\n if (preserveLogoutState) {\n // During logout, we need to preserve logout state for cleanup after redirect\n await this.clearTokensExceptLogoutState();\n } else {\n // Normal session clearing - clear everything\n await clearTokens(this.storage);\n }\n\n // Clear user session using shared utilities\n const userSession = new GenericUserSession(this.storage);\n await userSession.clear();\n\n // Clear backend session cache\n this.backendSessionCache = null;\n\n this.events.emit(AuthEvent.USER_SESSION_CHANGED, null);\n this.logger.info(\"Session cleared using shared lib utilities\");\n } catch (error) {\n this.logger.error(\"Failed to clear session:\", error);\n throw error;\n }\n }\n\n /**\n * Clear tokens from storage except logout state\n * This is needed during logout to preserve the logout state for cleanup after redirect\n */\n private async clearTokensExceptLogoutState(): Promise<void> {\n // Clear all token-related keys except LOGOUT_STATE\n // These are the OAuth token types from the constants\n const keysToDelete = [\n OAuthTokenTypes.ID_TOKEN,\n OAuthTokenTypes.ACCESS_TOKEN,\n OAuthTokenTypes.REFRESH_TOKEN,\n OAuthTokenTypes.OIDC_SESSION_EXPIRES_AT,\n REFRESH_IN_PROGRESS,\n AUTOREFRESH_TIMEOUT_NAME,\n // Note: NOT clearing LOGOUT_STATE here - it's needed for cleanup after redirect\n ];\n\n const clearPromises = keysToDelete.map(async (key) => {\n await this.storage.delete(key);\n });\n\n await Promise.all(clearPromises);\n }\n\n /**\n * Manually trigger token refresh\n */\n async refreshTokens(): Promise<void> {\n if (!this.tokenRefresher) {\n throw new Error(\n \"Token refresher not initialized. Call initializeWithAuthConfig first.\",\n );\n }\n\n return this.tokenRefresher.refreshTokens();\n }\n\n /**\n * Get token refresher state for debugging\n */\n getTokenRefresherState(): {\n isInitialized: boolean;\n isAuthenticated: boolean;\n isAutoRefreshActive: boolean;\n } | null {\n return this.tokenRefresher?.getState() || null;\n }\n\n /**\n * Clean up resources when session manager is destroyed\n */\n async destroy(): Promise<void> {\n await this.tokenRefresher?.destroy();\n this.tokenRefresher = undefined;\n this.logger.info(\"SessionManager destroyed\");\n }\n}\n"]}
@@ -13,6 +13,7 @@ export declare class TokenRefresher {
13
13
  private isAuthenticated;
14
14
  private isDestroyed;
15
15
  private logger;
16
+ private focusListenerAdded;
16
17
  constructor(storage: AuthStorage, events: AuthenticationEvents, authConfig?: AuthConfig);
17
18
  /**
18
19
  * Initialize the token refresher with auth configuration
@@ -26,6 +27,8 @@ export declare class TokenRefresher {
26
27
  * Manually refresh tokens
27
28
  */
28
29
  refreshTokens(): Promise<void>;
30
+ private onWindowFocus;
31
+ private addAutoRefreshOnFocusListener;
29
32
  /**
30
33
  * Start automatic token refresh
31
34
  */
@@ -1 +1 @@
1
- {"version":3,"file":"TokenRefresher.d.ts","sourceRoot":"","sources":["../../../src/vanillajs/auth/TokenRefresher.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AAOtE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAMzD;;;GAGG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,SAAS,CAAC,CAEiB;IACnC,OAAO,CAAC,OAAO,CAAc;IAC7B,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,UAAU,CAAC,CAAa;IAChC,OAAO,CAAC,eAAe,CAAkB;IACzC,OAAO,CAAC,WAAW,CAAkB;IACrC,OAAO,CAAC,MAAM,CAAiC;gBAG7C,OAAO,EAAE,WAAW,EACpB,MAAM,EAAE,oBAAoB,EAC5B,UAAU,CAAC,EAAE,UAAU;IASzB;;OAEG;IACG,UAAU,CAAC,UAAU,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAsEvD;;OAEG;IACH,sBAAsB,CAAC,eAAe,EAAE,OAAO,GAAG,IAAI;IAgBtD;;OAEG;IACG,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;IAiDpC;;OAEG;YACW,gBAAgB;IAwB9B;;OAEG;IACH,OAAO,CAAC,eAAe;IAOvB;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAW9B;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAM9B;;OAEG;IACH,QAAQ,IAAI;QACV,aAAa,EAAE,OAAO,CAAC;QACvB,eAAe,EAAE,OAAO,CAAC;QACzB,mBAAmB,EAAE,OAAO,CAAC;KAC9B;CAOF"}
1
+ {"version":3,"file":"TokenRefresher.d.ts","sourceRoot":"","sources":["../../../src/vanillajs/auth/TokenRefresher.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AAOtE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAMzD;;;GAGG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,SAAS,CAAC,CAEiB;IACnC,OAAO,CAAC,OAAO,CAAc;IAC7B,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,UAAU,CAAC,CAAa;IAChC,OAAO,CAAC,eAAe,CAAkB;IACzC,OAAO,CAAC,WAAW,CAAkB;IACrC,OAAO,CAAC,MAAM,CAAiC;IAC/C,OAAO,CAAC,kBAAkB,CAAkB;gBAE1C,OAAO,EAAE,WAAW,EACpB,MAAM,EAAE,oBAAoB,EAC5B,UAAU,CAAC,EAAE,UAAU;IASzB;;OAEG;IACG,UAAU,CAAC,UAAU,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IA8EvD;;OAEG;IACH,sBAAsB,CAAC,eAAe,EAAE,OAAO,GAAG,IAAI;IAgBtD;;OAEG;IACG,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;IAiDpC,OAAO,CAAC,aAAa,CAGnB;IAEF,OAAO,CAAC,6BAA6B;IAMrC;;OAEG;YACW,gBAAgB;IAyB9B;;OAEG;IACH,OAAO,CAAC,eAAe;IASvB;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAW9B;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAM9B;;OAEG;IACH,QAAQ,IAAI;QACV,aAAa,EAAE,OAAO,CAAC;QACvB,eAAe,EAAE,OAAO,CAAC;QACzB,mBAAmB,EAAE,OAAO,CAAC;KAC9B;CAOF"}
@@ -2,7 +2,7 @@ import { AuthEvent } from "../types/index.js";
2
2
  import { BrowserAuthenticationRefresher, } from "../../shared/lib/BrowserAuthenticationRefresher.js";
3
3
  import { BackendAuthenticationRefresher } from "./BackendAuthenticationRefresher.js";
4
4
  import { createLogger } from "../utils/logger.js";
5
- import { retrieveOidcSessionExpiredAt } from "../../shared/lib/util.js";
5
+ import { retrieveOidcSessionExpiredAtSeconds } from "../../shared/lib/util.js";
6
6
  import { getUser } from "../../shared/lib/session.js";
7
7
  import { GenericUserSession } from "../../shared/lib/UserSession.js";
8
8
  /**
@@ -17,6 +17,7 @@ export class TokenRefresher {
17
17
  isAuthenticated = false;
18
18
  isDestroyed = false;
19
19
  logger = createLogger("token-refresh");
20
+ focusListenerAdded = false;
20
21
  constructor(storage, events, authConfig) {
21
22
  this.storage = storage;
22
23
  this.events = events;
@@ -33,6 +34,15 @@ export class TokenRefresher {
33
34
  try {
34
35
  // Clear any existing refresher
35
36
  await this.cleanup();
37
+ this.events.on(AuthEvent.SIGN_OUT_STARTED, () => {
38
+ this.stopAutoRefresh();
39
+ });
40
+ // ensure we start auto-refresh setup on sign-in
41
+ this.events.on(AuthEvent.SIGN_IN_COMPLETE, () => {
42
+ if (this.isDestroyed)
43
+ return;
44
+ this.setAuthenticationState(true);
45
+ });
36
46
  const onError = async (error) => {
37
47
  this.logger.error("Token refresh error:", error);
38
48
  this.events.emit(AuthEvent.TOKEN_REFRESH_ERROR, error);
@@ -48,7 +58,7 @@ export class TokenRefresher {
48
58
  this.logger.info("Initializing backend authentication refresher", {
49
59
  loginUrl: authConfig.loginUrl,
50
60
  });
51
- this.refresher = await BackendAuthenticationRefresher.build(authConfig, authConfig.loginUrl, onError, this.events);
61
+ this.refresher = await BackendAuthenticationRefresher.build(authConfig, this.storage, authConfig.loginUrl, onError, this.events);
52
62
  }
53
63
  else {
54
64
  // SPA authentication flow - use BrowserAuthenticationRefresher
@@ -141,6 +151,16 @@ export class TokenRefresher {
141
151
  throw error;
142
152
  }
143
153
  }
154
+ onWindowFocus = () => {
155
+ this.logger.debug("Window focused, checking token refresh..");
156
+ this.refresher?.setupAutorefresh();
157
+ };
158
+ addAutoRefreshOnFocusListener() {
159
+ if (!this.focusListenerAdded) {
160
+ this.focusListenerAdded = true;
161
+ window.addEventListener("focus", this.onWindowFocus);
162
+ }
163
+ }
144
164
  /**
145
165
  * Start automatic token refresh
146
166
  */
@@ -150,7 +170,7 @@ export class TokenRefresher {
150
170
  try {
151
171
  // Calculate when the next refresh will happen (same logic as BrowserAuthenticationRefresher)
152
172
  const now = Math.floor(Date.now() / 1000);
153
- const expiresAt = (await retrieveOidcSessionExpiredAt(this.storage)) || now + 60;
173
+ const expiresAt = (await retrieveOidcSessionExpiredAtSeconds(this.storage)) || now + 60;
154
174
  const bufferTime = 30; // 30 seconds buffer
155
175
  const refreshTime = Math.max(0, expiresAt - bufferTime - now);
156
176
  const nextRefreshDate = new Date((now + refreshTime) * 1000);
@@ -160,6 +180,7 @@ export class TokenRefresher {
160
180
  this.logger.warn("Could not calculate next refresh time:", error);
161
181
  }
162
182
  this.refresher.setupAutorefresh();
183
+ this.addAutoRefreshOnFocusListener();
163
184
  }
164
185
  }
165
186
  /**
@@ -169,6 +190,8 @@ export class TokenRefresher {
169
190
  if (this.refresher) {
170
191
  this.logger.info("Stopping automatic token refresh");
171
192
  this.refresher.clearAutorefresh();
193
+ window.removeEventListener("focus", this.onWindowFocus);
194
+ this.focusListenerAdded = false;
172
195
  }
173
196
  }
174
197
  /**
@@ -177,7 +200,7 @@ export class TokenRefresher {
177
200
  async cleanup() {
178
201
  this.logger.info("Cleaning up TokenRefresher");
179
202
  if (this.refresher) {
180
- this.refresher.clearAutorefresh();
203
+ this.stopAutoRefresh();
181
204
  this.refresher = undefined;
182
205
  }
183
206
  this.isAuthenticated = false;
@@ -1 +1 @@
1
- {"version":3,"file":"TokenRefresher.js","sourceRoot":"","sources":["../../../src/vanillajs/auth/TokenRefresher.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AuthStorage } from \"../../types.js\";\nimport type { AuthenticationEvents } from \"./AuthenticationEvents.js\";\nimport { AuthEvent } from \"../types/index.js\";\nimport {\n BrowserAuthenticationRefresher,\n type RefreshEventCallbacks,\n} from \"../../shared/lib/BrowserAuthenticationRefresher.js\";\nimport { BackendAuthenticationRefresher } from \"./BackendAuthenticationRefresher.js\";\nimport type { AuthConfig } from \"../../server/config.js\";\nimport { createLogger } from \"../utils/logger.js\";\nimport { retrieveOidcSessionExpiredAt } from \"../../shared/lib/util.js\";\nimport { getUser } from \"../../shared/lib/session.js\";\nimport { GenericUserSession } from \"../../shared/lib/UserSession.js\";\n\n/**\n * TokenRefresher handles automatic token refresh for vanilla.js implementation\n * Inspired by the React useRefresh hook and BrowserAuthenticationRefresher\n */\nexport class TokenRefresher {\n private refresher?:\n | BrowserAuthenticationRefresher\n | BackendAuthenticationRefresher;\n private storage: AuthStorage;\n private events: AuthenticationEvents;\n private authConfig?: AuthConfig;\n private isAuthenticated: boolean = false;\n private isDestroyed: boolean = false;\n private logger = createLogger(\"token-refresh\");\n\n constructor(\n storage: AuthStorage,\n events: AuthenticationEvents,\n authConfig?: AuthConfig,\n ) {\n this.storage = storage;\n this.events = events;\n this.authConfig = authConfig;\n\n this.logger.info(\"TokenRefresher initialized\");\n }\n\n /**\n * Initialize the token refresher with auth configuration\n */\n async initialize(authConfig: AuthConfig): Promise<void> {\n if (this.isDestroyed) return;\n\n this.authConfig = authConfig;\n\n try {\n // Clear any existing refresher\n await this.cleanup();\n\n const onError = async (error: Error) => {\n this.logger.error(\"Token refresh error:\", error);\n this.events.emit(AuthEvent.TOKEN_REFRESH_ERROR, error);\n\n // Clear auto-refresh on error\n this.refresher?.clearAutorefresh();\n\n // Optionally sign out the user on refresh token errors\n // This mirrors the React implementation behavior\n this.events.emit(AuthEvent.SIGN_OUT_STARTED, null);\n };\n\n // Determine if this is a backend flow or SPA flow\n if (authConfig.loginUrl) {\n // Backend authentication flow - use BackendAuthenticationRefresher\n this.logger.info(\"Initializing backend authentication refresher\", {\n loginUrl: authConfig.loginUrl,\n });\n\n this.refresher = await BackendAuthenticationRefresher.build(\n authConfig,\n authConfig.loginUrl,\n onError,\n this.events, // Pass events for consistency with BrowserAuthenticationRefresher\n );\n } else {\n // SPA authentication flow - use BrowserAuthenticationRefresher\n this.logger.info(\"Initializing browser authentication refresher\");\n\n // Create callbacks for refresh events\n const refreshEventCallbacks: RefreshEventCallbacks = {\n onRefreshStarted: () => {\n this.logger.info(\"Auto token refresh started\");\n this.events.emit(AuthEvent.TOKEN_REFRESH_STARTED, null);\n },\n onRefreshComplete: () => {\n this.logger.info(\"Auto token refresh completed\");\n this.events.emit(AuthEvent.TOKEN_REFRESH_COMPLETE, null);\n },\n onRefreshError: (error: Error) => {\n this.logger.error(\"Auto token refresh failed:\", error);\n this.events.emit(AuthEvent.TOKEN_REFRESH_ERROR, error);\n },\n };\n\n this.refresher = await BrowserAuthenticationRefresher.build(\n authConfig,\n this.storage,\n onError,\n undefined, // endpointOverrides\n refreshEventCallbacks,\n );\n }\n\n this.logger.info(\"TokenRefresher initialized successfully\");\n } catch (error) {\n this.logger.error(\"Failed to initialize TokenRefresher:\", error);\n this.events.emit(AuthEvent.TOKEN_REFRESH_ERROR, error);\n }\n }\n\n /**\n * Set authentication state and manage auto-refresh accordingly\n */\n setAuthenticationState(isAuthenticated: boolean): void {\n if (this.isDestroyed) return;\n\n this.isAuthenticated = isAuthenticated;\n\n if (isAuthenticated && this.refresher) {\n // Fire and forget the async call - we don't want to make setAuthenticationState async\n // as it would break the interface\n this.startAutoRefresh().catch((error) => {\n this.logger.error(\"Error starting auto refresh:\", error);\n });\n } else {\n this.stopAutoRefresh();\n }\n }\n\n /**\n * Manually refresh tokens\n */\n async refreshTokens(): Promise<void> {\n if (this.isDestroyed || !this.refresher) {\n const errorMsg = `TokenRefresher not initialized or destroyed. isDestroyed: ${this.isDestroyed}, hasRefresher: ${!!this.refresher}`;\n this.logger.error(errorMsg);\n throw new Error(errorMsg);\n }\n\n try {\n this.events.emit(AuthEvent.TOKEN_REFRESH_STARTED, null);\n\n this.logger.info(\"Starting manual token refresh\");\n\n await this.refresher.refreshTokens();\n\n // For BrowserAuthenticationRefresher (SPA flows), we need to restore user data\n // BackendAuthenticationRefresher uses HTTP-only cookies so user data is handled server-side\n if (this.refresher instanceof BrowserAuthenticationRefresher) {\n try {\n this.logger.info(\"Restoring user data after token refresh\");\n\n // Get user info from the refreshed tokens\n const user = await getUser(this.storage);\n if (user) {\n // Store user data back to localStorage\n const userSession = new GenericUserSession(this.storage);\n await userSession.set(user);\n this.logger.info(\"User data restored successfully\");\n } else {\n this.logger.warn(\"No user data found after token refresh\");\n }\n } catch (userError) {\n // Don't fail the entire refresh if user restoration fails\n // The tokens are still valid, just log the error\n this.logger.error(\n \"Failed to restore user data after token refresh:\",\n userError,\n );\n }\n }\n\n this.events.emit(AuthEvent.TOKEN_REFRESH_COMPLETE, null);\n this.logger.info(\"Manual token refresh completed\");\n } catch (error) {\n this.logger.error(\"Manual token refresh failed:\", error);\n this.events.emit(AuthEvent.TOKEN_REFRESH_ERROR, error);\n throw error;\n }\n }\n\n /**\n * Start automatic token refresh\n */\n private async startAutoRefresh(): Promise<void> {\n if (this.refresher && this.isAuthenticated) {\n this.logger.info(\"Starting automatic token refresh\");\n\n try {\n // Calculate when the next refresh will happen (same logic as BrowserAuthenticationRefresher)\n const now = Math.floor(Date.now() / 1000);\n const expiresAt =\n (await retrieveOidcSessionExpiredAt(this.storage)) || now + 60;\n const bufferTime = 30; // 30 seconds buffer\n const refreshTime = Math.max(0, expiresAt - bufferTime - now);\n\n const nextRefreshDate = new Date((now + refreshTime) * 1000);\n this.logger.info(\n `Next token refresh scheduled for: ${nextRefreshDate.toISOString()} (in ${refreshTime} seconds)`,\n );\n } catch (error) {\n this.logger.warn(\"Could not calculate next refresh time:\", error);\n }\n\n this.refresher.setupAutorefresh();\n }\n }\n\n /**\n * Stop automatic token refresh\n */\n private stopAutoRefresh(): void {\n if (this.refresher) {\n this.logger.info(\"Stopping automatic token refresh\");\n this.refresher.clearAutorefresh();\n }\n }\n\n /**\n * Clean up resources\n */\n async cleanup(): Promise<void> {\n this.logger.info(\"Cleaning up TokenRefresher\");\n\n if (this.refresher) {\n this.refresher.clearAutorefresh();\n this.refresher = undefined;\n }\n\n this.isAuthenticated = false;\n }\n\n /**\n * Destroy the token refresher permanently\n */\n async destroy(): Promise<void> {\n this.isDestroyed = true;\n await this.cleanup();\n this.logger.info(\"TokenRefresher destroyed\");\n }\n\n /**\n * Get current refresh state\n */\n getState(): {\n isInitialized: boolean;\n isAuthenticated: boolean;\n isAutoRefreshActive: boolean;\n } {\n return {\n isInitialized: !!this.refresher,\n isAuthenticated: this.isAuthenticated,\n isAutoRefreshActive: this.isAuthenticated && !!this.refresher,\n };\n }\n}\n"]}
1
+ {"version":3,"file":"TokenRefresher.js","sourceRoot":"","sources":["../../../src/vanillajs/auth/TokenRefresher.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AuthStorage } from \"../../types.js\";\nimport type { AuthenticationEvents } from \"./AuthenticationEvents.js\";\nimport { AuthEvent } from \"../types/index.js\";\nimport {\n BrowserAuthenticationRefresher,\n type RefreshEventCallbacks,\n} from \"../../shared/lib/BrowserAuthenticationRefresher.js\";\nimport { BackendAuthenticationRefresher } from \"./BackendAuthenticationRefresher.js\";\nimport type { AuthConfig } from \"../../server/config.js\";\nimport { createLogger } from \"../utils/logger.js\";\nimport { retrieveOidcSessionExpiredAtSeconds } from \"../../shared/lib/util.js\";\nimport { getUser } from \"../../shared/lib/session.js\";\nimport { GenericUserSession } from \"../../shared/lib/UserSession.js\";\n\n/**\n * TokenRefresher handles automatic token refresh for vanilla.js implementation\n * Inspired by the React useRefresh hook and BrowserAuthenticationRefresher\n */\nexport class TokenRefresher {\n private refresher?:\n | BrowserAuthenticationRefresher\n | BackendAuthenticationRefresher;\n private storage: AuthStorage;\n private events: AuthenticationEvents;\n private authConfig?: AuthConfig;\n private isAuthenticated: boolean = false;\n private isDestroyed: boolean = false;\n private logger = createLogger(\"token-refresh\");\n private focusListenerAdded: boolean = false;\n constructor(\n storage: AuthStorage,\n events: AuthenticationEvents,\n authConfig?: AuthConfig,\n ) {\n this.storage = storage;\n this.events = events;\n this.authConfig = authConfig;\n\n this.logger.info(\"TokenRefresher initialized\");\n }\n\n /**\n * Initialize the token refresher with auth configuration\n */\n async initialize(authConfig: AuthConfig): Promise<void> {\n if (this.isDestroyed) return;\n\n this.authConfig = authConfig;\n\n try {\n // Clear any existing refresher\n await this.cleanup();\n this.events.on(AuthEvent.SIGN_OUT_STARTED, () => {\n this.stopAutoRefresh();\n });\n // ensure we start auto-refresh setup on sign-in\n this.events.on(AuthEvent.SIGN_IN_COMPLETE, () => {\n if (this.isDestroyed) return;\n this.setAuthenticationState(true);\n });\n const onError = async (error: Error) => {\n this.logger.error(\"Token refresh error:\", error);\n this.events.emit(AuthEvent.TOKEN_REFRESH_ERROR, error);\n\n // Clear auto-refresh on error\n this.refresher?.clearAutorefresh();\n\n // Optionally sign out the user on refresh token errors\n // This mirrors the React implementation behavior\n this.events.emit(AuthEvent.SIGN_OUT_STARTED, null);\n };\n\n // Determine if this is a backend flow or SPA flow\n if (authConfig.loginUrl) {\n // Backend authentication flow - use BackendAuthenticationRefresher\n this.logger.info(\"Initializing backend authentication refresher\", {\n loginUrl: authConfig.loginUrl,\n });\n\n this.refresher = await BackendAuthenticationRefresher.build(\n authConfig,\n this.storage,\n authConfig.loginUrl,\n onError,\n this.events, // Pass events for consistency with BrowserAuthenticationRefresher\n );\n } else {\n // SPA authentication flow - use BrowserAuthenticationRefresher\n this.logger.info(\"Initializing browser authentication refresher\");\n\n // Create callbacks for refresh events\n const refreshEventCallbacks: RefreshEventCallbacks = {\n onRefreshStarted: () => {\n this.logger.info(\"Auto token refresh started\");\n this.events.emit(AuthEvent.TOKEN_REFRESH_STARTED, null);\n },\n onRefreshComplete: () => {\n this.logger.info(\"Auto token refresh completed\");\n this.events.emit(AuthEvent.TOKEN_REFRESH_COMPLETE, null);\n },\n onRefreshError: (error: Error) => {\n this.logger.error(\"Auto token refresh failed:\", error);\n this.events.emit(AuthEvent.TOKEN_REFRESH_ERROR, error);\n },\n };\n\n this.refresher = await BrowserAuthenticationRefresher.build(\n authConfig,\n this.storage,\n onError,\n undefined, // endpointOverrides\n refreshEventCallbacks,\n );\n }\n\n this.logger.info(\"TokenRefresher initialized successfully\");\n } catch (error) {\n this.logger.error(\"Failed to initialize TokenRefresher:\", error);\n this.events.emit(AuthEvent.TOKEN_REFRESH_ERROR, error);\n }\n }\n\n /**\n * Set authentication state and manage auto-refresh accordingly\n */\n setAuthenticationState(isAuthenticated: boolean): void {\n if (this.isDestroyed) return;\n\n this.isAuthenticated = isAuthenticated;\n\n if (isAuthenticated && this.refresher) {\n // Fire and forget the async call - we don't want to make setAuthenticationState async\n // as it would break the interface\n this.startAutoRefresh().catch((error) => {\n this.logger.error(\"Error starting auto refresh:\", error);\n });\n } else {\n this.stopAutoRefresh();\n }\n }\n\n /**\n * Manually refresh tokens\n */\n async refreshTokens(): Promise<void> {\n if (this.isDestroyed || !this.refresher) {\n const errorMsg = `TokenRefresher not initialized or destroyed. isDestroyed: ${this.isDestroyed}, hasRefresher: ${!!this.refresher}`;\n this.logger.error(errorMsg);\n throw new Error(errorMsg);\n }\n\n try {\n this.events.emit(AuthEvent.TOKEN_REFRESH_STARTED, null);\n\n this.logger.info(\"Starting manual token refresh\");\n\n await this.refresher.refreshTokens();\n\n // For BrowserAuthenticationRefresher (SPA flows), we need to restore user data\n // BackendAuthenticationRefresher uses HTTP-only cookies so user data is handled server-side\n if (this.refresher instanceof BrowserAuthenticationRefresher) {\n try {\n this.logger.info(\"Restoring user data after token refresh\");\n\n // Get user info from the refreshed tokens\n const user = await getUser(this.storage);\n if (user) {\n // Store user data back to localStorage\n const userSession = new GenericUserSession(this.storage);\n await userSession.set(user);\n this.logger.info(\"User data restored successfully\");\n } else {\n this.logger.warn(\"No user data found after token refresh\");\n }\n } catch (userError) {\n // Don't fail the entire refresh if user restoration fails\n // The tokens are still valid, just log the error\n this.logger.error(\n \"Failed to restore user data after token refresh:\",\n userError,\n );\n }\n }\n\n this.events.emit(AuthEvent.TOKEN_REFRESH_COMPLETE, null);\n this.logger.info(\"Manual token refresh completed\");\n } catch (error) {\n this.logger.error(\"Manual token refresh failed:\", error);\n this.events.emit(AuthEvent.TOKEN_REFRESH_ERROR, error);\n throw error;\n }\n }\n\n private onWindowFocus = () => {\n this.logger.debug(\"Window focused, checking token refresh..\");\n this.refresher?.setupAutorefresh();\n };\n\n private addAutoRefreshOnFocusListener() {\n if (!this.focusListenerAdded) {\n this.focusListenerAdded = true;\n window.addEventListener(\"focus\", this.onWindowFocus);\n }\n }\n /**\n * Start automatic token refresh\n */\n private async startAutoRefresh(): Promise<void> {\n if (this.refresher && this.isAuthenticated) {\n this.logger.info(\"Starting automatic token refresh\");\n\n try {\n // Calculate when the next refresh will happen (same logic as BrowserAuthenticationRefresher)\n const now = Math.floor(Date.now() / 1000);\n const expiresAt =\n (await retrieveOidcSessionExpiredAtSeconds(this.storage)) || now + 60;\n const bufferTime = 30; // 30 seconds buffer\n const refreshTime = Math.max(0, expiresAt - bufferTime - now);\n\n const nextRefreshDate = new Date((now + refreshTime) * 1000);\n this.logger.info(\n `Next token refresh scheduled for: ${nextRefreshDate.toISOString()} (in ${refreshTime} seconds)`,\n );\n } catch (error) {\n this.logger.warn(\"Could not calculate next refresh time:\", error);\n }\n\n this.refresher.setupAutorefresh();\n this.addAutoRefreshOnFocusListener();\n }\n }\n\n /**\n * Stop automatic token refresh\n */\n private stopAutoRefresh(): void {\n if (this.refresher) {\n this.logger.info(\"Stopping automatic token refresh\");\n this.refresher.clearAutorefresh();\n window.removeEventListener(\"focus\", this.onWindowFocus);\n this.focusListenerAdded = false;\n }\n }\n\n /**\n * Clean up resources\n */\n async cleanup(): Promise<void> {\n this.logger.info(\"Cleaning up TokenRefresher\");\n\n if (this.refresher) {\n this.stopAutoRefresh();\n this.refresher = undefined;\n }\n\n this.isAuthenticated = false;\n }\n\n /**\n * Destroy the token refresher permanently\n */\n async destroy(): Promise<void> {\n this.isDestroyed = true;\n await this.cleanup();\n this.logger.info(\"TokenRefresher destroyed\");\n }\n\n /**\n * Get current refresh state\n */\n getState(): {\n isInitialized: boolean;\n isAuthenticated: boolean;\n isAutoRefreshActive: boolean;\n } {\n return {\n isInitialized: !!this.refresher,\n isAuthenticated: this.isAuthenticated,\n isAutoRefreshActive: this.isAuthenticated && !!this.refresher,\n };\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"ConfigProcessor.d.ts","sourceRoot":"","sources":["../../../../src/vanillajs/auth/config/ConfigProcessor.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,qBAAqB,EACrB,wBAAwB,EAEzB,MAAM,uBAAuB,CAAC;AAO/B;;GAEG;AACH,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,qBAAqB,GAC5B,wBAAwB,CA4E1B"}
1
+ {"version":3,"file":"ConfigProcessor.d.ts","sourceRoot":"","sources":["../../../../src/vanillajs/auth/config/ConfigProcessor.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,qBAAqB,EACrB,wBAAwB,EAEzB,MAAM,uBAAuB,CAAC;AAO/B;;GAEG;AACH,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,qBAAqB,GAC5B,wBAAwB,CA8E1B"}
@@ -42,7 +42,9 @@ export function processConfigWithDefaults(config) {
42
42
  // If loginUrl is provided (backend integration), automatically use BrowserCookieStorage
43
43
  // Otherwise, use provided storageAdapter or default to LocalStorageAdapter
44
44
  const storageAdapter = config.loginUrl
45
- ? new BrowserCookieStorage()
45
+ ? new BrowserCookieStorage({
46
+ path: config.basePath || "/", // Use basePath as cookie path
47
+ })
46
48
  : config.storageAdapter || new LocalStorageAdapter();
47
49
  return {
48
50
  ...config,
@@ -1 +1 @@
1
- {"version":3,"file":"ConfigProcessor.js","sourceRoot":"","sources":["../../../../src/vanillajs/auth/config/ConfigProcessor.ts"],"names":[],"mappings":"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","sourcesContent":["import { LocalStorageAdapter } from \"../../../browser/storage.js\";\nimport { BrowserCookieStorage } from \"../../../shared/lib/BrowserCookieStorage.js\";\nimport { DEFAULT_SCOPES, DEFAULT_AUTH_SERVER } from \"../../../constants.js\";\nimport type { DisplayMode } from \"../../../types.js\";\nimport type {\n CivicAuthClientConfig,\n ProcessedCivicAuthConfig,\n LoggingConfig,\n} from \"../types/AuthTypes.js\";\nimport {\n CivicAuthError,\n CivicAuthErrorCode,\n CIVIC_AUTH_CONSTANTS,\n} from \"../types/AuthTypes.js\";\n\n/**\n * Process the configuration with defaults and validation\n */\nexport function processConfigWithDefaults(\n config: CivicAuthClientConfig,\n): ProcessedCivicAuthConfig {\n // Validate required configuration\n validateRequiredConfig(config);\n\n const loggingConfig: LoggingConfig = {\n enabled: false,\n namespace: \"*\",\n level: \"debug\" as const,\n ...config.logging,\n };\n\n // Handle displayMode proxy: map \"embedded\" to \"iframe\" + iframeDisplayMode: \"embedded\"\n // the original displaymode doesn't suppors embedded, so we need to proxy it to iframe + iframeDisplayMode: \"embedded\"\n const originalDisplayMode = config.displayMode || \"iframe\";\n const processedDisplayMode: DisplayMode =\n originalDisplayMode === \"embedded\" ? \"iframe\" : originalDisplayMode;\n\n // Determine iframeDisplayMode with proper precedence:\n // 1. User explicitly provided iframeDisplayMode (highest priority)\n // 2. If displayMode is \"embedded\", set to \"embedded\"\n // 3. Default to \"modal\" for iframe mode\n const processedIframeDisplayMode =\n config.iframeDisplayMode ??\n (originalDisplayMode === \"embedded\"\n ? \"embedded\"\n : processedDisplayMode === \"iframe\"\n ? \"modal\"\n : undefined);\n\n // Determine preloadIframe with proper precedence:\n // 1. User explicitly provided preloadIframe (highest priority)\n // 2. If displayMode is \"embedded\", set to false (better for embedded visibility)\n // 3. Default to true\n const processedPreloadIframe =\n config.preloadIframe ?? originalDisplayMode !== \"embedded\";\n\n // Process redirectUrl - default to current page without query parameters\n const redirectUrl =\n config.redirectUrl ||\n `${window.location.origin}${window.location.pathname}`;\n\n // Process logoutRedirectUrl - default to redirectUrl if not provided (same behavior as reactjs implementation)\n const logoutRedirectUrl = config.logoutRedirectUrl || redirectUrl;\n\n // Auto-select storage adapter based on loginUrl\n // If loginUrl is provided (backend integration), automatically use BrowserCookieStorage\n // Otherwise, use provided storageAdapter or default to LocalStorageAdapter\n const storageAdapter = config.loginUrl\n ? new BrowserCookieStorage()\n : config.storageAdapter || new LocalStorageAdapter();\n\n return {\n ...config,\n redirectUrl,\n logoutRedirectUrl,\n oauthServerBaseUrl: config.oauthServerBaseUrl || DEFAULT_AUTH_SERVER,\n scopes: config.scopes || DEFAULT_SCOPES,\n textSignals: config.textSignals || {\n success: \"Authentication successful!\",\n error: \"Authentication failed. Please try again.\",\n },\n displayMode: processedDisplayMode,\n iframeDisplayMode: processedIframeDisplayMode,\n authProcessTimeout:\n config.authProcessTimeout ||\n CIVIC_AUTH_CONSTANTS.DEFAULT_AUTH_PROCESS_TIMEOUT,\n iframeId: config.iframeId || CIVIC_AUTH_CONSTANTS.DEFAULT_IFRAME_ID,\n prompt: \"consent\",\n logging: loggingConfig,\n storageAdapter,\n loginUrl: config.loginUrl, // Include loginUrl in processed config\n backendEndpoints: config.backendEndpoints, // Include backend endpoints in processed config\n preloadIframe: processedPreloadIframe, // Use the processed preloadIframe value\n autoRedirect: config.autoRedirect !== false, // Default to true unless explicitly set to false\n loginSuccessUrl: config.loginSuccessUrl, // Include loginSuccessUrl in processed config\n } as ProcessedCivicAuthConfig; // Type assertion: we've validated the config and ensured all required properties are present\n}\n\n/**\n * Validates required configuration properties\n */\nfunction validateRequiredConfig(config: CivicAuthClientConfig): void {\n // Dynamic validation: clientId is only required if loginUrl is not provided\n if (!config.loginUrl && !config.clientId) {\n throw new CivicAuthError(\n \"CivicAuth: clientId is required when loginUrl is not provided.\",\n CivicAuthErrorCode.CONFIG_REQUIRED,\n );\n }\n\n // Add any config here that is critical to the auth process\n}\n"]}
1
+ {"version":3,"file":"ConfigProcessor.js","sourceRoot":"","sources":["../../../../src/vanillajs/auth/config/ConfigProcessor.ts"],"names":[],"mappings":"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","sourcesContent":["import { LocalStorageAdapter } from \"../../../browser/storage.js\";\nimport { BrowserCookieStorage } from \"../../../shared/lib/BrowserCookieStorage.js\";\nimport { DEFAULT_SCOPES, DEFAULT_AUTH_SERVER } from \"../../../constants.js\";\nimport type { DisplayMode } from \"../../../types.js\";\nimport type {\n CivicAuthClientConfig,\n ProcessedCivicAuthConfig,\n LoggingConfig,\n} from \"../types/AuthTypes.js\";\nimport {\n CivicAuthError,\n CivicAuthErrorCode,\n CIVIC_AUTH_CONSTANTS,\n} from \"../types/AuthTypes.js\";\n\n/**\n * Process the configuration with defaults and validation\n */\nexport function processConfigWithDefaults(\n config: CivicAuthClientConfig,\n): ProcessedCivicAuthConfig {\n // Validate required configuration\n validateRequiredConfig(config);\n\n const loggingConfig: LoggingConfig = {\n enabled: false,\n namespace: \"*\",\n level: \"debug\" as const,\n ...config.logging,\n };\n\n // Handle displayMode proxy: map \"embedded\" to \"iframe\" + iframeDisplayMode: \"embedded\"\n // the original displaymode doesn't suppors embedded, so we need to proxy it to iframe + iframeDisplayMode: \"embedded\"\n const originalDisplayMode = config.displayMode || \"iframe\";\n const processedDisplayMode: DisplayMode =\n originalDisplayMode === \"embedded\" ? \"iframe\" : originalDisplayMode;\n\n // Determine iframeDisplayMode with proper precedence:\n // 1. User explicitly provided iframeDisplayMode (highest priority)\n // 2. If displayMode is \"embedded\", set to \"embedded\"\n // 3. Default to \"modal\" for iframe mode\n const processedIframeDisplayMode =\n config.iframeDisplayMode ??\n (originalDisplayMode === \"embedded\"\n ? \"embedded\"\n : processedDisplayMode === \"iframe\"\n ? \"modal\"\n : undefined);\n\n // Determine preloadIframe with proper precedence:\n // 1. User explicitly provided preloadIframe (highest priority)\n // 2. If displayMode is \"embedded\", set to false (better for embedded visibility)\n // 3. Default to true\n const processedPreloadIframe =\n config.preloadIframe ?? originalDisplayMode !== \"embedded\";\n\n // Process redirectUrl - default to current page without query parameters\n const redirectUrl =\n config.redirectUrl ||\n `${window.location.origin}${window.location.pathname}`;\n\n // Process logoutRedirectUrl - default to redirectUrl if not provided (same behavior as reactjs implementation)\n const logoutRedirectUrl = config.logoutRedirectUrl || redirectUrl;\n\n // Auto-select storage adapter based on loginUrl\n // If loginUrl is provided (backend integration), automatically use BrowserCookieStorage\n // Otherwise, use provided storageAdapter or default to LocalStorageAdapter\n const storageAdapter = config.loginUrl\n ? new BrowserCookieStorage({\n path: config.basePath || \"/\", // Use basePath as cookie path\n })\n : config.storageAdapter || new LocalStorageAdapter();\n\n return {\n ...config,\n redirectUrl,\n logoutRedirectUrl,\n oauthServerBaseUrl: config.oauthServerBaseUrl || DEFAULT_AUTH_SERVER,\n scopes: config.scopes || DEFAULT_SCOPES,\n textSignals: config.textSignals || {\n success: \"Authentication successful!\",\n error: \"Authentication failed. Please try again.\",\n },\n displayMode: processedDisplayMode,\n iframeDisplayMode: processedIframeDisplayMode,\n authProcessTimeout:\n config.authProcessTimeout ||\n CIVIC_AUTH_CONSTANTS.DEFAULT_AUTH_PROCESS_TIMEOUT,\n iframeId: config.iframeId || CIVIC_AUTH_CONSTANTS.DEFAULT_IFRAME_ID,\n prompt: \"consent\",\n logging: loggingConfig,\n storageAdapter,\n loginUrl: config.loginUrl, // Include loginUrl in processed config\n backendEndpoints: config.backendEndpoints, // Include backend endpoints in processed config\n preloadIframe: processedPreloadIframe, // Use the processed preloadIframe value\n autoRedirect: config.autoRedirect !== false, // Default to true unless explicitly set to false\n loginSuccessUrl: config.loginSuccessUrl, // Include loginSuccessUrl in processed config\n } as ProcessedCivicAuthConfig; // Type assertion: we've validated the config and ensured all required properties are present\n}\n\n/**\n * Validates required configuration properties\n */\nfunction validateRequiredConfig(config: CivicAuthClientConfig): void {\n // Dynamic validation: clientId is only required if loginUrl is not provided\n if (!config.loginUrl && !config.clientId) {\n throw new CivicAuthError(\n \"CivicAuth: clientId is required when loginUrl is not provided.\",\n CivicAuthErrorCode.CONFIG_REQUIRED,\n );\n }\n\n // Add any config here that is critical to the auth process\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"IframeAuthHandler.d.ts","sourceRoot":"","sources":["../../../../src/vanillajs/auth/handlers/IframeAuthHandler.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAC;AAGtE,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAC9D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAI1D,MAAM,WAAW,uBAAuB;IACtC,MAAM,EAAE,wBAAwB,CAAC;IACjC,MAAM,EAAE,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC;IACxC,aAAa,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,IAAI,CAAC;IAC5C,WAAW,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACpC,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,cAAc,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,CAAC;CAC/C;AAED,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,MAAM,CAA2B;IACzC,OAAO,CAAC,MAAM,CAAiC;IAC/C,OAAO,CAAC,aAAa,CAA+B;IACpD,OAAO,CAAC,WAAW,CAAyB;IAC5C,OAAO,CAAC,OAAO,CAAa;IAC5B,OAAO,CAAC,cAAc,CAAgC;IACtD,OAAO,CAAC,aAAa,CAAC,CAAgB;IACtC,OAAO,CAAC,aAAa,CAAC,CAAoB;IAC1C,OAAO,CAAC,cAAc,CAAC,CAAiB;IACxC,OAAO,CAAC,uBAAuB,CAA+B;IAC9D,OAAO,CAAC,gBAAgB,CAAU;gBAEtB,aAAa,EAAE,uBAAuB;IAsClD;;;OAGG;IACU,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IA4DjD,gBAAgB,CAC3B,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,iBAAiB,CAAC;IAiItB,gBAAgB,IAAI,aAAa,GAAG,SAAS;IAI7C,gBAAgB,IAAI,iBAAiB,GAAG,SAAS;IAIjD,aAAa,IAAI,IAAI;IA0C5B,OAAO,CAAC,4BAA4B;IAgBpC,OAAO,CAAC,oBAAoB;IAe5B,OAAO,CAAC,mBAAmB;IA+B3B,OAAO,CAAC,0BAA0B;IA4BlC,OAAO,CAAC,wBAAwB;IAsDhC,OAAO,CAAC,2BAA2B;IAgEnC,OAAO,CAAC,mBAAmB;IAsD3B,OAAO,CAAC,mBAAmB;IAiC3B,OAAO,CAAC,+BAA+B;IAmGvC,OAAO,CAAC,kBAAkB;IAgCnB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IA+BxC;;OAEG;IACI,iBAAiB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;IAKhD;;OAEG;IACI,iBAAiB,IAAI,OAAO;IAInC;;;;;;;;;;;;;;;;;OAiBG;IACI,kBAAkB,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO;IAShD;;;;;OAKG;IACI,eAAe,IAAI,IAAI;IAW9B;;OAEG;IACI,eAAe,IAAI,IAAI;CAU/B"}
1
+ {"version":3,"file":"IframeAuthHandler.d.ts","sourceRoot":"","sources":["../../../../src/vanillajs/auth/handlers/IframeAuthHandler.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAC;AAGtE,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAC9D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAI1D,MAAM,WAAW,uBAAuB;IACtC,MAAM,EAAE,wBAAwB,CAAC;IACjC,MAAM,EAAE,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC;IACxC,aAAa,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,IAAI,CAAC;IAC5C,WAAW,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACpC,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,cAAc,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,CAAC;CAC/C;AAED,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,MAAM,CAA2B;IACzC,OAAO,CAAC,MAAM,CAAiC;IAC/C,OAAO,CAAC,aAAa,CAA+B;IACpD,OAAO,CAAC,WAAW,CAAyB;IAC5C,OAAO,CAAC,OAAO,CAAa;IAC5B,OAAO,CAAC,cAAc,CAAgC;IACtD,OAAO,CAAC,aAAa,CAAC,CAAgB;IACtC,OAAO,CAAC,aAAa,CAAC,CAAoB;IAC1C,OAAO,CAAC,cAAc,CAAC,CAAiB;IACxC,OAAO,CAAC,uBAAuB,CAA+B;IAC9D,OAAO,CAAC,gBAAgB,CAAU;gBAEtB,aAAa,EAAE,uBAAuB;IAsClD;;;OAGG;IACU,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IA4DjD,gBAAgB,CAC3B,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,iBAAiB,CAAC;IAiItB,gBAAgB,IAAI,aAAa,GAAG,SAAS;IAI7C,gBAAgB,IAAI,iBAAiB,GAAG,SAAS;IAIjD,aAAa,IAAI,IAAI;IA0C5B,OAAO,CAAC,4BAA4B;IAgBpC,OAAO,CAAC,oBAAoB;IAe5B,OAAO,CAAC,mBAAmB;IA+B3B,OAAO,CAAC,0BAA0B;IA4BlC,OAAO,CAAC,wBAAwB;IAsDhC,OAAO,CAAC,2BAA2B;IAgEnC,OAAO,CAAC,mBAAmB;IA6E3B,OAAO,CAAC,mBAAmB;IAiC3B,OAAO,CAAC,+BAA+B;IAmGvC,OAAO,CAAC,kBAAkB;IAgCnB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IA+BxC;;OAEG;IACI,iBAAiB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;IAKhD;;OAEG;IACI,iBAAiB,IAAI,OAAO;IAInC;;;;;;;;;;;;;;;;;OAiBG;IACI,kBAAkB,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO;IAShD;;;;;OAKG;IACI,eAAe,IAAI,IAAI;IAW9B;;OAEG;IACI,eAAe,IAAI,IAAI;CAU/B"}
@@ -381,12 +381,30 @@ export class IframeAuthHandler {
381
381
  checkIframeRedirect() {
382
382
  try {
383
383
  const currentIframeHref = this.iframeElement?.contentWindow?.location.href;
384
+ const currentIframeOrigin = this.iframeElement?.contentWindow?.location.origin;
385
+ const currentIframePath = this.iframeElement?.contentWindow?.location.pathname;
384
386
  if (currentIframeHref) {
385
387
  this.logger.debug("Iframe current href accessible", {
386
388
  href: currentIframeHref,
387
389
  redirectUrl: this.config.redirectUrl,
388
390
  startsWithRedirect: currentIframeHref.startsWith(this.config.redirectUrl),
389
391
  });
392
+ // In Safari, the iframe manager may not catch the previous URL changes
393
+ // and we only get the current URL after the redirect to the successful login
394
+ // in this case we want to reload the page as we should have a valid session
395
+ if (!(currentIframePath === "/login" &&
396
+ currentIframeOrigin?.endsWith("civic.com")) && // special case for civic same-domain portal/login-app
397
+ currentIframeOrigin === new URL(this.config.redirectUrl).origin &&
398
+ !currentIframeHref.startsWith(this.config.redirectUrl) // we don't want to reload if we're on the redirect as we need to handle callback
399
+ ) {
400
+ this.logger.info("Iframe has navigated to the success URL, reloading the page to reflect the new state.");
401
+ this.config.events?.emit(AuthEvent.URL_CHANGE, {
402
+ url: currentIframeHref,
403
+ source: "login", // this means the page will do a 'hard' reload which is required for the UserButton etc. to take state changes into account
404
+ });
405
+ this.iframeManager?.hide();
406
+ return;
407
+ }
390
408
  if (currentIframeHref.startsWith(this.config.redirectUrl)) {
391
409
  this.logger.info("Iframe has navigated to redirectUrl (same-origin). Setting up DOM observer.");
392
410
  // Hide content since we're on callback page now