@civic/auth 0.11.0 → 0.11.1-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +5 -0
- package/README.md +1 -0
- package/dist/lib/logger.d.ts +2 -0
- package/dist/lib/logger.d.ts.map +1 -1
- package/dist/lib/logger.js +2 -0
- package/dist/lib/logger.js.map +1 -1
- package/dist/lib/oauth.d.ts +2 -1
- package/dist/lib/oauth.d.ts.map +1 -1
- package/dist/lib/oauth.js +2 -1
- package/dist/lib/oauth.js.map +1 -1
- package/dist/nextjs/config.d.ts +3 -0
- package/dist/nextjs/config.d.ts.map +1 -1
- package/dist/nextjs/config.js +2 -0
- package/dist/nextjs/config.js.map +1 -1
- package/dist/nextjs/hooks/useInitialAuthConfig.d.ts +1 -0
- package/dist/nextjs/hooks/useInitialAuthConfig.d.ts.map +1 -1
- package/dist/nextjs/hooks/useInitialAuthConfig.js +7 -5
- package/dist/nextjs/hooks/useInitialAuthConfig.js.map +1 -1
- package/dist/nextjs/providers/NextAuthProviderClient.d.ts.map +1 -1
- package/dist/nextjs/providers/NextAuthProviderClient.js +2 -1
- package/dist/nextjs/providers/NextAuthProviderClient.js.map +1 -1
- package/dist/nextjs/routeHandler.d.ts.map +1 -1
- package/dist/nextjs/routeHandler.js +3 -0
- package/dist/nextjs/routeHandler.js.map +1 -1
- package/dist/reactjs/components/Button.d.ts.map +1 -1
- package/dist/reactjs/components/Button.js +4 -0
- package/dist/reactjs/components/Button.js.map +1 -1
- package/dist/reactjs/components/ButtonContentOrLoader.d.ts.map +1 -1
- package/dist/reactjs/components/ButtonContentOrLoader.js +9 -2
- package/dist/reactjs/components/ButtonContentOrLoader.js.map +1 -1
- package/dist/reactjs/components/SignInButton.d.ts +12 -2
- package/dist/reactjs/components/SignInButton.d.ts.map +1 -1
- package/dist/reactjs/components/SignInButton.js +52 -16
- package/dist/reactjs/components/SignInButton.js.map +1 -1
- package/dist/reactjs/components/SignOutButton.d.ts +8 -2
- package/dist/reactjs/components/SignOutButton.d.ts.map +1 -1
- package/dist/reactjs/components/SignOutButton.js +33 -8
- package/dist/reactjs/components/SignOutButton.js.map +1 -1
- package/dist/reactjs/components/UserButton.d.ts.map +1 -1
- package/dist/reactjs/components/UserButton.js +9 -29
- package/dist/reactjs/components/UserButton.js.map +1 -1
- package/dist/reactjs/core/GlobalAuthManager.d.ts +1 -0
- package/dist/reactjs/core/GlobalAuthManager.d.ts.map +1 -1
- package/dist/reactjs/core/GlobalAuthManager.js.map +1 -1
- package/dist/reactjs/styles/colors.d.ts +4 -0
- package/dist/reactjs/styles/colors.d.ts.map +1 -1
- package/dist/reactjs/styles/colors.js +4 -2
- package/dist/reactjs/styles/colors.js.map +1 -1
- package/dist/server/ServerAuthenticationResolver.d.ts.map +1 -1
- package/dist/server/ServerAuthenticationResolver.js +49 -54
- package/dist/server/ServerAuthenticationResolver.js.map +1 -1
- package/dist/server/config.d.ts +7 -0
- package/dist/server/config.d.ts.map +1 -1
- package/dist/server/config.js.map +1 -1
- package/dist/server/session.d.ts.map +1 -1
- package/dist/server/session.js +3 -0
- package/dist/server/session.js.map +1 -1
- package/dist/shared/lib/AuthenticationRefresherImpl.d.ts.map +1 -1
- package/dist/shared/lib/AuthenticationRefresherImpl.js +28 -21
- package/dist/shared/lib/AuthenticationRefresherImpl.js.map +1 -1
- package/dist/shared/lib/BrowserAuthenticationRefresher.d.ts.map +1 -1
- package/dist/shared/lib/BrowserAuthenticationRefresher.js +6 -0
- package/dist/shared/lib/BrowserAuthenticationRefresher.js.map +1 -1
- package/dist/shared/lib/cookieConfig.d.ts.map +1 -1
- package/dist/shared/lib/cookieConfig.js +1 -0
- package/dist/shared/lib/cookieConfig.js.map +1 -1
- package/dist/shared/version.d.ts +1 -1
- package/dist/shared/version.d.ts.map +1 -1
- package/dist/shared/version.js +1 -1
- package/dist/shared/version.js.map +1 -1
- package/dist/vanillajs/auth/BackendAuthenticationRefresher.d.ts.map +1 -1
- package/dist/vanillajs/auth/BackendAuthenticationRefresher.js +7 -1
- package/dist/vanillajs/auth/BackendAuthenticationRefresher.js.map +1 -1
- package/dist/vanillajs/auth/CivicAuth.d.ts +23 -0
- package/dist/vanillajs/auth/CivicAuth.d.ts.map +1 -1
- package/dist/vanillajs/auth/CivicAuth.js +157 -2
- package/dist/vanillajs/auth/CivicAuth.js.map +1 -1
- package/dist/vanillajs/auth/SessionManager.d.ts.map +1 -1
- package/dist/vanillajs/auth/SessionManager.js +3 -8
- package/dist/vanillajs/auth/SessionManager.js.map +1 -1
- package/dist/vanillajs/auth/TokenRefresher.d.ts +10 -0
- package/dist/vanillajs/auth/TokenRefresher.d.ts.map +1 -1
- package/dist/vanillajs/auth/TokenRefresher.js +80 -5
- package/dist/vanillajs/auth/TokenRefresher.js.map +1 -1
- package/package.json +1 -1
- package/dist/nextjs/NextClientAuthenticationRefresher.d.ts +0 -8
- package/dist/nextjs/NextClientAuthenticationRefresher.d.ts.map +0 -1
- package/dist/nextjs/NextClientAuthenticationRefresher.js +0 -24
- package/dist/nextjs/NextClientAuthenticationRefresher.js.map +0 -1
- package/dist/nextjs/NextServerAuthenticationRefresherImpl.d.ts +0 -12
- package/dist/nextjs/NextServerAuthenticationRefresherImpl.d.ts.map +0 -1
- package/dist/nextjs/NextServerAuthenticationRefresherImpl.js +0 -25
- package/dist/nextjs/NextServerAuthenticationRefresherImpl.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 (!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.storageType === \"cookie\";\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"]}
|
|
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 // token clearing is handled by the tokenRefresher on specific failures\n this.logger.warn(\n \"Token refresh failed during authentication check:\",\n error,\n );\n }\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 }\n }\n // If we reach here, authentication failed and refresh was tried if available - clear tokens to ensure clean state\n await clearTokens(this.storage);\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.storageType === \"cookie\";\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"]}
|
|
@@ -14,6 +14,9 @@ export declare class TokenRefresher {
|
|
|
14
14
|
private isDestroyed;
|
|
15
15
|
private logger;
|
|
16
16
|
private focusListenerAdded;
|
|
17
|
+
private visibilityListenerAdded;
|
|
18
|
+
private wasAutoRefreshActiveBeforeHidden;
|
|
19
|
+
private refreshDebounceTimer?;
|
|
17
20
|
constructor(storage: AuthStorage, events: AuthenticationEvents, authConfig?: AuthConfig);
|
|
18
21
|
/**
|
|
19
22
|
* Initialize the token refresher with auth configuration
|
|
@@ -27,8 +30,15 @@ export declare class TokenRefresher {
|
|
|
27
30
|
* Manually refresh tokens
|
|
28
31
|
*/
|
|
29
32
|
refreshTokens(): Promise<void>;
|
|
33
|
+
/**
|
|
34
|
+
* Debounced method to check and resume auto-refresh
|
|
35
|
+
* Prevents duplicate refresh operations when multiple events fire in quick succession
|
|
36
|
+
*/
|
|
37
|
+
private debouncedRefreshCheck;
|
|
30
38
|
private onWindowFocus;
|
|
39
|
+
private onVisibilityChange;
|
|
31
40
|
private addAutoRefreshOnFocusListener;
|
|
41
|
+
private addVisibilityChangeListener;
|
|
32
42
|
/**
|
|
33
43
|
* Start automatic token refresh
|
|
34
44
|
*/
|
|
@@ -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;IAC/C,OAAO,CAAC,kBAAkB,CAAkB;
|
|
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;IAC5C,OAAO,CAAC,uBAAuB,CAAkB;IACjD,OAAO,CAAC,gCAAgC,CAAkB;IAC1D,OAAO,CAAC,oBAAoB,CAAC,CAAS;gBAGpC,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;IAuDpC;;;OAGG;IACH,OAAO,CAAC,qBAAqB,CAoB3B;IAEF,OAAO,CAAC,aAAa,CAMnB;IAEF,OAAO,CAAC,kBAAkB,CAuCxB;IAEF,OAAO,CAAC,6BAA6B;IAUrC,OAAO,CAAC,2BAA2B;IASnC;;OAEG;YACW,gBAAgB;IAmC9B;;OAEG;IACH,OAAO,CAAC,eAAe;IAkBvB;;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;CAUF"}
|
|
@@ -18,6 +18,9 @@ export class TokenRefresher {
|
|
|
18
18
|
isDestroyed = false;
|
|
19
19
|
logger = createLogger("token-refresh");
|
|
20
20
|
focusListenerAdded = false;
|
|
21
|
+
visibilityListenerAdded = false;
|
|
22
|
+
wasAutoRefreshActiveBeforeHidden = false;
|
|
23
|
+
refreshDebounceTimer;
|
|
21
24
|
constructor(storage, events, authConfig) {
|
|
22
25
|
this.storage = storage;
|
|
23
26
|
this.events = events;
|
|
@@ -110,6 +113,11 @@ export class TokenRefresher {
|
|
|
110
113
|
* Manually refresh tokens
|
|
111
114
|
*/
|
|
112
115
|
async refreshTokens() {
|
|
116
|
+
// Check if refresh is disabled
|
|
117
|
+
if (this.authConfig?.disableRefresh) {
|
|
118
|
+
this.logger.info("Token refresh is disabled by configuration");
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
113
121
|
if (this.isDestroyed || !this.refresher) {
|
|
114
122
|
const errorMsg = `TokenRefresher not initialized or destroyed. isDestroyed: ${this.isDestroyed}, hasRefresher: ${!!this.refresher}`;
|
|
115
123
|
this.logger.error(errorMsg);
|
|
@@ -151,11 +159,55 @@ export class TokenRefresher {
|
|
|
151
159
|
throw error;
|
|
152
160
|
}
|
|
153
161
|
}
|
|
162
|
+
/**
|
|
163
|
+
* Debounced method to check and resume auto-refresh
|
|
164
|
+
* Prevents duplicate refresh operations when multiple events fire in quick succession
|
|
165
|
+
*/
|
|
166
|
+
debouncedRefreshCheck = (delay = 800) => {
|
|
167
|
+
// If a timer is already running, let it complete
|
|
168
|
+
if (this.refreshDebounceTimer) {
|
|
169
|
+
this.logger.debug("Refresh check already scheduled, skipping duplicate", new Date());
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
this.refreshDebounceTimer = window.setTimeout(async () => {
|
|
173
|
+
if (this.isAuthenticated && this.refresher) {
|
|
174
|
+
this.logger.info("Executing debounced refresh check - setting up auto-refresh", new Date());
|
|
175
|
+
await this.refresher.setupAutorefresh();
|
|
176
|
+
}
|
|
177
|
+
this.refreshDebounceTimer = undefined;
|
|
178
|
+
}, delay);
|
|
179
|
+
};
|
|
154
180
|
onWindowFocus = () => {
|
|
155
|
-
this.logger.debug("Window focused,
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
181
|
+
this.logger.debug("Window focused, scheduling debounced refresh check", new Date());
|
|
182
|
+
this.debouncedRefreshCheck(800);
|
|
183
|
+
};
|
|
184
|
+
onVisibilityChange = () => {
|
|
185
|
+
if (document.visibilityState === "hidden") {
|
|
186
|
+
// Page is being hidden (tab switched, minimized, or frozen)
|
|
187
|
+
this.logger.info("Page hidden - stopping auto-refresh to prevent cookie-less requests", new Date());
|
|
188
|
+
// Cancel any pending refresh check
|
|
189
|
+
if (this.refreshDebounceTimer) {
|
|
190
|
+
clearTimeout(this.refreshDebounceTimer);
|
|
191
|
+
this.refreshDebounceTimer = undefined;
|
|
192
|
+
}
|
|
193
|
+
// Remember if auto-refresh was active so we can resume it
|
|
194
|
+
this.wasAutoRefreshActiveBeforeHidden =
|
|
195
|
+
this.getState().isAutoRefreshActive;
|
|
196
|
+
if (this.wasAutoRefreshActiveBeforeHidden) {
|
|
197
|
+
this.refresher?.clearAutorefresh();
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
else if (document.visibilityState === "visible") {
|
|
201
|
+
// Page is becoming visible again
|
|
202
|
+
this.logger.info("Page visible - scheduling debounced refresh check", new Date());
|
|
203
|
+
if (this.wasAutoRefreshActiveBeforeHidden &&
|
|
204
|
+
this.refresher &&
|
|
205
|
+
this.isAuthenticated) {
|
|
206
|
+
// Use debounced refresh check with 800ms delay
|
|
207
|
+
this.debouncedRefreshCheck(800);
|
|
208
|
+
}
|
|
209
|
+
this.wasAutoRefreshActiveBeforeHidden = false;
|
|
210
|
+
}
|
|
159
211
|
};
|
|
160
212
|
addAutoRefreshOnFocusListener() {
|
|
161
213
|
if (!this.focusListenerAdded) {
|
|
@@ -166,10 +218,22 @@ export class TokenRefresher {
|
|
|
166
218
|
});
|
|
167
219
|
}
|
|
168
220
|
}
|
|
221
|
+
addVisibilityChangeListener() {
|
|
222
|
+
if (!this.visibilityListenerAdded) {
|
|
223
|
+
this.visibilityListenerAdded = true;
|
|
224
|
+
document.addEventListener("visibilitychange", this.onVisibilityChange);
|
|
225
|
+
this.logger.info("Added visibility change listener for auto-refresh management");
|
|
226
|
+
}
|
|
227
|
+
}
|
|
169
228
|
/**
|
|
170
229
|
* Start automatic token refresh
|
|
171
230
|
*/
|
|
172
231
|
async startAutoRefresh() {
|
|
232
|
+
// Check if refresh is disabled
|
|
233
|
+
if (this.authConfig?.disableRefresh) {
|
|
234
|
+
this.logger.info("Auto-refresh is disabled by configuration", this.logger.info);
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
173
237
|
if (this.refresher && this.isAuthenticated) {
|
|
174
238
|
this.logger.info("Starting automatic token refresh");
|
|
175
239
|
try {
|
|
@@ -186,17 +250,26 @@ export class TokenRefresher {
|
|
|
186
250
|
}
|
|
187
251
|
this.refresher.setupAutorefresh();
|
|
188
252
|
this.addAutoRefreshOnFocusListener();
|
|
253
|
+
this.addVisibilityChangeListener();
|
|
189
254
|
}
|
|
190
255
|
}
|
|
191
256
|
/**
|
|
192
257
|
* Stop automatic token refresh
|
|
193
258
|
*/
|
|
194
259
|
stopAutoRefresh() {
|
|
260
|
+
// Cancel any pending debounced refresh
|
|
261
|
+
if (this.refreshDebounceTimer) {
|
|
262
|
+
clearTimeout(this.refreshDebounceTimer);
|
|
263
|
+
this.refreshDebounceTimer = undefined;
|
|
264
|
+
}
|
|
195
265
|
if (this.refresher) {
|
|
196
266
|
this.logger.info("Stopping automatic token refresh");
|
|
197
267
|
this.refresher.clearAutorefresh();
|
|
198
268
|
window.removeEventListener("focus", this.onWindowFocus);
|
|
269
|
+
document.removeEventListener("visibilitychange", this.onVisibilityChange);
|
|
199
270
|
this.focusListenerAdded = false;
|
|
271
|
+
this.visibilityListenerAdded = false;
|
|
272
|
+
this.wasAutoRefreshActiveBeforeHidden = false;
|
|
200
273
|
}
|
|
201
274
|
}
|
|
202
275
|
/**
|
|
@@ -225,7 +298,9 @@ export class TokenRefresher {
|
|
|
225
298
|
return {
|
|
226
299
|
isInitialized: !!this.refresher,
|
|
227
300
|
isAuthenticated: this.isAuthenticated,
|
|
228
|
-
isAutoRefreshActive: this.isAuthenticated &&
|
|
301
|
+
isAutoRefreshActive: this.isAuthenticated &&
|
|
302
|
+
!!this.refresher &&
|
|
303
|
+
!this.authConfig?.disableRefresh,
|
|
229
304
|
};
|
|
230
305
|
}
|
|
231
306
|
}
|
|
@@ -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 { 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 setTimeout(() => {\n this.refresher?.setupAutorefresh();\n }, 800); // Delay to allow any navigation to complete. 800 ms seems to work well after trying between 1000 and 300 ms\n };\n\n private addAutoRefreshOnFocusListener() {\n if (!this.focusListenerAdded) {\n this.focusListenerAdded = true;\n window.addEventListener(\"focus\", this.onWindowFocus);\n window.addEventListener(\"beforeunload\", () => {\n this.stopAutoRefresh();\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 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
|
+
{"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 private visibilityListenerAdded: boolean = false;\n private wasAutoRefreshActiveBeforeHidden: boolean = false;\n private refreshDebounceTimer?: number;\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 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 // Check if refresh is disabled\n if (this.authConfig?.disableRefresh) {\n this.logger.info(\"Token refresh is disabled by configuration\");\n return;\n }\n\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 * Debounced method to check and resume auto-refresh\n * Prevents duplicate refresh operations when multiple events fire in quick succession\n */\n private debouncedRefreshCheck = (delay = 800) => {\n // If a timer is already running, let it complete\n if (this.refreshDebounceTimer) {\n this.logger.debug(\n \"Refresh check already scheduled, skipping duplicate\",\n new Date(),\n );\n return;\n }\n\n this.refreshDebounceTimer = window.setTimeout(async () => {\n if (this.isAuthenticated && this.refresher) {\n this.logger.info(\n \"Executing debounced refresh check - setting up auto-refresh\",\n new Date(),\n );\n await this.refresher.setupAutorefresh();\n }\n this.refreshDebounceTimer = undefined;\n }, delay);\n };\n\n private onWindowFocus = () => {\n this.logger.debug(\n \"Window focused, scheduling debounced refresh check\",\n new Date(),\n );\n this.debouncedRefreshCheck(800);\n };\n\n private onVisibilityChange = () => {\n if (document.visibilityState === \"hidden\") {\n // Page is being hidden (tab switched, minimized, or frozen)\n this.logger.info(\n \"Page hidden - stopping auto-refresh to prevent cookie-less requests\",\n new Date(),\n );\n\n // Cancel any pending refresh check\n if (this.refreshDebounceTimer) {\n clearTimeout(this.refreshDebounceTimer);\n this.refreshDebounceTimer = undefined;\n }\n\n // Remember if auto-refresh was active so we can resume it\n this.wasAutoRefreshActiveBeforeHidden =\n this.getState().isAutoRefreshActive;\n\n if (this.wasAutoRefreshActiveBeforeHidden) {\n this.refresher?.clearAutorefresh();\n }\n } else if (document.visibilityState === \"visible\") {\n // Page is becoming visible again\n this.logger.info(\n \"Page visible - scheduling debounced refresh check\",\n new Date(),\n );\n\n if (\n this.wasAutoRefreshActiveBeforeHidden &&\n this.refresher &&\n this.isAuthenticated\n ) {\n // Use debounced refresh check with 800ms delay\n this.debouncedRefreshCheck(800);\n }\n\n this.wasAutoRefreshActiveBeforeHidden = false;\n }\n };\n\n private addAutoRefreshOnFocusListener() {\n if (!this.focusListenerAdded) {\n this.focusListenerAdded = true;\n window.addEventListener(\"focus\", this.onWindowFocus);\n window.addEventListener(\"beforeunload\", () => {\n this.stopAutoRefresh();\n });\n }\n }\n\n private addVisibilityChangeListener() {\n if (!this.visibilityListenerAdded) {\n this.visibilityListenerAdded = true;\n document.addEventListener(\"visibilitychange\", this.onVisibilityChange);\n this.logger.info(\n \"Added visibility change listener for auto-refresh management\",\n );\n }\n }\n /**\n * Start automatic token refresh\n */\n private async startAutoRefresh(): Promise<void> {\n // Check if refresh is disabled\n if (this.authConfig?.disableRefresh) {\n this.logger.info(\n \"Auto-refresh is disabled by configuration\",\n this.logger.info,\n );\n return;\n }\n\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 this.addVisibilityChangeListener();\n }\n }\n\n /**\n * Stop automatic token refresh\n */\n private stopAutoRefresh(): void {\n // Cancel any pending debounced refresh\n if (this.refreshDebounceTimer) {\n clearTimeout(this.refreshDebounceTimer);\n this.refreshDebounceTimer = undefined;\n }\n\n if (this.refresher) {\n this.logger.info(\"Stopping automatic token refresh\");\n this.refresher.clearAutorefresh();\n window.removeEventListener(\"focus\", this.onWindowFocus);\n document.removeEventListener(\"visibilitychange\", this.onVisibilityChange);\n this.focusListenerAdded = false;\n this.visibilityListenerAdded = false;\n this.wasAutoRefreshActiveBeforeHidden = 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:\n this.isAuthenticated &&\n !!this.refresher &&\n !this.authConfig?.disableRefresh,\n };\n }\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import type { AuthConfig } from "../server/config.js";
|
|
2
|
-
import type { AuthStorage, OIDCTokenResponseBody } from "../types.js";
|
|
3
|
-
import { BrowserAuthenticationRefresher } from "../shared/lib/BrowserAuthenticationRefresher.js";
|
|
4
|
-
export declare class NextClientAuthenticationRefresher extends BrowserAuthenticationRefresher {
|
|
5
|
-
static build(authConfig: AuthConfig, storage: AuthStorage, onError: (error: Error) => Promise<void>): Promise<NextClientAuthenticationRefresher>;
|
|
6
|
-
refreshAccessToken(): Promise<OIDCTokenResponseBody | null>;
|
|
7
|
-
}
|
|
8
|
-
//# sourceMappingURL=NextClientAuthenticationRefresher.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"NextClientAuthenticationRefresher.d.ts","sourceRoot":"","sources":["../../src/nextjs/NextClientAuthenticationRefresher.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,KAAK,EAAE,WAAW,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AACrE,OAAO,EAAE,8BAA8B,EAAE,MAAM,gDAAgD,CAAC;AAEhG,qBAAa,iCAAkC,SAAQ,8BAA8B;WAC7D,KAAK,CACzB,UAAU,EAAE,UAAU,EACtB,OAAO,EAAE,WAAW,EACpB,OAAO,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,OAAO,CAAC,IAAI,CAAC,GACvC,OAAO,CAAC,iCAAiC,CAAC;IAS9B,kBAAkB,IAAI,OAAO,CAAC,qBAAqB,GAAG,IAAI,CAAC;CAkB3E"}
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { BrowserAuthenticationRefresher } from "../shared/lib/BrowserAuthenticationRefresher.js";
|
|
2
|
-
export class NextClientAuthenticationRefresher extends BrowserAuthenticationRefresher {
|
|
3
|
-
static async build(authConfig, storage, onError) {
|
|
4
|
-
const refresher = new NextClientAuthenticationRefresher(authConfig, storage, onError);
|
|
5
|
-
return refresher;
|
|
6
|
-
}
|
|
7
|
-
async refreshAccessToken() {
|
|
8
|
-
if (!this.authConfig)
|
|
9
|
-
throw new Error("No auth config available");
|
|
10
|
-
if (!this.authConfig.refreshUrl)
|
|
11
|
-
throw new Error("No refresh URL available");
|
|
12
|
-
try {
|
|
13
|
-
const res = await fetch(this.authConfig.refreshUrl);
|
|
14
|
-
const json = await res.json();
|
|
15
|
-
return json.tokens;
|
|
16
|
-
}
|
|
17
|
-
catch (error) {
|
|
18
|
-
console.error("NextClientAuthenticationRefresher refreshAccessToken: Failed to refresh tokens:", error);
|
|
19
|
-
this.onError(error);
|
|
20
|
-
throw error;
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
//# sourceMappingURL=NextClientAuthenticationRefresher.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"NextClientAuthenticationRefresher.js","sourceRoot":"","sources":["../../src/nextjs/NextClientAuthenticationRefresher.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,8BAA8B,EAAE,MAAM,gDAAgD,CAAC;AAEhG,MAAM,OAAO,iCAAkC,SAAQ,8BAA8B;IACnF,MAAM,CAAU,KAAK,CAAC,KAAK,CACzB,UAAsB,EACtB,OAAoB,EACpB,OAAwC;QAExC,MAAM,SAAS,GAAG,IAAI,iCAAiC,CACrD,UAAU,EACV,OAAO,EACP,OAAO,CACR,CAAC;QACF,OAAO,SAAS,CAAC;IACnB,CAAC;IAEQ,KAAK,CAAC,kBAAkB;QAC/B,IAAI,CAAC,IAAI,CAAC,UAAU;YAAE,MAAM,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAC;QAClE,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,UAAU;YAC7B,MAAM,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAC;QAE9C,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC;YACpD,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;YAC9B,OAAO,IAAI,CAAC,MAA+B,CAAC;QAC9C,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CACX,iFAAiF,EACjF,KAAK,CACN,CAAC;YACF,IAAI,CAAC,OAAO,CAAC,KAAc,CAAC,CAAC;YAC7B,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;CACF","sourcesContent":["import type { AuthConfig } from \"@/server/config.js\";\nimport type { AuthStorage, OIDCTokenResponseBody } from \"@/types.js\";\nimport { BrowserAuthenticationRefresher } from \"@/shared/lib/BrowserAuthenticationRefresher.js\";\n\nexport class NextClientAuthenticationRefresher extends BrowserAuthenticationRefresher {\n static override async build(\n authConfig: AuthConfig,\n storage: AuthStorage,\n onError: (error: Error) => Promise<void>,\n ): Promise<NextClientAuthenticationRefresher> {\n const refresher = new NextClientAuthenticationRefresher(\n authConfig,\n storage,\n onError,\n );\n return refresher;\n }\n\n override async refreshAccessToken(): Promise<OIDCTokenResponseBody | null> {\n if (!this.authConfig) throw new Error(\"No auth config available\");\n if (!this.authConfig.refreshUrl)\n throw new Error(\"No refresh URL available\");\n\n try {\n const res = await fetch(this.authConfig.refreshUrl);\n const json = await res.json();\n return json.tokens as OIDCTokenResponseBody;\n } catch (error) {\n console.error(\n \"NextClientAuthenticationRefresher refreshAccessToken: Failed to refresh tokens:\",\n error,\n );\n this.onError(error as Error);\n throw error;\n }\n }\n}\n"]}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { AuthenticationRefresherImpl } from "../shared/lib/AuthenticationRefresherImpl.js";
|
|
2
|
-
import type { Endpoints, OIDCTokenResponseBody } from "../types.js";
|
|
3
|
-
import type { AuthConfig } from "../server/config.js";
|
|
4
|
-
import type { CookieStorage } from "../server/index.js";
|
|
5
|
-
export declare class NextServerAuthenticationRefresherImpl extends AuthenticationRefresherImpl {
|
|
6
|
-
endpointOverrides?: Partial<Endpoints> | undefined;
|
|
7
|
-
storage: CookieStorage | undefined;
|
|
8
|
-
constructor(authConfig: AuthConfig, storage: CookieStorage, onError: (error: Error) => Promise<void>, endpointOverrides?: Partial<Endpoints> | undefined);
|
|
9
|
-
storeTokens(tokenResponseBody: OIDCTokenResponseBody | null): Promise<void>;
|
|
10
|
-
static build(authConfig: AuthConfig, storage: CookieStorage, onError: (error: Error) => Promise<void>, endpointOverrides?: Partial<Endpoints>): Promise<NextServerAuthenticationRefresherImpl>;
|
|
11
|
-
}
|
|
12
|
-
//# sourceMappingURL=NextServerAuthenticationRefresherImpl.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"NextServerAuthenticationRefresherImpl.d.ts","sourceRoot":"","sources":["../../src/nextjs/NextServerAuthenticationRefresherImpl.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,2BAA2B,EAAE,MAAM,6CAA6C,CAAC;AAC1F,OAAO,KAAK,EAAE,SAAS,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AACnE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAErD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAEvD,qBAAa,qCAAsC,SAAQ,2BAA2B;IAMzE,iBAAiB,CAAC,EAAE,OAAO,CAAC,SAAS,CAAC;IALxC,OAAO,EAAE,aAAa,GAAG,SAAS,CAAC;gBAE1C,UAAU,EAAE,UAAU,EACtB,OAAO,EAAE,aAAa,EACtB,OAAO,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,OAAO,CAAC,IAAI,CAAC,EAC/B,iBAAiB,CAAC,EAAE,OAAO,CAAC,SAAS,CAAC,YAAA;IAMlC,WAAW,CACxB,iBAAiB,EAAE,qBAAqB,GAAG,IAAI,GAC9C,OAAO,CAAC,IAAI,CAAC;WAQM,KAAK,CACzB,UAAU,EAAE,UAAU,EACtB,OAAO,EAAE,aAAa,EACtB,OAAO,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,OAAO,CAAC,IAAI,CAAC,EACxC,iBAAiB,CAAC,EAAE,OAAO,CAAC,SAAS,CAAC,GACrC,OAAO,CAAC,qCAAqC,CAAC;CAWlD"}
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { AuthenticationRefresherImpl } from "../shared/lib/AuthenticationRefresherImpl.js";
|
|
2
|
-
import { storeServerTokens } from "../shared/lib/util.js";
|
|
3
|
-
export class NextServerAuthenticationRefresherImpl extends AuthenticationRefresherImpl {
|
|
4
|
-
endpointOverrides;
|
|
5
|
-
storage;
|
|
6
|
-
constructor(authConfig, storage, onError, endpointOverrides) {
|
|
7
|
-
super(authConfig, storage, onError, endpointOverrides);
|
|
8
|
-
this.endpointOverrides = endpointOverrides;
|
|
9
|
-
this.storage = storage;
|
|
10
|
-
}
|
|
11
|
-
async storeTokens(tokenResponseBody) {
|
|
12
|
-
if (!this.storage)
|
|
13
|
-
throw new Error("No storage available");
|
|
14
|
-
// For null tokenResponseBody, we skip storage since tokens might be managed elsewhere (e.g., HTTP-only cookies)
|
|
15
|
-
if (!tokenResponseBody)
|
|
16
|
-
return;
|
|
17
|
-
await storeServerTokens(this.storage, tokenResponseBody);
|
|
18
|
-
}
|
|
19
|
-
static async build(authConfig, storage, onError, endpointOverrides) {
|
|
20
|
-
const refresher = new NextServerAuthenticationRefresherImpl(authConfig, storage, onError, endpointOverrides);
|
|
21
|
-
await refresher.init();
|
|
22
|
-
return refresher;
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
//# sourceMappingURL=NextServerAuthenticationRefresherImpl.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"NextServerAuthenticationRefresherImpl.js","sourceRoot":"","sources":["../../src/nextjs/NextServerAuthenticationRefresherImpl.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,2BAA2B,EAAE,MAAM,6CAA6C,CAAC;AAG1F,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAGzD,MAAM,OAAO,qCAAsC,SAAQ,2BAA2B;IAMzE;IALF,OAAO,CAA4B;IAC5C,YACE,UAAsB,EACtB,OAAsB,EACtB,OAAwC,EAC/B,iBAAsC;QAE/C,KAAK,CAAC,UAAU,EAAE,OAAO,EAAE,OAAO,EAAE,iBAAiB,CAAC,CAAC;QAF9C,sBAAiB,GAAjB,iBAAiB,CAAqB;QAG/C,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACzB,CAAC;IAEQ,KAAK,CAAC,WAAW,CACxB,iBAA+C;QAE/C,IAAI,CAAC,IAAI,CAAC,OAAO;YAAE,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;QAC3D,gHAAgH;QAChH,IAAI,CAAC,iBAAiB;YAAE,OAAO;QAE/B,MAAM,iBAAiB,CAAC,IAAI,CAAC,OAAO,EAAE,iBAAiB,CAAC,CAAC;IAC3D,CAAC;IAED,MAAM,CAAU,KAAK,CAAC,KAAK,CACzB,UAAsB,EACtB,OAAsB,EACtB,OAAwC,EACxC,iBAAsC;QAEtC,MAAM,SAAS,GAAG,IAAI,qCAAqC,CACzD,UAAU,EACV,OAAO,EACP,OAAO,EACP,iBAAiB,CAClB,CAAC;QACF,MAAM,SAAS,CAAC,IAAI,EAAE,CAAC;QAEvB,OAAO,SAAS,CAAC;IACnB,CAAC;CACF","sourcesContent":["import { AuthenticationRefresherImpl } from \"@/shared/lib/AuthenticationRefresherImpl.js\";\nimport type { Endpoints, OIDCTokenResponseBody } from \"@/types.js\";\nimport type { AuthConfig } from \"@/server/config.js\";\nimport { storeServerTokens } from \"@/shared/lib/util.js\";\nimport type { CookieStorage } from \"@/server/index.js\";\n\nexport class NextServerAuthenticationRefresherImpl extends AuthenticationRefresherImpl {\n override storage: CookieStorage | undefined;\n constructor(\n authConfig: AuthConfig,\n storage: CookieStorage,\n onError: (error: Error) => Promise<void>,\n override endpointOverrides?: Partial<Endpoints>,\n ) {\n super(authConfig, storage, onError, endpointOverrides);\n this.storage = storage;\n }\n\n override async storeTokens(\n tokenResponseBody: OIDCTokenResponseBody | null,\n ): Promise<void> {\n if (!this.storage) throw new Error(\"No storage available\");\n // For null tokenResponseBody, we skip storage since tokens might be managed elsewhere (e.g., HTTP-only cookies)\n if (!tokenResponseBody) return;\n\n await storeServerTokens(this.storage, tokenResponseBody);\n }\n\n static override async build(\n authConfig: AuthConfig,\n storage: CookieStorage,\n onError: (error: Error) => Promise<void>,\n endpointOverrides?: Partial<Endpoints>,\n ): Promise<NextServerAuthenticationRefresherImpl> {\n const refresher = new NextServerAuthenticationRefresherImpl(\n authConfig,\n storage,\n onError,\n endpointOverrides,\n );\n await refresher.init();\n\n return refresher;\n }\n}\n"]}
|