@civic/auth 0.11.0-beta.2 → 0.11.1-beta.0
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 +1 -0
- package/dist/lib/logger.d.ts.map +1 -1
- package/dist/lib/logger.js +1 -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 +5 -2
- 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/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.js +1 -1
- package/dist/shared/version.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/TokenRefresher.d.ts.map +1 -1
- package/dist/vanillajs/auth/TokenRefresher.js +13 -1
- package/dist/vanillajs/auth/TokenRefresher.js.map +1 -1
- package/package.json +1 -1
|
@@ -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":"AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAC9C,OAAO,EACL,8BAA8B,GAE/B,MAAM,oDAAoD,CAAC;AAC5D,OAAO,EAAE,8BAA8B,EAAE,MAAM,qCAAqC,CAAC;AAErF,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,mCAAmC,EAAE,MAAM,0BAA0B,CAAC;AAC/E,OAAO,EAAE,OAAO,EAAE,MAAM,6BAA6B,CAAC;AACtD,OAAO,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AAErE;;;GAGG;AACH,MAAM,OAAO,cAAc;IACjB,SAAS,CAEkB;IAC3B,OAAO,CAAc;IACrB,MAAM,CAAuB;IAC7B,UAAU,CAAc;IACxB,eAAe,GAAY,KAAK,CAAC;IACjC,WAAW,GAAY,KAAK,CAAC;IAC7B,MAAM,GAAG,YAAY,CAAC,eAAe,CAAC,CAAC;IACvC,kBAAkB,GAAY,KAAK,CAAC;IAC5C,YACE,OAAoB,EACpB,MAA4B,EAC5B,UAAuB;QAEvB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;QAE7B,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,4BAA4B,CAAC,CAAC;IACjD,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,UAAU,CAAC,UAAsB;QACrC,IAAI,IAAI,CAAC,WAAW;YAAE,OAAO;QAE7B,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;QAE7B,IAAI,CAAC;YACH,+BAA+B;YAC/B,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC;YACrB,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,SAAS,CAAC,gBAAgB,EAAE,GAAG,EAAE;gBAC9C,IAAI,CAAC,eAAe,EAAE,CAAC;YACzB,CAAC,CAAC,CAAC;YACH,gDAAgD;YAChD,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,SAAS,CAAC,gBAAgB,EAAE,GAAG,EAAE;gBAC9C,IAAI,IAAI,CAAC,WAAW;oBAAE,OAAO;gBAC7B,IAAI,CAAC,sBAAsB,CAAC,IAAI,CAAC,CAAC;YACpC,CAAC,CAAC,CAAC;YACH,MAAM,OAAO,GAAG,KAAK,EAAE,KAAY,EAAE,EAAE;gBACrC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,sBAAsB,EAAE,KAAK,CAAC,CAAC;gBACjD,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,mBAAmB,EAAE,KAAK,CAAC,CAAC;gBAEvD,8BAA8B;gBAC9B,IAAI,CAAC,SAAS,EAAE,gBAAgB,EAAE,CAAC;gBAEnC,uDAAuD;gBACvD,iDAAiD;gBACjD,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,gBAAgB,EAAE,IAAI,CAAC,CAAC;YACrD,CAAC,CAAC;YAEF,kDAAkD;YAClD,IAAI,UAAU,CAAC,QAAQ,EAAE,CAAC;gBACxB,mEAAmE;gBACnE,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,+CAA+C,EAAE;oBAChE,QAAQ,EAAE,UAAU,CAAC,QAAQ;iBAC9B,CAAC,CAAC;gBAEH,IAAI,CAAC,SAAS,GAAG,MAAM,8BAA8B,CAAC,KAAK,CACzD,UAAU,EACV,IAAI,CAAC,OAAO,EACZ,UAAU,CAAC,QAAQ,EACnB,OAAO,EACP,IAAI,CAAC,MAAM,CACZ,CAAC;YACJ,CAAC;iBAAM,CAAC;gBACN,+DAA+D;gBAC/D,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,+CAA+C,CAAC,CAAC;gBAElE,sCAAsC;gBACtC,MAAM,qBAAqB,GAA0B;oBACnD,gBAAgB,EAAE,GAAG,EAAE;wBACrB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,4BAA4B,CAAC,CAAC;wBAC/C,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,qBAAqB,EAAE,IAAI,CAAC,CAAC;oBAC1D,CAAC;oBACD,iBAAiB,EAAE,GAAG,EAAE;wBACtB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,8BAA8B,CAAC,CAAC;wBACjD,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,sBAAsB,EAAE,IAAI,CAAC,CAAC;oBAC3D,CAAC;oBACD,cAAc,EAAE,CAAC,KAAY,EAAE,EAAE;wBAC/B,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,4BAA4B,EAAE,KAAK,CAAC,CAAC;wBACvD,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,mBAAmB,EAAE,KAAK,CAAC,CAAC;oBACzD,CAAC;iBACF,CAAC;gBAEF,IAAI,CAAC,SAAS,GAAG,MAAM,8BAA8B,CAAC,KAAK,CACzD,UAAU,EACV,IAAI,CAAC,OAAO,EACZ,OAAO,EACP,SAAS,EAAE,oBAAoB;gBAC/B,qBAAqB,CACtB,CAAC;YACJ,CAAC;YAED,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,yCAAyC,CAAC,CAAC;QAC9D,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,sCAAsC,EAAE,KAAK,CAAC,CAAC;YACjE,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,mBAAmB,EAAE,KAAK,CAAC,CAAC;QACzD,CAAC;IACH,CAAC;IAED;;OAEG;IACH,sBAAsB,CAAC,eAAwB;QAC7C,IAAI,IAAI,CAAC,WAAW;YAAE,OAAO;QAE7B,IAAI,CAAC,eAAe,GAAG,eAAe,CAAC;QAEvC,IAAI,eAAe,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YACtC,sFAAsF;YACtF,kCAAkC;YAClC,IAAI,CAAC,gBAAgB,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;gBACtC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,8BAA8B,EAAE,KAAK,CAAC,CAAC;YAC3D,CAAC,CAAC,CAAC;QACL,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,eAAe,EAAE,CAAC;QACzB,CAAC;IACH,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,aAAa;QACjB,+BAA+B;QAC/B,IAAI,IAAI,CAAC,UAAU,EAAE,cAAc,EAAE,CAAC;YACpC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,4CAA4C,CAAC,CAAC;YAC/D,OAAO;QACT,CAAC;QAED,IAAI,IAAI,CAAC,WAAW,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC;YACxC,MAAM,QAAQ,GAAG,6DAA6D,IAAI,CAAC,WAAW,mBAAmB,CAAC,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC;YACpI,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;YAC5B,MAAM,IAAI,KAAK,CAAC,QAAQ,CAAC,CAAC;QAC5B,CAAC;QAED,IAAI,CAAC;YACH,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,qBAAqB,EAAE,IAAI,CAAC,CAAC;YAExD,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,+BAA+B,CAAC,CAAC;YAElD,MAAM,IAAI,CAAC,SAAS,CAAC,aAAa,EAAE,CAAC;YAErC,+EAA+E;YAC/E,4FAA4F;YAC5F,IAAI,IAAI,CAAC,SAAS,YAAY,8BAA8B,EAAE,CAAC;gBAC7D,IAAI,CAAC;oBACH,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,yCAAyC,CAAC,CAAC;oBAE5D,0CAA0C;oBAC1C,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;oBACzC,IAAI,IAAI,EAAE,CAAC;wBACT,uCAAuC;wBACvC,MAAM,WAAW,GAAG,IAAI,kBAAkB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;wBACzD,MAAM,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;wBAC5B,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,iCAAiC,CAAC,CAAC;oBACtD,CAAC;yBAAM,CAAC;wBACN,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,wCAAwC,CAAC,CAAC;oBAC7D,CAAC;gBACH,CAAC;gBAAC,OAAO,SAAS,EAAE,CAAC;oBACnB,0DAA0D;oBAC1D,iDAAiD;oBACjD,IAAI,CAAC,MAAM,CAAC,KAAK,CACf,kDAAkD,EAClD,SAAS,CACV,CAAC;gBACJ,CAAC;YACH,CAAC;YAED,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,sBAAsB,EAAE,IAAI,CAAC,CAAC;YACzD,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,gCAAgC,CAAC,CAAC;QACrD,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,8BAA8B,EAAE,KAAK,CAAC,CAAC;YACzD,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,mBAAmB,EAAE,KAAK,CAAC,CAAC;YACvD,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;IAEO,aAAa,GAAG,GAAG,EAAE;QAC3B,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,0CAA0C,CAAC,CAAC;QAC9D,UAAU,CAAC,GAAG,EAAE;YACd,IAAI,CAAC,SAAS,EAAE,gBAAgB,EAAE,CAAC;QACrC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,4GAA4G;IACvH,CAAC,CAAC;IAEM,6BAA6B;QACnC,IAAI,CAAC,IAAI,CAAC,kBAAkB,EAAE,CAAC;YAC7B,IAAI,CAAC,kBAAkB,GAAG,IAAI,CAAC;YAC/B,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC;YACrD,MAAM,CAAC,gBAAgB,CAAC,cAAc,EAAE,GAAG,EAAE;gBAC3C,IAAI,CAAC,eAAe,EAAE,CAAC;YACzB,CAAC,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IACD;;OAEG;IACK,KAAK,CAAC,gBAAgB;QAC5B,+BAA+B;QAC/B,IAAI,IAAI,CAAC,UAAU,EAAE,cAAc,EAAE,CAAC;YACpC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,2CAA2C,CAAC,CAAC;YAC9D,OAAO;QACT,CAAC;QAED,IAAI,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,eAAe,EAAE,CAAC;YAC3C,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,kCAAkC,CAAC,CAAC;YAErD,IAAI,CAAC;gBACH,6FAA6F;gBAC7F,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;gBAC1C,MAAM,SAAS,GACb,CAAC,MAAM,mCAAmC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,GAAG,GAAG,EAAE,CAAC;gBACxE,MAAM,UAAU,GAAG,EAAE,CAAC,CAAC,oBAAoB;gBAC3C,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,SAAS,GAAG,UAAU,GAAG,GAAG,CAAC,CAAC;gBAE9D,MAAM,eAAe,GAAG,IAAI,IAAI,CAAC,CAAC,GAAG,GAAG,WAAW,CAAC,GAAG,IAAI,CAAC,CAAC;gBAC7D,IAAI,CAAC,MAAM,CAAC,IAAI,CACd,qCAAqC,eAAe,CAAC,WAAW,EAAE,QAAQ,WAAW,WAAW,CACjG,CAAC;YACJ,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,wCAAwC,EAAE,KAAK,CAAC,CAAC;YACpE,CAAC;YAED,IAAI,CAAC,SAAS,CAAC,gBAAgB,EAAE,CAAC;YAClC,IAAI,CAAC,6BAA6B,EAAE,CAAC;QACvC,CAAC;IACH,CAAC;IAED;;OAEG;IACK,eAAe;QACrB,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YACnB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,kCAAkC,CAAC,CAAC;YACrD,IAAI,CAAC,SAAS,CAAC,gBAAgB,EAAE,CAAC;YAClC,MAAM,CAAC,mBAAmB,CAAC,OAAO,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC;YACxD,IAAI,CAAC,kBAAkB,GAAG,KAAK,CAAC;QAClC,CAAC;IACH,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,OAAO;QACX,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,4BAA4B,CAAC,CAAC;QAE/C,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YACnB,IAAI,CAAC,eAAe,EAAE,CAAC;YACvB,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;QAC7B,CAAC;QAED,IAAI,CAAC,eAAe,GAAG,KAAK,CAAC;IAC/B,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,OAAO;QACX,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;QACxB,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC;QACrB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,0BAA0B,CAAC,CAAC;IAC/C,CAAC;IAED;;OAEG;IACH,QAAQ;QAKN,OAAO;YACL,aAAa,EAAE,CAAC,CAAC,IAAI,CAAC,SAAS;YAC/B,eAAe,EAAE,IAAI,CAAC,eAAe;YACrC,mBAAmB,EACjB,IAAI,CAAC,eAAe;gBACpB,CAAC,CAAC,IAAI,CAAC,SAAS;gBAChB,CAAC,IAAI,CAAC,UAAU,EAAE,cAAc;SACnC,CAAC;IACJ,CAAC;CACF","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 // 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 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 // Check if refresh is disabled\n if (this.authConfig?.disableRefresh) {\n this.logger.info(\"Auto-refresh is disabled by configuration\");\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 }\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:\n this.isAuthenticated &&\n !!this.refresher &&\n !this.authConfig?.disableRefresh,\n };\n }\n}\n"]}
|