@civic/auth 0.8.2 → 0.9.0-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.
Files changed (154) hide show
  1. package/CHANGELOG.md +5 -0
  2. package/README.md +9 -3
  3. package/dist/constants.d.ts +2 -1
  4. package/dist/constants.d.ts.map +1 -1
  5. package/dist/constants.js +3 -1
  6. package/dist/constants.js.map +1 -1
  7. package/dist/lib/oauth.d.ts +4 -2
  8. package/dist/lib/oauth.d.ts.map +1 -1
  9. package/dist/lib/oauth.js +4 -2
  10. package/dist/lib/oauth.js.map +1 -1
  11. package/dist/nextjs/NextClientAuthenticationRefresher.d.ts +1 -1
  12. package/dist/nextjs/NextClientAuthenticationRefresher.d.ts.map +1 -1
  13. package/dist/nextjs/NextClientAuthenticationRefresher.js.map +1 -1
  14. package/dist/nextjs/NextServerAuthenticationRefresherImpl.d.ts +1 -1
  15. package/dist/nextjs/NextServerAuthenticationRefresherImpl.d.ts.map +1 -1
  16. package/dist/nextjs/NextServerAuthenticationRefresherImpl.js +3 -0
  17. package/dist/nextjs/NextServerAuthenticationRefresherImpl.js.map +1 -1
  18. package/dist/nextjs/config.d.ts +3 -0
  19. package/dist/nextjs/config.d.ts.map +1 -1
  20. package/dist/nextjs/config.js +3 -0
  21. package/dist/nextjs/config.js.map +1 -1
  22. package/dist/nextjs/providers/NextAuthProvider.d.ts.map +1 -1
  23. package/dist/nextjs/providers/NextAuthProvider.js +1 -1
  24. package/dist/nextjs/providers/NextAuthProvider.js.map +1 -1
  25. package/dist/nextjs/routeHandler.d.ts.map +1 -1
  26. package/dist/nextjs/routeHandler.js +2 -1
  27. package/dist/nextjs/routeHandler.js.map +1 -1
  28. package/dist/reactjs/core/GlobalAuthManager.d.ts +16 -0
  29. package/dist/reactjs/core/GlobalAuthManager.d.ts.map +1 -1
  30. package/dist/reactjs/core/GlobalAuthManager.js +28 -1
  31. package/dist/reactjs/core/GlobalAuthManager.js.map +1 -1
  32. package/dist/reactjs/hooks/useUser.d.ts +3 -0
  33. package/dist/reactjs/hooks/useUser.d.ts.map +1 -1
  34. package/dist/reactjs/hooks/useUser.js +32 -0
  35. package/dist/reactjs/hooks/useUser.js.map +1 -1
  36. package/dist/reactjs/providers/CivicAuthContext.d.ts +4 -0
  37. package/dist/reactjs/providers/CivicAuthContext.d.ts.map +1 -1
  38. package/dist/reactjs/providers/CivicAuthContext.js +22 -13
  39. package/dist/reactjs/providers/CivicAuthContext.js.map +1 -1
  40. package/dist/reactjs/providers/CivicAuthProvider.d.ts +2 -0
  41. package/dist/reactjs/providers/CivicAuthProvider.d.ts.map +1 -1
  42. package/dist/reactjs/providers/CivicAuthProvider.js +5 -1
  43. package/dist/reactjs/providers/CivicAuthProvider.js.map +1 -1
  44. package/dist/server/config.d.ts +47 -0
  45. package/dist/server/config.d.ts.map +1 -1
  46. package/dist/server/config.js.map +1 -1
  47. package/dist/server/index.d.ts +8 -2
  48. package/dist/server/index.d.ts.map +1 -1
  49. package/dist/server/index.js +5 -1
  50. package/dist/server/index.js.map +1 -1
  51. package/dist/server/login.d.ts +9 -0
  52. package/dist/server/login.d.ts.map +1 -1
  53. package/dist/server/login.js +4 -2
  54. package/dist/server/login.js.map +1 -1
  55. package/dist/server/refresh.d.ts +1 -1
  56. package/dist/server/refresh.d.ts.map +1 -1
  57. package/dist/server/refresh.js.map +1 -1
  58. package/dist/server/session.d.ts +60 -2
  59. package/dist/server/session.d.ts.map +1 -1
  60. package/dist/server/session.js +216 -5
  61. package/dist/server/session.js.map +1 -1
  62. package/dist/server/types/express.d.ts +97 -0
  63. package/dist/server/types/express.d.ts.map +1 -0
  64. package/dist/server/types/express.js +2 -0
  65. package/dist/server/types/express.js.map +1 -0
  66. package/dist/services/AuthenticationService.d.ts +12 -0
  67. package/dist/services/AuthenticationService.d.ts.map +1 -1
  68. package/dist/services/AuthenticationService.js +62 -6
  69. package/dist/services/AuthenticationService.js.map +1 -1
  70. package/dist/services/types.d.ts +1 -1
  71. package/dist/services/types.d.ts.map +1 -1
  72. package/dist/services/types.js.map +1 -1
  73. package/dist/shared/components/CivicAuthIframe.d.ts +1 -0
  74. package/dist/shared/components/CivicAuthIframe.d.ts.map +1 -1
  75. package/dist/shared/components/CivicAuthIframe.js +4 -4
  76. package/dist/shared/components/CivicAuthIframe.js.map +1 -1
  77. package/dist/shared/components/CivicAuthIframeContainer.d.ts +2 -1
  78. package/dist/shared/components/CivicAuthIframeContainer.d.ts.map +1 -1
  79. package/dist/shared/components/CivicAuthIframeContainer.js +10 -3
  80. package/dist/shared/components/CivicAuthIframeContainer.js.map +1 -1
  81. package/dist/shared/components/IFrameAndLoading.d.ts.map +1 -1
  82. package/dist/shared/components/IFrameAndLoading.js +1 -1
  83. package/dist/shared/components/IFrameAndLoading.js.map +1 -1
  84. package/dist/shared/hooks/useSignIn.d.ts.map +1 -1
  85. package/dist/shared/hooks/useSignIn.js +5 -3
  86. package/dist/shared/hooks/useSignIn.js.map +1 -1
  87. package/dist/shared/lib/AuthenticationRefresherImpl.d.ts +2 -2
  88. package/dist/shared/lib/AuthenticationRefresherImpl.d.ts.map +1 -1
  89. package/dist/shared/lib/AuthenticationRefresherImpl.js +3 -0
  90. package/dist/shared/lib/AuthenticationRefresherImpl.js.map +1 -1
  91. package/dist/shared/lib/GenericAuthenticationRefresher.d.ts +2 -2
  92. package/dist/shared/lib/GenericAuthenticationRefresher.d.ts.map +1 -1
  93. package/dist/shared/lib/GenericAuthenticationRefresher.js.map +1 -1
  94. package/dist/shared/lib/iframeUtils.d.ts +2 -0
  95. package/dist/shared/lib/iframeUtils.d.ts.map +1 -1
  96. package/dist/shared/lib/iframeUtils.js +12 -0
  97. package/dist/shared/lib/iframeUtils.js.map +1 -1
  98. package/dist/shared/lib/types.d.ts +1 -0
  99. package/dist/shared/lib/types.d.ts.map +1 -1
  100. package/dist/shared/lib/types.js.map +1 -1
  101. package/dist/shared/lib/util.d.ts +7 -0
  102. package/dist/shared/lib/util.d.ts.map +1 -1
  103. package/dist/shared/lib/util.js +12 -0
  104. package/dist/shared/lib/util.js.map +1 -1
  105. package/dist/shared/providers/CivicAuthConfigContext.d.ts +2 -1
  106. package/dist/shared/providers/CivicAuthConfigContext.d.ts.map +1 -1
  107. package/dist/shared/providers/CivicAuthConfigContext.js +3 -1
  108. package/dist/shared/providers/CivicAuthConfigContext.js.map +1 -1
  109. package/dist/shared/version.d.ts +1 -1
  110. package/dist/shared/version.d.ts.map +1 -1
  111. package/dist/shared/version.js +1 -1
  112. package/dist/shared/version.js.map +1 -1
  113. package/dist/vanillajs/auth/BackendAuthenticationRefresher.d.ts +41 -0
  114. package/dist/vanillajs/auth/BackendAuthenticationRefresher.d.ts.map +1 -0
  115. package/dist/vanillajs/auth/BackendAuthenticationRefresher.js +125 -0
  116. package/dist/vanillajs/auth/BackendAuthenticationRefresher.js.map +1 -0
  117. package/dist/vanillajs/auth/CivicAuth.d.ts +67 -0
  118. package/dist/vanillajs/auth/CivicAuth.d.ts.map +1 -1
  119. package/dist/vanillajs/auth/CivicAuth.js +310 -10
  120. package/dist/vanillajs/auth/CivicAuth.js.map +1 -1
  121. package/dist/vanillajs/auth/SessionManager.d.ts +31 -3
  122. package/dist/vanillajs/auth/SessionManager.d.ts.map +1 -1
  123. package/dist/vanillajs/auth/SessionManager.js +253 -22
  124. package/dist/vanillajs/auth/SessionManager.js.map +1 -1
  125. package/dist/vanillajs/auth/TokenRefresher.d.ts.map +1 -1
  126. package/dist/vanillajs/auth/TokenRefresher.js +31 -18
  127. package/dist/vanillajs/auth/TokenRefresher.js.map +1 -1
  128. package/dist/vanillajs/auth/config/ConfigProcessor.d.ts.map +1 -1
  129. package/dist/vanillajs/auth/config/ConfigProcessor.js +15 -8
  130. package/dist/vanillajs/auth/config/ConfigProcessor.js.map +1 -1
  131. package/dist/vanillajs/auth/handlers/IframeAuthHandler.d.ts +44 -0
  132. package/dist/vanillajs/auth/handlers/IframeAuthHandler.d.ts.map +1 -1
  133. package/dist/vanillajs/auth/handlers/IframeAuthHandler.js +163 -1
  134. package/dist/vanillajs/auth/handlers/IframeAuthHandler.js.map +1 -1
  135. package/dist/vanillajs/auth/handlers/MessageHandler.d.ts +23 -0
  136. package/dist/vanillajs/auth/handlers/MessageHandler.d.ts.map +1 -1
  137. package/dist/vanillajs/auth/handlers/MessageHandler.js +59 -2
  138. package/dist/vanillajs/auth/handlers/MessageHandler.js.map +1 -1
  139. package/dist/vanillajs/auth/types/AuthTypes.d.ts +20 -0
  140. package/dist/vanillajs/auth/types/AuthTypes.d.ts.map +1 -1
  141. package/dist/vanillajs/auth/types/AuthTypes.js +1 -0
  142. package/dist/vanillajs/auth/types/AuthTypes.js.map +1 -1
  143. package/dist/vanillajs/iframe/IframeManager.d.ts +36 -0
  144. package/dist/vanillajs/iframe/IframeManager.d.ts.map +1 -1
  145. package/dist/vanillajs/iframe/IframeManager.js +216 -24
  146. package/dist/vanillajs/iframe/IframeManager.js.map +1 -1
  147. package/dist/vanillajs/index.d.ts +2 -0
  148. package/dist/vanillajs/index.d.ts.map +1 -1
  149. package/dist/vanillajs/index.js +4 -0
  150. package/dist/vanillajs/index.js.map +1 -1
  151. package/dist/vanillajs/ui/LoadingComponents.d.ts.map +1 -1
  152. package/dist/vanillajs/ui/LoadingComponents.js +1 -1
  153. package/dist/vanillajs/ui/LoadingComponents.js.map +1 -1
  154. package/package.json +7 -2
@@ -1 +1 @@
1
- {"version":3,"file":"AuthenticationService.js","sourceRoot":"","sources":["../../src/services/AuthenticationService.ts"],"names":[],"mappings":"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","sourcesContent":["// Proposals for revised versions of the SessionService AKA AuthSessionService\n\nimport type {\n DisplayMode,\n Endpoints,\n FrameworkType,\n LoginAppDesignOptions,\n LoginPostMessage,\n OIDCTokenResponseBody,\n SessionData,\n} from \"@/types.js\";\nimport {\n BrowserPublicClientPKCEProducer,\n ConfidentialClientPKCEConsumer,\n} from \"@/services/PKCE.js\";\nimport {\n clearTokens,\n clearUser,\n exchangeTokens,\n generateOauthLoginUrl,\n generateOauthLogoutUrl,\n getEndpointsWithOverrides,\n retrieveTokens,\n storeTokens,\n validateOauth2Tokens,\n} from \"@/shared/lib/util.js\";\nimport { displayModeFromState, generateState } from \"@/lib/oauth.js\";\nimport { getVersion } from \"@/shared/index.js\";\nimport { OAuth2Client } from \"oslo/oauth2\";\nimport { LocalStorageAdapter } from \"@/browser/storage.js\";\nimport type {\n AuthenticationInitiator,\n AuthenticationResolver,\n PKCEConsumer,\n} from \"@/services/types.js\";\nimport { PopupError } from \"@/services/types.js\";\nimport { removeParamsWithoutReload } from \"@/lib/windowUtil.js\";\nimport {\n DEFAULT_AUTH_SERVER,\n DEFAULT_OAUTH_GET_PARAMS,\n LOGOUT_STATE,\n} from \"@/constants.js\";\nimport { validateLoginAppPostMessage } from \"@/lib/postMessage.js\";\nimport { getUser } from \"@/shared/lib/session.js\";\nimport { GenericUserSession } from \"@/shared/lib/UserSession.js\";\nimport { getIframeRef } from \"@/shared/lib/iframeUtils.js\";\nimport { v4 as uuid } from \"uuid\";\nimport { CodeVerifier } from \"@/shared/lib/types.js\";\nimport { BrowserAuthenticationRefresher } from \"@/shared/lib/BrowserAuthenticationRefresher.js\";\nimport { collectAndSendSDKAnalytics } from \"@/lib/analytics.js\";\n\nconst clearStorageAndEmitSignOut = async () => {\n const localStorage = new LocalStorageAdapter();\n await clearTokens(localStorage);\n await clearUser(localStorage);\n LocalStorageAdapter.emitter.emit(\"signOut\");\n};\n\nexport type GenericAuthenticationInitiatorConfig = {\n clientId: string;\n redirectUrl: string;\n state: string;\n scopes: string[];\n oauthServer: string;\n nonce?: string;\n // the endpoints to use for the login (if not obtained from the auth server)\n endpointOverrides?: Partial<Endpoints>;\n // Optional PKCE challenge - not needed for confidential clients using client secrets\n pkceConsumer?: PKCEConsumer;\n};\n\nexport type BrowserAuthenticationInitiatorConfig = Omit<\n GenericAuthenticationInitiatorConfig,\n \"state\"\n> & {\n logoutUrl?: string;\n logoutRedirectUrl: string;\n // determines whether to trigger the login/logout in an iframe, a new browser window, or redirect the current one.\n displayMode: DisplayMode;\n // Optional base path for routing in case app is served from a subdirectory\n basePath?: string;\n // Optional URL to redirect to after login success\n loginSuccessUrl?: string;\n // Framework being used (for analytics)\n framework?: FrameworkType;\n};\n\nconst defaultSetDesignOptions = (value: LoginAppDesignOptions) => {\n localStorage.setItem(\"loginAppDesign\", JSON.stringify(value));\n};\n/**\n * An authentication initiator that works on a browser. Since this is just triggering\n * login and logout, session data is not stored here.\n * An associated AuthenticationResolver would be needed to get the session data.\n * Storage is needed for the code verifier, this is the domain of the PKCEConsumer\n * The storage used by the PKCEConsumer should be available to the AuthenticationResolver.\n *\n * Example usage:\n *\n * 1) Client-only SPA -eg a react app with no server:\n * new BrowserAuthenticationInitiator({\n * pkceConsumer: new BrowserPublicClientPKCEProducer(), // generate and retrieve the challenge client-side\n * ... other config\n * })\n *\n * 2) Client-side of a client/server app - eg a react app with a backend:\n * new BrowserAuthenticationInitiator({\n * pkceConsumer: new ConfidentialClientPKCEConsumer(\"https://myserver.com/pkce\"), // get the challenge from the server\n * ... other config\n * })\n */\nexport class BrowserAuthenticationInitiator implements AuthenticationInitiator {\n private postMessageHandler: null | ((event: MessageEvent) => void) = null;\n\n protected config: BrowserAuthenticationInitiatorConfig;\n\n public setDisplayMode(displayMode: DisplayMode) {\n this.config.displayMode = displayMode;\n }\n\n get displayMode() {\n return this.config.displayMode;\n }\n\n get isServerTokenExchange() {\n return this.config.pkceConsumer instanceof ConfidentialClientPKCEConsumer;\n }\n get state() {\n return generateState({\n displayMode: this.config.displayMode,\n serverTokenExchange: this.isServerTokenExchange,\n loginSuccessUrl: this.config.loginSuccessUrl,\n framework: this.config.framework,\n sdkVersion: getVersion(),\n });\n }\n public instanceId: string;\n constructor(\n config: typeof this.config,\n readonly setDesignOptions = defaultSetDesignOptions,\n ) {\n this.instanceId = uuid();\n this.config = config;\n\n this.postMessageHandler = (event: MessageEvent) => {\n const thisURL = new URL(window.location.href);\n if (\n event.origin.endsWith(\"civic.com\") ||\n thisURL.hostname === \"localhost\"\n ) {\n if (!validateLoginAppPostMessage(event.data, this.config.clientId)) {\n return;\n }\n const loginMessage = event.data as LoginPostMessage;\n if (loginMessage.type === \"generatePopupFailed\") {\n this.handleLoginAppPopupFailed(\n (loginMessage.data as { url: string }).url,\n );\n return;\n }\n if (loginMessage.type === \"design\") {\n // TODO handle the design message\n this.handleLoginAppDesignUpdate(\n loginMessage.data as LoginAppDesignOptions,\n );\n return;\n }\n }\n };\n\n window.addEventListener(\"message\", this.postMessageHandler);\n }\n\n async handleLoginAppPopupFailed(redirectUrl: string) {\n console.warn(\n \"Login app popup failed open a popup, using redirect mode instead...\",\n redirectUrl,\n );\n window.location.href = redirectUrl;\n }\n\n async handleLoginAppDesignUpdate(options: LoginAppDesignOptions) {\n this.setDesignOptions(options);\n }\n\n // Use the config (Client ID, scopes OAuth Server, Endpoints, PKCEConsumer) to generate a new login url\n // and then use the display mode to decide how to send the user there\n async signIn(iframeRef: HTMLIFrameElement | null): Promise<URL> {\n // Send SDK analytics when authentication starts\n // Fire and forget - don't block authentication if analytics fails\n collectAndSendSDKAnalytics(\n this.config.clientId,\n this.config.oauthServer,\n this.config.framework,\n );\n\n const url = await generateOauthLoginUrl({\n ...this.config,\n state: this.state,\n });\n\n if (this.config.displayMode === \"iframe\") {\n const ref = getIframeRef(iframeRef);\n ref.setAttribute(\"src\", url.toString());\n }\n\n if (this.config.displayMode === \"redirect\") {\n window.location.href = url.toString();\n }\n\n if (this.config.displayMode === \"new_tab\") {\n try {\n const popupWindow = window.open(url.toString(), \"_blank\");\n if (!popupWindow) {\n throw new PopupError(\"Failed to open popup window\");\n }\n // TODO handle the 'onclose' event to clean up and reset the authStatus\n } catch (error) {\n console.error(\"popupWindow\", error);\n throw new PopupError(\n \"window.open has thrown: Failed to open popup window\",\n );\n }\n }\n\n return url;\n }\n\n async signOut(\n idToken: string | undefined,\n iframeRef: HTMLIFrameElement | null,\n ): Promise<URL> {\n let url;\n const localStorage = new LocalStorageAdapter();\n const state = this.state;\n if (this.isServerTokenExchange) {\n if (!this.config.logoutUrl) {\n throw new Error(\"logoutUrl is required for server token exchange\");\n }\n url = new URL(this.config.logoutUrl, window.location.origin);\n url.searchParams.append(\"state\", state);\n } else {\n if (!idToken) {\n throw new Error(\"idToken is required for non-server token exchange\");\n }\n\n url = await generateOauthLogoutUrl({\n ...this.config,\n idToken,\n state,\n redirectUrl: this.config.logoutRedirectUrl,\n });\n }\n\n if (this.config.displayMode === \"iframe\") {\n // Clear storage before calling server by setting iframe src to the logout url\n await clearStorageAndEmitSignOut();\n await localStorage.delete(LOGOUT_STATE);\n const ref = getIframeRef(iframeRef);\n ref.setAttribute(\"src\", url.toString());\n\n LocalStorageAdapter.emitter.emit(\"signOut\");\n }\n\n if (this.config.displayMode === \"redirect\") {\n // we don't clear any storage here as we're redirecting to the logout url\n // and the server should handle that\n await localStorage.set(LOGOUT_STATE, state);\n window.location.href = url.toString();\n }\n\n if (this.config.displayMode === \"new_tab\") {\n try {\n // Clear storage before calling server by setting iframe src to the logout url\n await clearStorageAndEmitSignOut();\n const popupWindow = window.open(url.toString(), \"_blank\");\n if (!popupWindow) {\n throw new PopupError(\"Failed to open popup window\");\n }\n } catch (error) {\n console.error(\"popupWindow\", error);\n throw new PopupError(\n \"window.open has thrown: Failed to open popup window\",\n );\n }\n }\n\n return url;\n }\n\n cleanup() {\n if (this.postMessageHandler) {\n window.removeEventListener(\"message\", this.postMessageHandler);\n }\n }\n}\n\n/** A general-purpose authentication initiator, that just generates urls, but lets\n * the caller decide how to use them. This is useful for server-side applications\n * that may serve this URL to their front-ends or just call them directly\n */\nexport class GenericAuthenticationInitiator implements AuthenticationInitiator {\n protected config: GenericAuthenticationInitiatorConfig;\n\n constructor(config: typeof this.config) {\n this.config = config;\n }\n\n // Use the config (Client ID, scopes OAuth Server, Endpoints, PKCEConsumer) to generate a new login url\n // and simply return the url\n async signIn(): Promise<URL> {\n return generateOauthLoginUrl(this.config);\n }\n\n async signOut(idToken: string): Promise<URL> {\n return generateOauthLogoutUrl({\n ...this.config,\n idToken,\n });\n }\n}\n\ntype BrowserAuthenticationConfig = {\n clientId: string;\n redirectUrl: string;\n logoutUrl?: string;\n logoutRedirectUrl: string;\n scopes: string[];\n oauthServer: string;\n endpointOverrides?: Partial<Endpoints>;\n displayMode: DisplayMode;\n};\n\n/**\n * An authentication resolver that can run on the browser (i.e. a public client)\n * It uses PKCE for security. PKCE and Session data are stored in local storage\n */\nexport class BrowserAuthenticationService extends BrowserAuthenticationInitiator {\n private oauth2client: OAuth2Client | undefined;\n private endpoints: Endpoints | undefined;\n\n // TODO WIP - perhaps we want to keep resolver and initiator separate here\n constructor(\n config: BrowserAuthenticationConfig,\n // Since we are running fully on the client, we produce as well as consume the PKCE challenge\n protected pkceProducer = new BrowserPublicClientPKCEProducer(),\n ) {\n super({\n ...config,\n // Store and retrieve the PKCE challenge in local storage\n pkceConsumer: pkceProducer,\n });\n }\n\n // TODO too much code duplication here between the browser and the server variant.\n // Suggestion for refactor: Standardise the config for AuthenticationResolvers and create a one-shot\n // function for generating an oauth2client from it\n async init(): Promise<this> {\n // resolve oauth config\n this.endpoints = await getEndpointsWithOverrides(\n this.oauthServer,\n this.config.endpointOverrides,\n );\n this.oauth2client = new OAuth2Client(\n this.config.clientId,\n this.endpoints.auth,\n this.endpoints.token,\n {\n redirectURI: this.config.redirectUrl,\n },\n );\n\n return this;\n }\n\n async storeTokensOnLogin(tokens: OIDCTokenResponseBody) {\n const clientStorage = new LocalStorageAdapter();\n await storeTokens(clientStorage, tokens);\n // delete code verifier as it should be single-use\n await clientStorage.delete(CodeVerifier.COOKIE_NAME);\n const user = await getUser(clientStorage);\n if (!user) {\n throw new Error(\"Failed to get user info\");\n }\n const userSession = new GenericUserSession(clientStorage);\n await userSession.set(user);\n LocalStorageAdapter.emitter.emit(\"signIn\");\n }\n\n // Two responsibilities:\n // 1. resolve the auth code to get the tokens (should use library code)\n // 2. store the tokens in local storage\n async tokenExchange(\n code: string,\n state: string,\n ): Promise<OIDCTokenResponseBody> {\n if (!this.oauth2client) await this.init();\n const codeVerifier = await this.pkceProducer.getCodeVerifier();\n if (!codeVerifier) throw new Error(\"Code verifier not found in storage\");\n\n // exchange auth code for tokens\n const tokens = await exchangeTokens(\n code,\n state,\n this.pkceProducer,\n this.oauth2client!, // clean up types here to avoid the ! operator\n this.oauthServer,\n this.endpoints!, // clean up types here to avoid the ! operator\n );\n await this.storeTokensOnLogin(tokens);\n // cleanup the browser window if needed\n const parsedDisplayMode = displayModeFromState(\n state,\n this.config.displayMode,\n );\n\n if (parsedDisplayMode === \"new_tab\") {\n // Close the popup window\n window.addEventListener(\"beforeunload\", () => {\n window?.opener?.focus();\n });\n window.close();\n }\n // these are the default oAuth params that get added to the URL in redirect which we want to remove if present\n removeParamsWithoutReload(DEFAULT_OAUTH_GET_PARAMS);\n return tokens;\n }\n\n // Get the session data from local storage\n async getSessionData(): Promise<SessionData | null> {\n const storageData = await retrieveTokens(new LocalStorageAdapter());\n if (!storageData) return null;\n\n return {\n authenticated: !!storageData.id_token,\n idToken: storageData.id_token,\n accessToken: storageData.access_token,\n refreshToken: storageData.refresh_token,\n oidcSessionExpiresAt: storageData.oidc_session_expires_at,\n };\n }\n\n async tryRefreshTokens(\n sessionData: SessionData | null,\n ): Promise<SessionData> {\n // If token validation fails but we have a refresh token, attempt to refresh\n if (sessionData?.refreshToken) {\n try {\n const clientStorage = new LocalStorageAdapter();\n\n // Create a BrowserAuthenticationRefresher to handle token refresh using the build method\n const authConfig = {\n clientId: this.config.clientId,\n oauthServer: this.oauthServer,\n redirectUrl: this.config.redirectUrl,\n };\n\n // Use build method which handles initialization\n const refresher = await BrowserAuthenticationRefresher.build(\n authConfig,\n clientStorage,\n async (error: Error) => {\n console.warn(\"Failed to refresh tokens during validation\", error);\n },\n this.config.endpointOverrides,\n );\n\n try {\n // Perform token refresh (no need to call init explicitly)\n const tokenResponse = await refresher.refreshAccessToken();\n // Return a new session with the refreshed tokens\n const refreshedSession = await this.getSessionData();\n if (refreshedSession && refreshedSession.authenticated) {\n await this.storeTokensOnLogin(tokenResponse);\n return {\n ...refreshedSession,\n authenticated: true,\n };\n } else {\n throw new Error(\"Failed to get refreshed session data\");\n }\n } catch (refreshApiError) {\n console.error(\n \"Error during token refresh API call:\",\n refreshApiError,\n );\n throw refreshApiError; // Re-throw to be caught by outer catch block\n }\n } catch (error) {\n const refreshError = error as Error;\n console.error(\"Token refresh failed with error:\", refreshError);\n // Only delete refresh token if it's invalid, not for network errors\n // which might be temporary\n if (\n refreshError.message.includes(\"invalid\") ||\n refreshError.message.includes(\"expired\")\n ) {\n const clientStorage = new LocalStorageAdapter();\n console.log(\"Deleting invalid refresh token\");\n await clearTokens(clientStorage);\n await clearUser(clientStorage);\n }\n console.warn(\"Failed to refresh tokens\", refreshError);\n }\n }\n\n return {\n ...sessionData,\n authenticated: false,\n };\n }\n\n async validateExistingSession(): Promise<SessionData> {\n try {\n const sessionData = await this.getSessionData();\n if (!sessionData?.idToken) {\n const refreshedSessionData = await this.tryRefreshTokens(sessionData);\n if (refreshedSessionData.authenticated) {\n return refreshedSessionData;\n }\n const unAuthenticatedSession = { ...sessionData, authenticated: false };\n return unAuthenticatedSession;\n }\n if (!this.endpoints?.jwks || !this.oauth2client) await this.init();\n\n if (!this.endpoints?.jwks) {\n throw new Error(\"No jwks endpoint\");\n }\n\n // this function will throw if the idToken is invalid\n // Note: Access token is no longer required for authentication\n await validateOauth2Tokens(\n {\n id_token: sessionData.idToken,\n refresh_token: sessionData.refreshToken,\n access_token: sessionData.accessToken,\n oidc_session_expires_at: sessionData.oidcSessionExpiresAt,\n },\n this.endpoints.jwks,\n this.oauth2client!,\n this.oauthServer,\n );\n return sessionData;\n } catch (error) {\n console.warn(\"Failed to validate existing tokens\", error);\n const unAuthenticatedSession = {\n authenticated: false,\n };\n const storage = new LocalStorageAdapter();\n await clearTokens(storage);\n await clearUser(storage);\n return unAuthenticatedSession;\n }\n }\n\n get oauthServer(): string {\n return this.config.oauthServer || DEFAULT_AUTH_SERVER;\n }\n\n async getEndSessionEndpoint(): Promise<string | null> {\n if (!this.endpoints) {\n return null;\n }\n return this.endpoints?.endsession;\n }\n\n static async build(\n config: BrowserAuthenticationConfig,\n ): Promise<AuthenticationResolver> {\n const resolver = new BrowserAuthenticationService(config);\n await resolver.init();\n\n return resolver;\n }\n}\n"]}
1
+ {"version":3,"file":"AuthenticationService.js","sourceRoot":"","sources":["../../src/services/AuthenticationService.ts"],"names":[],"mappings":"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","sourcesContent":["// Proposals for revised versions of the SessionService AKA AuthSessionService\n\nimport type {\n DisplayMode,\n Endpoints,\n FrameworkType,\n LoginAppDesignOptions,\n LoginPostMessage,\n OIDCTokenResponseBody,\n SessionData,\n} from \"@/types.js\";\nimport {\n BrowserPublicClientPKCEProducer,\n ConfidentialClientPKCEConsumer,\n} from \"@/services/PKCE.js\";\nimport {\n clearTokens,\n clearUser,\n exchangeTokens,\n generateOauthLoginUrl,\n generateOauthLogoutUrl,\n getEndpointsWithOverrides,\n retrieveTokens,\n storeTokens,\n validateOauth2Tokens,\n} from \"@/shared/lib/util.js\";\nimport { displayModeFromState, generateState } from \"@/lib/oauth.js\";\nimport { getVersion } from \"@/shared/index.js\";\nimport { OAuth2Client } from \"oslo/oauth2\";\nimport { LocalStorageAdapter } from \"@/browser/storage.js\";\nimport type {\n AuthenticationInitiator,\n AuthenticationResolver,\n PKCEConsumer,\n} from \"@/services/types.js\";\nimport { PopupError } from \"@/services/types.js\";\nimport { removeParamsWithoutReload } from \"@/lib/windowUtil.js\";\nimport {\n DEFAULT_AUTH_SERVER,\n DEFAULT_OAUTH_GET_PARAMS,\n LOGOUT_STATE,\n} from \"@/constants.js\";\nimport { validateLoginAppPostMessage } from \"@/lib/postMessage.js\";\nimport { getUser } from \"@/shared/lib/session.js\";\nimport { GenericUserSession } from \"@/shared/lib/UserSession.js\";\nimport {\n getIframeRef,\n iframeIsVisible,\n isEmbeddedIframeMode,\n} from \"@/shared/lib/iframeUtils.js\";\nimport { v4 as uuid } from \"uuid\";\nimport { CodeVerifier } from \"@/shared/lib/types.js\";\nimport { BrowserAuthenticationRefresher } from \"@/shared/lib/BrowserAuthenticationRefresher.js\";\nimport { collectAndSendSDKAnalytics } from \"@/lib/analytics.js\";\n\nconst clearStorageAndEmitSignOut = async () => {\n const localStorage = new LocalStorageAdapter();\n await clearTokens(localStorage);\n await clearUser(localStorage);\n LocalStorageAdapter.emitter.emit(\"signOut\");\n};\n\nexport type GenericAuthenticationInitiatorConfig = {\n clientId: string;\n redirectUrl: string;\n state: string;\n scopes: string[];\n oauthServer: string;\n nonce?: string;\n // the endpoints to use for the login (if not obtained from the auth server)\n endpointOverrides?: Partial<Endpoints>;\n // Optional PKCE challenge - not needed for confidential clients using client secrets\n pkceConsumer?: PKCEConsumer;\n};\n\nexport type BrowserAuthenticationInitiatorConfig = Omit<\n GenericAuthenticationInitiatorConfig,\n \"state\"\n> & {\n logoutUrl?: string;\n logoutRedirectUrl: string;\n // determines whether to trigger the login/logout in an iframe, a new browser window, or redirect the current one.\n displayMode: DisplayMode;\n // Optional iframe display mode - modal (full-screen overlay) or embedded (within container)\n iframeDisplayMode?: \"modal\" | \"embedded\";\n // Optional base path for routing in case app is served from a subdirectory\n basePath?: string;\n // Optional URL to redirect to after login success\n loginSuccessUrl?: string;\n // Framework being used (for analytics)\n framework?: FrameworkType;\n // Whether to automatically switch to redirect mode when browser doesn't support iframe-based auth\n autoRedirect?: boolean;\n};\n\nconst defaultSetDesignOptions = (value: LoginAppDesignOptions) => {\n localStorage.setItem(\"loginAppDesign\", JSON.stringify(value));\n};\n/**\n * An authentication initiator that works on a browser. Since this is just triggering\n * login and logout, session data is not stored here.\n * An associated AuthenticationResolver would be needed to get the session data.\n * Storage is needed for the code verifier, this is the domain of the PKCEConsumer\n * The storage used by the PKCEConsumer should be available to the AuthenticationResolver.\n *\n * Example usage:\n *\n * 1) Client-only SPA -eg a react app with no server:\n * new BrowserAuthenticationInitiator({\n * pkceConsumer: new BrowserPublicClientPKCEProducer(), // generate and retrieve the challenge client-side\n * ... other config\n * })\n *\n * 2) Client-side of a client/server app - eg a react app with a backend:\n * new BrowserAuthenticationInitiator({\n * pkceConsumer: new ConfidentialClientPKCEConsumer(\"https://myserver.com/pkce\"), // get the challenge from the server\n * ... other config\n * })\n */\nexport class BrowserAuthenticationInitiator implements AuthenticationInitiator {\n private postMessageHandler: null | ((event: MessageEvent) => void) = null;\n\n protected config: BrowserAuthenticationInitiatorConfig;\n static browserCorsFailsSilentlyRedirectUrl: string;\n private _iframeRef: HTMLIFrameElement | null = null;\n\n public setDisplayMode(displayMode: DisplayMode) {\n this.config.displayMode = displayMode;\n }\n\n get displayMode() {\n return this.config.displayMode;\n }\n\n get isServerTokenExchange() {\n return this.config.pkceConsumer instanceof ConfidentialClientPKCEConsumer;\n }\n get state() {\n return generateState({\n displayMode: this.config.displayMode,\n iframeDisplayMode: this.config.iframeDisplayMode,\n serverTokenExchange: this.isServerTokenExchange,\n loginSuccessUrl: this.config.loginSuccessUrl,\n framework: this.config.framework,\n sdkVersion: getVersion(),\n });\n }\n public instanceId: string;\n public browserCorsFailsSilentlyRedirectUrl: string = \"\";\n\n constructor(\n config: typeof this.config,\n readonly setDesignOptions = defaultSetDesignOptions,\n ) {\n this.instanceId = uuid();\n this.config = config;\n\n this.postMessageHandler = (event: MessageEvent) => {\n const thisURL = new URL(window.location.href);\n if (\n event.origin.endsWith(\"civic.com\") ||\n thisURL.hostname === \"localhost\"\n ) {\n if (!validateLoginAppPostMessage(event.data, this.config.clientId)) {\n return;\n }\n const loginMessage = event.data as LoginPostMessage;\n if (loginMessage.type === \"generatePopupFailed\") {\n this.handleLoginAppPopupFailed(\n (loginMessage.data as { url: string }).url,\n );\n return;\n }\n if (\n loginMessage.type === \"browserCorsFailsSilently\" &&\n this.displayMode === \"iframe\"\n ) {\n this.handleBrowserCorsFailsSilently(\n (loginMessage.data as { url: string }).url,\n );\n return;\n }\n if (loginMessage.type === \"design\") {\n // TODO handle the design message\n this.handleLoginAppDesignUpdate(\n loginMessage.data as LoginAppDesignOptions,\n );\n return;\n }\n }\n };\n\n window.addEventListener(\"message\", this.postMessageHandler);\n }\n\n async handleLoginAppPopupFailed(redirectUrl: string) {\n console.warn(\n \"Login app popup failed open a popup, using redirect mode instead...\",\n redirectUrl,\n );\n window.location.href = redirectUrl;\n }\n\n async handleBrowserCorsFailsSilently(redirectUrl: string) {\n console.warn(\n \"Login app opened in a browser where popups fail silently...\",\n {\n redirectUrl,\n iframeIsVisible: iframeIsVisible(),\n autoRedirect: this.config.autoRedirect,\n },\n );\n BrowserAuthenticationInitiator.browserCorsFailsSilentlyRedirectUrl =\n redirectUrl;\n // Check autoRedirect config before proceeding\n if (this.config.autoRedirect !== false && iframeIsVisible()) {\n // hide the iframe as we're in redirect mode\n // to avoid it loading then immediately disappearing\n const iframe = document.getElementById(\n \"civic-auth-iframe-container\",\n ) as HTMLIFrameElement | null;\n if (iframe) {\n iframe.style.display = \"none\";\n }\n return this.handleUserInteractionBrowserCorsFailsSilently();\n }\n }\n\n async handleUserInteractionBrowserCorsFailsSilently(): Promise<{\n isRedirecting: boolean;\n }> {\n const isInEmbeddedIframeMode = isEmbeddedIframeMode();\n // check if the iframe is visible\n if (\n !isInEmbeddedIframeMode &&\n this.config.autoRedirect !== false && // Add this check\n BrowserAuthenticationInitiator.browserCorsFailsSilentlyRedirectUrl\n ) {\n console.warn(\n \"Browser CORS failed silently, redirecting...\",\n BrowserAuthenticationInitiator.browserCorsFailsSilentlyRedirectUrl,\n );\n this.config.displayMode = \"redirect\";\n collectAndSendSDKAnalytics(\n this.config.clientId,\n this.config.oauthServer,\n this.config.framework,\n );\n const signInUrl = await this.getSignInUrl();\n window.dispatchEvent(\n new CustomEvent(\"locationWillChange\", {\n detail: { newUrl: signInUrl.toString() },\n }),\n );\n setTimeout(() => {\n window.location.href = signInUrl.toString();\n }, 100);\n return { isRedirecting: true };\n }\n return { isRedirecting: false };\n }\n\n async handleLoginAppDesignUpdate(options: LoginAppDesignOptions) {\n this.setDesignOptions(options);\n }\n\n async getSignInUrl(): Promise<URL> {\n const val = await generateOauthLoginUrl({\n ...this.config,\n state: this.state,\n });\n return val;\n }\n\n // Use the config (Client ID, scopes OAuth Server, Endpoints, PKCEConsumer) to generate a new login url\n // and then use the display mode to decide how to send the user there\n async signIn(iframeRef: HTMLIFrameElement | null): Promise<URL> {\n // Send SDK analytics when authentication starts\n // Fire and forget - don't block authentication if analytics fails\n collectAndSendSDKAnalytics(\n this.config.clientId,\n this.config.oauthServer,\n this.config.framework,\n );\n\n const url = await this.getSignInUrl();\n\n if (this.config.displayMode === \"iframe\") {\n const ref = getIframeRef(iframeRef);\n ref.setAttribute(\"src\", url.toString());\n }\n\n if (this.config.displayMode === \"redirect\") {\n window.location.href = url.toString();\n }\n\n if (this.config.displayMode === \"new_tab\") {\n try {\n const popupWindow = window.open(url.toString(), \"_blank\");\n if (!popupWindow) {\n throw new PopupError(\"Failed to open popup window\");\n }\n // TODO handle the 'onclose' event to clean up and reset the authStatus\n } catch (error) {\n console.error(\"popupWindow\", error);\n throw new PopupError(\n \"window.open has thrown: Failed to open popup window\",\n );\n }\n }\n\n return url;\n }\n\n async signOut(\n idToken: string | undefined,\n iframeRef: HTMLIFrameElement | null,\n ): Promise<URL> {\n let url;\n const localStorage = new LocalStorageAdapter();\n const state = this.state;\n if (this.isServerTokenExchange) {\n if (!this.config.logoutUrl) {\n throw new Error(\"logoutUrl is required for server token exchange\");\n }\n url = new URL(this.config.logoutUrl, window.location.origin);\n url.searchParams.append(\"state\", state);\n } else {\n if (!idToken) {\n throw new Error(\"idToken is required for non-server token exchange\");\n }\n\n url = await generateOauthLogoutUrl({\n ...this.config,\n idToken,\n state,\n redirectUrl: this.config.logoutRedirectUrl,\n });\n }\n\n if (this.config.displayMode === \"iframe\") {\n // Clear storage before calling server by setting iframe src to the logout url\n await clearStorageAndEmitSignOut();\n await localStorage.delete(LOGOUT_STATE);\n const ref = getIframeRef(iframeRef);\n ref.setAttribute(\"src\", url.toString());\n\n LocalStorageAdapter.emitter.emit(\"signOut\");\n }\n\n if (this.config.displayMode === \"redirect\") {\n // we don't clear any storage here as we're redirecting to the logout url\n // and the server should handle that\n await localStorage.set(LOGOUT_STATE, state);\n window.location.href = url.toString();\n }\n\n if (this.config.displayMode === \"new_tab\") {\n try {\n // Clear storage before calling server by setting iframe src to the logout url\n await clearStorageAndEmitSignOut();\n const popupWindow = window.open(url.toString(), \"_blank\");\n if (!popupWindow) {\n throw new PopupError(\"Failed to open popup window\");\n }\n } catch (error) {\n console.error(\"popupWindow\", error);\n throw new PopupError(\n \"window.open has thrown: Failed to open popup window\",\n );\n }\n }\n\n return url;\n }\n\n cleanup() {\n if (this.postMessageHandler) {\n window.removeEventListener(\"message\", this.postMessageHandler);\n }\n }\n}\n\n/** A general-purpose authentication initiator, that just generates urls, but lets\n * the caller decide how to use them. This is useful for server-side applications\n * that may serve this URL to their front-ends or just call them directly\n */\nexport class GenericAuthenticationInitiator implements AuthenticationInitiator {\n protected config: GenericAuthenticationInitiatorConfig;\n\n constructor(config: typeof this.config) {\n this.config = config;\n }\n\n // Use the config (Client ID, scopes OAuth Server, Endpoints, PKCEConsumer) to generate a new login url\n // and simply return the url\n async signIn(): Promise<URL> {\n return generateOauthLoginUrl(this.config);\n }\n\n async signOut(idToken: string): Promise<URL> {\n return generateOauthLogoutUrl({\n ...this.config,\n idToken,\n });\n }\n}\n\ntype BrowserAuthenticationConfig = {\n clientId: string;\n redirectUrl: string;\n logoutUrl?: string;\n logoutRedirectUrl: string;\n scopes: string[];\n oauthServer: string;\n endpointOverrides?: Partial<Endpoints>;\n displayMode: DisplayMode;\n};\n\n/**\n * An authentication resolver that can run on the browser (i.e. a public client)\n * It uses PKCE for security. PKCE and Session data are stored in local storage\n */\nexport class BrowserAuthenticationService extends BrowserAuthenticationInitiator {\n private oauth2client: OAuth2Client | undefined;\n private endpoints: Endpoints | undefined;\n\n // TODO WIP - perhaps we want to keep resolver and initiator separate here\n constructor(\n config: BrowserAuthenticationConfig,\n // Since we are running fully on the client, we produce as well as consume the PKCE challenge\n protected pkceProducer = new BrowserPublicClientPKCEProducer(),\n ) {\n super({\n ...config,\n // Store and retrieve the PKCE challenge in local storage\n pkceConsumer: pkceProducer,\n });\n }\n\n // TODO too much code duplication here between the browser and the server variant.\n // Suggestion for refactor: Standardise the config for AuthenticationResolvers and create a one-shot\n // function for generating an oauth2client from it\n async init(): Promise<this> {\n // resolve oauth config\n this.endpoints = await getEndpointsWithOverrides(\n this.oauthServer,\n this.config.endpointOverrides,\n );\n this.oauth2client = new OAuth2Client(\n this.config.clientId,\n this.endpoints.auth,\n this.endpoints.token,\n {\n redirectURI: this.config.redirectUrl,\n },\n );\n\n return this;\n }\n\n async storeTokensOnLogin(tokens: OIDCTokenResponseBody) {\n const clientStorage = new LocalStorageAdapter();\n await storeTokens(clientStorage, tokens);\n // delete code verifier as it should be single-use\n await clientStorage.delete(CodeVerifier.COOKIE_NAME);\n const user = await getUser(clientStorage);\n if (!user) {\n throw new Error(\"Failed to get user info\");\n }\n const userSession = new GenericUserSession(clientStorage);\n await userSession.set(user);\n LocalStorageAdapter.emitter.emit(\"signIn\");\n }\n\n // Two responsibilities:\n // 1. resolve the auth code to get the tokens (should use library code)\n // 2. store the tokens in local storage\n async tokenExchange(\n code: string,\n state: string,\n ): Promise<OIDCTokenResponseBody> {\n if (!this.oauth2client) await this.init();\n const codeVerifier = await this.pkceProducer.getCodeVerifier();\n if (!codeVerifier) throw new Error(\"Code verifier not found in storage\");\n\n // exchange auth code for tokens\n const tokens = await exchangeTokens(\n code,\n state,\n this.pkceProducer,\n this.oauth2client!, // clean up types here to avoid the ! operator\n this.oauthServer,\n this.endpoints!, // clean up types here to avoid the ! operator\n );\n await this.storeTokensOnLogin(tokens);\n // cleanup the browser window if needed\n const parsedDisplayMode = displayModeFromState(\n state,\n this.config.displayMode,\n );\n\n if (parsedDisplayMode === \"new_tab\") {\n // Close the popup window\n window.addEventListener(\"beforeunload\", () => {\n window?.opener?.focus();\n });\n window.close();\n }\n // these are the default oAuth params that get added to the URL in redirect which we want to remove if present\n removeParamsWithoutReload(DEFAULT_OAUTH_GET_PARAMS);\n return tokens;\n }\n\n // Get the session data from local storage\n async getSessionData(): Promise<SessionData | null> {\n const storageData = await retrieveTokens(new LocalStorageAdapter());\n if (!storageData) return null;\n\n return {\n authenticated: !!storageData.id_token,\n idToken: storageData.id_token,\n accessToken: storageData.access_token,\n refreshToken: storageData.refresh_token,\n oidcSessionExpiresAt: storageData.oidc_session_expires_at,\n };\n }\n\n async tryRefreshTokens(\n sessionData: SessionData | null,\n ): Promise<SessionData> {\n // If token validation fails but we have a refresh token, attempt to refresh\n if (sessionData?.refreshToken) {\n try {\n const clientStorage = new LocalStorageAdapter();\n\n // Create a BrowserAuthenticationRefresher to handle token refresh using the build method\n const authConfig = {\n clientId: this.config.clientId,\n oauthServer: this.oauthServer,\n redirectUrl: this.config.redirectUrl,\n };\n\n // Use build method which handles initialization\n const refresher = await BrowserAuthenticationRefresher.build(\n authConfig,\n clientStorage,\n async (error: Error) => {\n console.warn(\"Failed to refresh tokens during validation\", error);\n },\n this.config.endpointOverrides,\n );\n\n try {\n // Perform token refresh (no need to call init explicitly)\n const tokenResponse = await refresher.refreshAccessToken();\n\n // For backend flows, tokenResponse might be null since tokens are in HTTP-only cookies\n if (tokenResponse) {\n // Store tokens for SPA flows where tokens are accessible\n await this.storeTokensOnLogin(tokenResponse);\n }\n\n // Return a new session with the refreshed tokens\n const refreshedSession = await this.getSessionData();\n if (refreshedSession && refreshedSession.authenticated) {\n return {\n ...refreshedSession,\n authenticated: true,\n };\n } else {\n throw new Error(\"Failed to get refreshed session data\");\n }\n } catch (refreshApiError) {\n console.error(\n \"Error during token refresh API call:\",\n refreshApiError,\n );\n throw refreshApiError; // Re-throw to be caught by outer catch block\n }\n } catch (error) {\n const refreshError = error as Error;\n console.error(\"Token refresh failed with error:\", refreshError);\n // Only delete refresh token if it's invalid, not for network errors\n // which might be temporary\n if (\n refreshError.message.includes(\"invalid\") ||\n refreshError.message.includes(\"expired\")\n ) {\n const clientStorage = new LocalStorageAdapter();\n console.log(\"Deleting invalid refresh token\");\n await clearTokens(clientStorage);\n await clearUser(clientStorage);\n }\n console.warn(\"Failed to refresh tokens\", refreshError);\n }\n }\n\n return {\n ...sessionData,\n authenticated: false,\n };\n }\n\n async validateExistingSession(): Promise<SessionData> {\n try {\n const sessionData = await this.getSessionData();\n if (!sessionData?.idToken) {\n const refreshedSessionData = await this.tryRefreshTokens(sessionData);\n if (refreshedSessionData.authenticated) {\n return refreshedSessionData;\n }\n const unAuthenticatedSession = { ...sessionData, authenticated: false };\n return unAuthenticatedSession;\n }\n if (!this.endpoints?.jwks || !this.oauth2client) await this.init();\n\n if (!this.endpoints?.jwks) {\n throw new Error(\"No jwks endpoint\");\n }\n\n // this function will throw if the idToken is invalid\n // Note: Access token is no longer required for authentication\n await validateOauth2Tokens(\n {\n id_token: sessionData.idToken,\n refresh_token: sessionData.refreshToken,\n access_token: sessionData.accessToken,\n oidc_session_expires_at: sessionData.oidcSessionExpiresAt,\n },\n this.endpoints.jwks,\n this.oauth2client!,\n this.oauthServer,\n );\n return sessionData;\n } catch (error) {\n console.warn(\"Failed to validate existing tokens\", error);\n const unAuthenticatedSession = {\n authenticated: false,\n };\n const storage = new LocalStorageAdapter();\n await clearTokens(storage);\n await clearUser(storage);\n return unAuthenticatedSession;\n }\n }\n\n get oauthServer(): string {\n return this.config.oauthServer || DEFAULT_AUTH_SERVER;\n }\n\n async getEndSessionEndpoint(): Promise<string | null> {\n if (!this.endpoints) {\n return null;\n }\n return this.endpoints?.endsession;\n }\n\n static async build(\n config: BrowserAuthenticationConfig,\n ): Promise<AuthenticationResolver> {\n const resolver = new BrowserAuthenticationService(config);\n await resolver.init();\n\n return resolver;\n }\n}\n"]}
@@ -17,7 +17,7 @@ export interface AuthenticationResolver {
17
17
  tryRefreshTokens(sessionData: SessionData | null): Promise<SessionData>;
18
18
  }
19
19
  export interface AuthenticationRefresher {
20
- refreshTokens: () => Promise<OIDCTokenResponseBody>;
20
+ refreshTokens: () => Promise<OIDCTokenResponseBody | null>;
21
21
  }
22
22
  export declare class PopupError extends Error {
23
23
  constructor(message: string);
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/services/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AASrE,MAAM,WAAW,YAAY;IAE3B,gBAAgB,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;CACrC;AAGD,MAAM,WAAW,YAAa,SAAQ,YAAY;IAEhD,eAAe,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;CAC3C;AAGD,MAAM,WAAW,uBAAuB;IAEtC,MAAM,CAAC,SAAS,EAAE,iBAAiB,GAAG,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;IAG1D,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,iBAAiB,GAAG,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;CAC7E;AAGD,MAAM,WAAW,sBAAsB;IAKrC,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAAC;IAG3E,cAAc,IAAI,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IAE9C,qBAAqB,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAEhD,uBAAuB,CAAC,WAAW,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IAIrE,gBAAgB,CAAC,WAAW,EAAE,WAAW,GAAG,IAAI,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;CACzE;AAED,MAAM,WAAW,uBAAuB;IACtC,aAAa,EAAE,MAAM,OAAO,CAAC,qBAAqB,CAAC,CAAC;CACrD;AAED,qBAAa,UAAW,SAAQ,KAAK;gBACvB,OAAO,EAAE,MAAM;CAI5B"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/services/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AASrE,MAAM,WAAW,YAAY;IAE3B,gBAAgB,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;CACrC;AAGD,MAAM,WAAW,YAAa,SAAQ,YAAY;IAEhD,eAAe,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;CAC3C;AAGD,MAAM,WAAW,uBAAuB;IAEtC,MAAM,CAAC,SAAS,EAAE,iBAAiB,GAAG,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;IAG1D,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,iBAAiB,GAAG,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;CAC7E;AAGD,MAAM,WAAW,sBAAsB;IAKrC,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAAC;IAG3E,cAAc,IAAI,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IAE9C,qBAAqB,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAEhD,uBAAuB,CAAC,WAAW,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IAIrE,gBAAgB,CAAC,WAAW,EAAE,WAAW,GAAG,IAAI,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;CACzE;AAED,MAAM,WAAW,uBAAuB;IACtC,aAAa,EAAE,MAAM,OAAO,CAAC,qBAAqB,GAAG,IAAI,CAAC,CAAC;CAC5D;AAED,qBAAa,UAAW,SAAQ,KAAK;gBACvB,OAAO,EAAE,MAAM;CAI5B"}
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/services/types.ts"],"names":[],"mappings":"AAqDA,MAAM,OAAO,UAAW,SAAQ,KAAK;IACnC,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,UAAU,CAAC,SAAS,CAAC,CAAC;IACpD,CAAC;CACF","sourcesContent":["import type { OIDCTokenResponseBody, SessionData } from \"@/types.js\";\n\n// A PKCEConsumer can get a code challenge to use in the login process\n// A PKCEProducer can also generate and store verifiers. The producer must also be a consumer in order to get the challenge from an existing flow\n// Examples:\n// - Client-only SPA: The SPA generates the code challenge and verifier, stores the verifier in state and returns the code challenge\n// Note - The SPA should use PKCEProducer instead to do both\n// - Client-side of a client/server app: The client calls the backend to get the challenge.\n// - Server-side: The server should generate a new stored verifier and derive the challenge from it.\nexport interface PKCEConsumer {\n // Retrieve a new PKCE challenge\n getCodeChallenge(): Promise<string>;\n}\n\n// All producers are consumers, because the producer can get its own challenge\nexport interface PKCEProducer extends PKCEConsumer {\n // Retrieve the PKCE challenge from the session if one exists\n getCodeVerifier(): Promise<string | null>;\n}\n\n// A service that can initiate requests to login or log out\nexport interface AuthenticationInitiator {\n // trigger a new login\n signIn(iframeRef: HTMLIFrameElement | null): Promise<URL>;\n\n // trigger a new logout\n signOut(idToken: string, iframeRef: HTMLIFrameElement | null): Promise<URL>;\n}\n\n// A service that can resolve an authentication request according to the OAuth Auth Code grant types\nexport interface AuthenticationResolver {\n // Given an auth code, get the tokens from the auth server and store them. works in PKCE and non-PKCE environments\n // Note, if we choose later to implement other grants, this method would move into a subinterface specifically\n // for the authorization code grant type.\n // The return type is just for convenience and can be ignored, as the same data would be provided by getSessionData\n tokenExchange(code: string, state: string): Promise<OIDCTokenResponseBody>;\n\n // If the tokens have already been retrieved, return them\n getSessionData(): Promise<SessionData | null>;\n\n getEndSessionEndpoint(): Promise<string | null>;\n // If an existing session is found, validate it and return the session data\n validateExistingSession(autoRefresh?: boolean): Promise<SessionData>;\n\n // if there's a refresh token, use it to get new tokens\n // failing gracefully and deleting the bad refresh_token on failure\n tryRefreshTokens(sessionData: SessionData | null): Promise<SessionData>;\n}\n\nexport interface AuthenticationRefresher {\n refreshTokens: () => Promise<OIDCTokenResponseBody>;\n}\n\nexport class PopupError extends Error {\n constructor(message: string) {\n super(message);\n Object.setPrototypeOf(this, PopupError.prototype);\n }\n}\n"]}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/services/types.ts"],"names":[],"mappings":"AAqDA,MAAM,OAAO,UAAW,SAAQ,KAAK;IACnC,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,UAAU,CAAC,SAAS,CAAC,CAAC;IACpD,CAAC;CACF","sourcesContent":["import type { OIDCTokenResponseBody, SessionData } from \"@/types.js\";\n\n// A PKCEConsumer can get a code challenge to use in the login process\n// A PKCEProducer can also generate and store verifiers. The producer must also be a consumer in order to get the challenge from an existing flow\n// Examples:\n// - Client-only SPA: The SPA generates the code challenge and verifier, stores the verifier in state and returns the code challenge\n// Note - The SPA should use PKCEProducer instead to do both\n// - Client-side of a client/server app: The client calls the backend to get the challenge.\n// - Server-side: The server should generate a new stored verifier and derive the challenge from it.\nexport interface PKCEConsumer {\n // Retrieve a new PKCE challenge\n getCodeChallenge(): Promise<string>;\n}\n\n// All producers are consumers, because the producer can get its own challenge\nexport interface PKCEProducer extends PKCEConsumer {\n // Retrieve the PKCE challenge from the session if one exists\n getCodeVerifier(): Promise<string | null>;\n}\n\n// A service that can initiate requests to login or log out\nexport interface AuthenticationInitiator {\n // trigger a new login\n signIn(iframeRef: HTMLIFrameElement | null): Promise<URL>;\n\n // trigger a new logout\n signOut(idToken: string, iframeRef: HTMLIFrameElement | null): Promise<URL>;\n}\n\n// A service that can resolve an authentication request according to the OAuth Auth Code grant types\nexport interface AuthenticationResolver {\n // Given an auth code, get the tokens from the auth server and store them. works in PKCE and non-PKCE environments\n // Note, if we choose later to implement other grants, this method would move into a subinterface specifically\n // for the authorization code grant type.\n // The return type is just for convenience and can be ignored, as the same data would be provided by getSessionData\n tokenExchange(code: string, state: string): Promise<OIDCTokenResponseBody>;\n\n // If the tokens have already been retrieved, return them\n getSessionData(): Promise<SessionData | null>;\n\n getEndSessionEndpoint(): Promise<string | null>;\n // If an existing session is found, validate it and return the session data\n validateExistingSession(autoRefresh?: boolean): Promise<SessionData>;\n\n // if there's a refresh token, use it to get new tokens\n // failing gracefully and deleting the bad refresh_token on failure\n tryRefreshTokens(sessionData: SessionData | null): Promise<SessionData>;\n}\n\nexport interface AuthenticationRefresher {\n refreshTokens: () => Promise<OIDCTokenResponseBody | null>;\n}\n\nexport class PopupError extends Error {\n constructor(message: string) {\n super(message);\n Object.setPrototypeOf(this, PopupError.prototype);\n }\n}\n"]}
@@ -2,6 +2,7 @@ import React from "react";
2
2
  type CivicAuthIframeProps = {
3
3
  onLoad?: () => void;
4
4
  id: string;
5
+ isRedirecting?: boolean;
5
6
  };
6
7
  declare const CivicAuthIframe: React.ForwardRefExoticComponent<CivicAuthIframeProps & React.RefAttributes<HTMLIFrameElement>>;
7
8
  export type { CivicAuthIframeProps };
@@ -1 +1 @@
1
- {"version":3,"file":"CivicAuthIframe.d.ts","sourceRoot":"","sources":["../../../src/shared/components/CivicAuthIframe.tsx"],"names":[],"mappings":"AACA,OAAO,KAAqB,MAAM,OAAO,CAAC;AAM1C,KAAK,oBAAoB,GAAG;IAC1B,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,EAAE,EAAE,MAAM,CAAC;CACZ,CAAC;AAEF,QAAA,MAAM,eAAe,gGAyEpB,CAAC;AAIF,YAAY,EAAE,oBAAoB,EAAE,CAAC;AAErC,OAAO,EAAE,eAAe,EAAE,CAAC"}
1
+ {"version":3,"file":"CivicAuthIframe.d.ts","sourceRoot":"","sources":["../../../src/shared/components/CivicAuthIframe.tsx"],"names":[],"mappings":"AACA,OAAO,KAAqB,MAAM,OAAO,CAAC;AAM1C,KAAK,oBAAoB,GAAG;IAC1B,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,EAAE,EAAE,MAAM,CAAC;IACX,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB,CAAC;AAEF,QAAA,MAAM,eAAe,gGA6EpB,CAAC;AAIF,YAAY,EAAE,oBAAoB,EAAE,CAAC;AAErC,OAAO,EAAE,eAAe,EAAE,CAAC"}
@@ -5,7 +5,7 @@ import { IframeResizer } from "@civic/iframe-resizer";
5
5
  import SVGLoading from "./SVGLoading.js";
6
6
  import { useIframe } from "../hooks/useIframe.js";
7
7
  import { useIsClient } from "usehooks-ts";
8
- const CivicAuthIframe = forwardRef(({ onLoad, id }, ref) => {
8
+ const CivicAuthIframe = forwardRef(({ onLoad, id, isRedirecting }, ref) => {
9
9
  const [isLoaded, setIsLoaded] = React.useState(false);
10
10
  const { iframeMode, backgroundColor } = useIframe();
11
11
  const iframeRef = ref;
@@ -18,7 +18,7 @@ const CivicAuthIframe = forwardRef(({ onLoad, id }, ref) => {
18
18
  transition: "all 250ms ease",
19
19
  backgroundColor: isLoaded ? backgroundColor : "transparent",
20
20
  minHeight: iframeMode !== "embedded" ? "26px" : "auto",
21
- }, children: [!isLoaded ? (_jsx("div", { "data-testid": "iframe-shimmer-loader", style: {
21
+ }, children: [!isLoaded || isRedirecting ? (_jsx("div", { "data-testid": "iframe-shimmer-loader", style: {
22
22
  width: "100%",
23
23
  height: "26px",
24
24
  display: "flex",
@@ -33,7 +33,7 @@ const CivicAuthIframe = forwardRef(({ onLoad, id }, ref) => {
33
33
  }, children: iframeMode !== "embedded" && (_jsx(SVGLoading, { backgroundColor: backgroundColor })) })) : null, _jsx("div", { style: {
34
34
  opacity: isLoaded ? 1 : 0,
35
35
  transition: "opacity 250ms ease",
36
- }, children: _jsx(IframeResizer, { ref: iframeRef, id: id, "data-testid": "civic-auth-iframe-with-resizer", initialHeight: iframeMode !== "embedded" ? "26px" : "max-content", animate: true, animationDuration: 250, checkOrigin: false, style: {
36
+ }, children: !isRedirecting && (_jsx(IframeResizer, { ref: iframeRef, id: id, "data-testid": "civic-auth-iframe-with-resizer", initialHeight: iframeMode !== "embedded" ? "26px" : "max-content", animate: true, animationDuration: 250, checkOrigin: false, style: {
37
37
  width: "100%",
38
38
  border: "none",
39
39
  minWidth: "100%",
@@ -42,7 +42,7 @@ const CivicAuthIframe = forwardRef(({ onLoad, id }, ref) => {
42
42
  }, onLoad: () => {
43
43
  setIsLoaded(true);
44
44
  onLoad?.();
45
- }, allow: "camera; screen-wake-lock; publickey-credentials-get *; publickey-credentials-create *;", allowFullScreen: true }) })] }));
45
+ }, allow: "camera; screen-wake-lock; publickey-credentials-get *; publickey-credentials-create *;", allowFullScreen: true })) })] }));
46
46
  });
47
47
  CivicAuthIframe.displayName = "CivicAuthIframe";
48
48
  export { CivicAuthIframe };
@@ -1 +1 @@
1
- {"version":3,"file":"CivicAuthIframe.js","sourceRoot":"","sources":["../../../src/shared/components/CivicAuthIframe.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AACb,OAAO,KAAK,EAAE,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,UAAU,MAAM,iBAAiB,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAClD,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAO1C,MAAM,eAAe,GAAG,UAAU,CAChC,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,GAAG,EAAE,EAAE;IACtB,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IACtD,MAAM,EAAE,UAAU,EAAE,eAAe,EAAE,GAAG,SAAS,EAAE,CAAC;IACpD,MAAM,SAAS,GAAG,GAAG,CAAC;IACtB,MAAM,QAAQ,GAAG,WAAW,EAAE,CAAC;IAE/B,8GAA8G;IAC9G,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CACxB,eACE,KAAK,EAAE;YACL,QAAQ,EAAE,UAAU;YACpB,YAAY,EAAE,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;YACnC,QAAQ,EAAE,QAAQ;YAClB,UAAU,EAAE,gBAAgB;YAC5B,eAAe,EAAE,QAAQ,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,aAAa;YAC3D,SAAS,EAAE,UAAU,KAAK,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM;SACvD,aAEA,CAAC,QAAQ,CAAC,CAAC,CAAC,CACX,6BACc,uBAAuB,EACnC,KAAK,EAAE;oBACL,KAAK,EAAE,MAAM;oBACb,MAAM,EAAE,MAAM;oBACd,OAAO,EAAE,MAAM;oBACf,UAAU,EAAE,QAAQ;oBACpB,cAAc,EAAE,QAAQ;oBACxB,QAAQ,EAAE,UAAU;oBACpB,GAAG,EAAE,KAAK;oBACV,IAAI,EAAE,KAAK;oBACX,SAAS,EAAE,uBAAuB;oBAClC,YAAY,EAAE,MAAM;oBACpB,QAAQ,EAAE,QAAQ;iBACnB,YAEA,UAAU,KAAK,UAAU,IAAI,CAC5B,KAAC,UAAU,IAAC,eAAe,EAAE,eAAe,GAAI,CACjD,GACG,CACP,CAAC,CAAC,CAAC,IAAI,EACR,cACE,KAAK,EAAE;oBACL,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;oBACzB,UAAU,EAAE,oBAAoB;iBACjC,YAED,KAAC,aAAa,IACZ,GAAG,EAAE,SAAS,EACd,EAAE,EAAE,EAAE,iBACO,gCAAgC,EAC7C,aAAa,EAAE,UAAU,KAAK,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,aAAa,EACjE,OAAO,EAAE,IAAI,EACb,iBAAiB,EAAE,GAAG,EACtB,WAAW,EAAE,KAAK,EAClB,KAAK,EAAE;wBACL,KAAK,EAAE,MAAM;wBACb,MAAM,EAAE,MAAM;wBACd,QAAQ,EAAE,MAAM;wBAChB,eAAe,EAAE,QAAQ,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,aAAa;wBAC3D,aAAa,EAAE,MAAM;qBACtB,EACD,MAAM,EAAE,GAAG,EAAE;wBACX,WAAW,CAAC,IAAI,CAAC,CAAC;wBAClB,MAAM,EAAE,EAAE,CAAC;oBACb,CAAC,EACD,KAAK,EAAC,wFAAwF,EAC9F,eAAe,SACf,GACE,IACF,CACP,CAAC;AACJ,CAAC,CACF,CAAC;AAEF,eAAe,CAAC,WAAW,GAAG,iBAAiB,CAAC;AAIhD,OAAO,EAAE,eAAe,EAAE,CAAC","sourcesContent":["\"use client\";\nimport React, { forwardRef } from \"react\";\nimport { IframeResizer } from \"@civic/iframe-resizer\";\nimport SVGLoading from \"./SVGLoading.js\";\nimport { useIframe } from \"../hooks/useIframe.js\";\nimport { useIsClient } from \"usehooks-ts\";\n\ntype CivicAuthIframeProps = {\n onLoad?: () => void;\n id: string;\n};\n\nconst CivicAuthIframe = forwardRef<HTMLIFrameElement, CivicAuthIframeProps>(\n ({ onLoad, id }, ref) => {\n const [isLoaded, setIsLoaded] = React.useState(false);\n const { iframeMode, backgroundColor } = useIframe();\n const iframeRef = ref;\n const isClient = useIsClient();\n\n // don't render on the server as the appearance changes when the iframe is loaded from login-app post-messages\n return !isClient ? null : (\n <div\n style={{\n position: \"relative\",\n borderRadius: isLoaded ? \"26px\" : 0,\n overflow: \"hidden\",\n transition: \"all 250ms ease\",\n backgroundColor: isLoaded ? backgroundColor : \"transparent\",\n minHeight: iframeMode !== \"embedded\" ? \"26px\" : \"auto\",\n }}\n >\n {!isLoaded ? (\n <div\n data-testid=\"iframe-shimmer-loader\"\n style={{\n width: \"100%\",\n height: \"26px\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n position: \"absolute\",\n top: \"50%\",\n left: \"50%\",\n transform: \"translate(-50%, -50%)\",\n borderRadius: \"13px\",\n overflow: \"hidden\",\n }}\n >\n {iframeMode !== \"embedded\" && (\n <SVGLoading backgroundColor={backgroundColor} />\n )}\n </div>\n ) : null}\n <div\n style={{\n opacity: isLoaded ? 1 : 0,\n transition: \"opacity 250ms ease\",\n }}\n >\n <IframeResizer\n ref={iframeRef}\n id={id}\n data-testid={\"civic-auth-iframe-with-resizer\"}\n initialHeight={iframeMode !== \"embedded\" ? \"26px\" : \"max-content\"}\n animate={true}\n animationDuration={250}\n checkOrigin={false}\n style={{\n width: \"100%\",\n border: \"none\",\n minWidth: \"100%\",\n backgroundColor: isLoaded ? backgroundColor : \"transparent\",\n pointerEvents: \"auto\",\n }}\n onLoad={() => {\n setIsLoaded(true);\n onLoad?.();\n }}\n allow=\"camera; screen-wake-lock; publickey-credentials-get *; publickey-credentials-create *;\"\n allowFullScreen\n />\n </div>\n </div>\n );\n },\n);\n\nCivicAuthIframe.displayName = \"CivicAuthIframe\";\n\nexport type { CivicAuthIframeProps };\n\nexport { CivicAuthIframe };\n"]}
1
+ {"version":3,"file":"CivicAuthIframe.js","sourceRoot":"","sources":["../../../src/shared/components/CivicAuthIframe.tsx"],"names":[],"mappings":"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","sourcesContent":["\"use client\";\nimport React, { forwardRef } from \"react\";\nimport { IframeResizer } from \"@civic/iframe-resizer\";\nimport SVGLoading from \"./SVGLoading.js\";\nimport { useIframe } from \"../hooks/useIframe.js\";\nimport { useIsClient } from \"usehooks-ts\";\n\ntype CivicAuthIframeProps = {\n onLoad?: () => void;\n id: string;\n isRedirecting?: boolean; // Optional prop to indicate if the iframe is redirecting\n};\n\nconst CivicAuthIframe = forwardRef<HTMLIFrameElement, CivicAuthIframeProps>(\n ({ onLoad, id, isRedirecting }, ref) => {\n const [isLoaded, setIsLoaded] = React.useState(false);\n const { iframeMode, backgroundColor } = useIframe();\n const iframeRef = ref;\n const isClient = useIsClient();\n\n // don't render on the server as the appearance changes when the iframe is loaded from login-app post-messages\n return !isClient ? null : (\n <div\n style={{\n position: \"relative\",\n borderRadius: isLoaded ? \"26px\" : 0,\n overflow: \"hidden\",\n transition: \"all 250ms ease\",\n backgroundColor: isLoaded ? backgroundColor : \"transparent\",\n minHeight: iframeMode !== \"embedded\" ? \"26px\" : \"auto\",\n }}\n >\n {/* show the shimmer effect while loading or redirecting */}\n {!isLoaded || isRedirecting ? (\n <div\n data-testid=\"iframe-shimmer-loader\"\n style={{\n width: \"100%\",\n height: \"26px\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n position: \"absolute\",\n top: \"50%\",\n left: \"50%\",\n transform: \"translate(-50%, -50%)\",\n borderRadius: \"13px\",\n overflow: \"hidden\",\n }}\n >\n {iframeMode !== \"embedded\" && (\n <SVGLoading backgroundColor={backgroundColor} />\n )}\n </div>\n ) : null}\n <div\n style={{\n opacity: isLoaded ? 1 : 0,\n transition: \"opacity 250ms ease\",\n }}\n >\n {/* don't need to show the iframe at all if we are redirecting */}\n {!isRedirecting && (\n <IframeResizer\n ref={iframeRef}\n id={id}\n data-testid={\"civic-auth-iframe-with-resizer\"}\n initialHeight={iframeMode !== \"embedded\" ? \"26px\" : \"max-content\"}\n animate={true}\n animationDuration={250}\n checkOrigin={false}\n style={{\n width: \"100%\",\n border: \"none\",\n minWidth: \"100%\",\n backgroundColor: isLoaded ? backgroundColor : \"transparent\",\n pointerEvents: \"auto\",\n }}\n onLoad={() => {\n setIsLoaded(true);\n onLoad?.();\n }}\n allow=\"camera; screen-wake-lock; publickey-credentials-get *; publickey-credentials-create *;\"\n allowFullScreen\n />\n )}\n </div>\n </div>\n );\n },\n);\n\nCivicAuthIframe.displayName = \"CivicAuthIframe\";\n\nexport type { CivicAuthIframeProps };\n\nexport { CivicAuthIframe };\n"]}
@@ -3,10 +3,11 @@ type CivicAuthIframeContainerProps = {
3
3
  onClose?: () => void;
4
4
  closeOnRedirect?: boolean;
5
5
  };
6
- export declare function IframeChrome({ children, onClose, isFrameLoaded, }: {
6
+ export declare function IframeChrome({ children, onClose, isFrameLoaded, isRedirecting, }: {
7
7
  children: React.ReactNode;
8
8
  onClose?: () => void;
9
9
  isFrameLoaded: boolean;
10
+ isRedirecting?: boolean;
10
11
  }): import("@emotion/react/jsx-runtime").JSX.Element;
11
12
  declare const CivicAuthIframeContainer: ({ onClose, closeOnRedirect, }: CivicAuthIframeContainerProps) => import("@emotion/react/jsx-runtime").JSX.Element;
12
13
  export type { CivicAuthIframeContainerProps };
@@ -1 +1 @@
1
- {"version":3,"file":"CivicAuthIframeContainer.d.ts","sourceRoot":"","sources":["../../../src/shared/components/CivicAuthIframeContainer.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAmD,MAAM,OAAO,CAAC;AAcxE,KAAK,6BAA6B,GAAG;IACnC,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B,CAAC;AAeF,wBAAgB,YAAY,CAAC,EAC3B,QAAQ,EACR,OAAO,EACP,aAAa,GACd,EAAE;IACD,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,aAAa,EAAE,OAAO,CAAC;CACxB,oDA+DA;AAED,QAAA,MAAM,wBAAwB,kCAG3B,6BAA6B,qDAgK/B,CAAC;AAEF,YAAY,EAAE,6BAA6B,EAAE,CAAC;AAE9C,OAAO,EAAE,wBAAwB,EAAE,CAAC"}
1
+ {"version":3,"file":"CivicAuthIframeContainer.d.ts","sourceRoot":"","sources":["../../../src/shared/components/CivicAuthIframeContainer.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAmD,MAAM,OAAO,CAAC;AAcxE,KAAK,6BAA6B,GAAG;IACnC,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B,CAAC;AAeF,wBAAgB,YAAY,CAAC,EAC3B,QAAQ,EACR,OAAO,EACP,aAAa,EACb,aAAa,GACd,EAAE;IACD,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,aAAa,EAAE,OAAO,CAAC;IACvB,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB,oDA8DA;AAED,QAAA,MAAM,wBAAwB,kCAG3B,6BAA6B,qDA4K/B,CAAC;AAEF,YAAY,EAAE,6BAA6B,EAAE,CAAC;AAE9C,OAAO,EAAE,wBAAwB,EAAE,CAAC"}
@@ -13,7 +13,7 @@ import { useIsClient } from "usehooks-ts";
13
13
  function NoChrome({ children, }) {
14
14
  return (_jsx("div", { "data-testid": "civic-iframe-no-chrome", style: { position: "relative" }, children: children }));
15
15
  }
16
- export function IframeChrome({ children, onClose, isFrameLoaded, }) {
16
+ export function IframeChrome({ children, onClose, isFrameLoaded, isRedirecting, }) {
17
17
  const { setIframeAborted } = useIframe();
18
18
  return (_jsx("div", { style: {
19
19
  position: "absolute",
@@ -37,7 +37,7 @@ export function IframeChrome({ children, onClose, isFrameLoaded, }) {
37
37
  paddingRight: "0",
38
38
  paddingBottom: "0",
39
39
  width: "22rem",
40
- }, onClick: (e) => e.stopPropagation(), children: [isFrameLoaded && (_jsx("button", { style: {
40
+ }, onClick: (e) => e.stopPropagation(), children: [isFrameLoaded && !isRedirecting && (_jsx("button", { style: {
41
41
  position: "absolute",
42
42
  right: "0.6rem",
43
43
  top: "0.6rem",
@@ -60,6 +60,7 @@ const CivicAuthIframeContainer = ({ onClose, closeOnRedirect = true, }) => {
60
60
  const { doTokenExchange } = useClientTokenExchangeSession();
61
61
  const { iframeRef, iframeMode, backgroundColor, setIframeMounted } = useIframe();
62
62
  const [isIframeContentLoaded, setIsIframeContentLoaded] = useState(false);
63
+ const [isRedirecting, setIsRedirecting] = useState(false);
63
64
  useEffect(() => {
64
65
  setIframeMounted(true);
65
66
  }, [setIframeMounted]);
@@ -120,6 +121,12 @@ const CivicAuthIframeContainer = ({ onClose, closeOnRedirect = true, }) => {
120
121
  // handle Escape
121
122
  useEffect(() => {
122
123
  window.addEventListener("keydown", handleEscape);
124
+ window.addEventListener("locationWillChange", () => {
125
+ console.log("locationWillChange event triggered, setting isRedirecting to true");
126
+ // If the location will
127
+ // Show loading state
128
+ setIsRedirecting(true);
129
+ });
123
130
  return () => window.removeEventListener("keydown", handleEscape);
124
131
  });
125
132
  const handleIframeLoad = useCallback(() => {
@@ -164,7 +171,7 @@ const CivicAuthIframeContainer = ({ onClose, closeOnRedirect = true, }) => {
164
171
  }, children: _jsx(CivicAuthIframe, { ref: iframeRef, id: "civic-auth-iframe", onLoad: handleIframeLoad }) })] }) }));
165
172
  }
166
173
  // if the iframe is not embedded, we can just render the iframe directly
167
- return (_jsx(WrapperComponent, { onClose: onClose, isFrameLoaded: isIframeContentLoaded, children: _jsx(CivicAuthIframe, { ref: iframeRef, id: "civic-auth-iframe", onLoad: handleIframeLoad }) }));
174
+ return (_jsx(WrapperComponent, { onClose: onClose, isFrameLoaded: isIframeContentLoaded, isRedirecting: isRedirecting, children: _jsx(CivicAuthIframe, { ref: iframeRef, id: "civic-auth-iframe", onLoad: handleIframeLoad, isRedirecting: isRedirecting }) }));
168
175
  };
169
176
  export { CivicAuthIframeContainer };
170
177
  //# sourceMappingURL=CivicAuthIframeContainer.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"CivicAuthIframeContainer.js","sourceRoot":"","sources":["../../../src/shared/components/CivicAuthIframeContainer.tsx"],"names":[],"mappings":"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","sourcesContent":["\"use client\";\n\nimport React, { useCallback, useEffect, useRef, useState } from \"react\";\nimport { LoadingIcon } from \"@/shared/components/LoadingIcon.js\";\nimport { CloseIcon } from \"@/shared/components/CloseIcon.js\";\nimport { CivicAuthIframe } from \"@/shared/components/CivicAuthIframe.js\";\nimport { useIframe } from \"@/shared/hooks/index.js\";\nimport {\n TOKEN_EXCHANGE_SUCCESS_TEXT,\n TOKEN_EXCHANGE_TRIGGER_TEXT,\n} from \"@/constants.js\";\nimport { useCivicAuthConfig } from \"@/shared/hooks/index.js\";\nimport { useClientTokenExchangeSession } from \"@/shared/hooks/index.js\";\nimport { getIframeRef } from \"../lib/iframeUtils.js\";\nimport { useIsClient } from \"usehooks-ts\";\n\ntype CivicAuthIframeContainerProps = {\n onClose?: () => void;\n closeOnRedirect?: boolean;\n};\n\nfunction NoChrome({\n children,\n}: {\n children: React.ReactNode;\n onClose?: () => void;\n}) {\n return (\n <div data-testid=\"civic-iframe-no-chrome\" style={{ position: \"relative\" }}>\n {children}\n </div>\n );\n}\n\nexport function IframeChrome({\n children,\n onClose,\n isFrameLoaded,\n}: {\n children: React.ReactNode;\n onClose?: () => void;\n isFrameLoaded: boolean;\n}) {\n const { setIframeAborted } = useIframe();\n\n return (\n <div\n style={{\n position: \"absolute\",\n left: 0,\n top: 0,\n zIndex: 50,\n display: \"flex\",\n height: \"100vh\",\n width: \"100vw\",\n alignItems: \"center\",\n justifyContent: \"center\",\n backgroundColor: \"rgba(17, 24, 39, 0.5)\",\n backdropFilter: \"blur(4px)\",\n }}\n onClick={() => {\n setIframeAborted(true);\n onClose?.();\n }}\n >\n <div\n data-testid=\"iframe-chrome\"\n style={{\n position: \"relative\",\n overflow: \"hidden\",\n paddingLeft: \"0\",\n paddingRight: \"0\",\n paddingBottom: \"0\",\n width: \"22rem\",\n }}\n onClick={(e) => e.stopPropagation()}\n >\n {isFrameLoaded && (\n <button\n style={{\n position: \"absolute\",\n right: \"0.6rem\",\n top: \"0.6rem\",\n cursor: \"pointer\",\n alignItems: \"center\",\n justifyContent: \"center\",\n border: \"none\",\n backgroundColor: \"transparent\",\n padding: \"0.25rem\",\n color: \"#9ca3af\",\n zIndex: 100,\n }}\n onClick={() => {\n setIframeAborted(true);\n onClose?.();\n }}\n >\n <CloseIcon />\n </button>\n )}\n\n {children}\n </div>\n </div>\n );\n}\n\nconst CivicAuthIframeContainer = ({\n onClose,\n closeOnRedirect = true,\n}: CivicAuthIframeContainerProps) => {\n const config = useCivicAuthConfig();\n const [tokenExchangeUrl, setTokenExchangeUrl] = useState<string | null>(null);\n const { doTokenExchange } = useClientTokenExchangeSession();\n const { iframeRef, iframeMode, backgroundColor, setIframeMounted } =\n useIframe();\n const [isIframeContentLoaded, setIsIframeContentLoaded] = useState(false);\n\n useEffect(() => {\n setIframeMounted(true);\n }, [setIframeMounted]);\n\n useEffect(() => {\n if (tokenExchangeUrl) {\n doTokenExchange?.(tokenExchangeUrl);\n }\n }, [doTokenExchange, tokenExchangeUrl]);\n\n const processIframeUrl = useCallback(() => {\n if (!config) return;\n if (iframeRef && iframeRef.current) {\n const ref = getIframeRef(iframeRef.current)!;\n if (ref?.contentWindow) {\n try {\n const iframeUrl = ref.contentWindow.location.href;\n // we know that oauth has finished when the iframe redirects to our redirectUrl\n if (iframeUrl.startsWith(config.redirectUrl)) {\n const iframeBody = ref.contentWindow.document.body.innerHTML;\n\n // If we're doing a server token exchange, we need to call the server a second time\n // using a fetch so that we're on the same domain and cookies can be sent and read\n // The server will use the presence of the code_verifier cookie to determine whether to do a token exchange or not.\n // On the initial (3rd party) redirect from the auth server, the cookie won't be sent, so the server-side callback route will just render a blank page,\n // and we'll do the exchange request from here, which will include the cookies.\n if (iframeBody.includes(TOKEN_EXCHANGE_TRIGGER_TEXT)) {\n const params = new URL(iframeUrl).searchParams;\n const appUrl = globalThis.window?.location?.origin;\n fetch(\n `${config.redirectUrl}?${params.toString()}&appUrl=${appUrl}`,\n );\n } else {\n // if we're doing token-exchange in the client, we can just set the authResponseUrl\n // to be handled by the auth provider\n // iframeRef.current.setAttribute(\"src\", \"\");\n setTokenExchangeUrl(iframeUrl);\n }\n if (\n iframeBody.includes(TOKEN_EXCHANGE_SUCCESS_TEXT) &&\n config.loginSuccessUrl\n ) {\n globalThis.window.location.href = config.loginSuccessUrl;\n }\n\n if (closeOnRedirect) onClose?.();\n return true; // Successfully processed the URL\n }\n } catch {\n // ignore errors while waiting for redirect\n }\n }\n }\n return false; // Haven't processed the URL yet\n }, [closeOnRedirect, config, iframeRef, onClose]);\n\n const intervalId = useRef<NodeJS.Timeout>();\n\n const handleEscape = useCallback(\n (event: KeyboardEvent) => {\n if (event.key === \"Escape\") {\n onClose?.();\n }\n },\n [onClose],\n );\n\n // handle Escape\n useEffect(() => {\n window.addEventListener(\"keydown\", handleEscape);\n\n return () => window.removeEventListener(\"keydown\", handleEscape);\n });\n\n const handleIframeLoad = useCallback(() => {\n setIsIframeContentLoaded(true);\n\n const iframeHasUrl = processIframeUrl();\n if (iframeHasUrl && intervalId.current) {\n clearInterval(intervalId.current);\n }\n }, [processIframeUrl, intervalId]);\n\n const WrapperComponent = iframeMode === \"embedded\" ? NoChrome : IframeChrome;\n const isClient = useIsClient();\n // if the iframe is embedded, we need to handle the loading state differently\n if (iframeMode === \"embedded\") {\n return (\n <WrapperComponent onClose={onClose} isFrameLoaded={isIframeContentLoaded}>\n <div\n style={{\n minHeight: isIframeContentLoaded ? \"auto\" : \"225px\",\n backgroundColor: isClient ? backgroundColor : \"#8E949D\",\n borderRadius: \"26px\",\n position: \"relative\",\n transition: \"all 0.5s ease-in-out\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n overflow: \"hidden\",\n }}\n >\n {/* always load the loading spinner in the center of the iframe */}\n {!isIframeContentLoaded && (\n <div\n style={{\n position: \"absolute\",\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n }}\n >\n <LoadingIcon />\n </div>\n )}\n <div\n style={{\n width: \"100%\",\n minWidth: \"100%\",\n alignItems: \"center\",\n justifyContent: \"center\",\n borderRadius: \"26px\",\n overflow: \"hidden\",\n opacity: isIframeContentLoaded ? 1 : 0,\n transition: \"opacity 0.5s ease-in-out\",\n }}\n >\n <CivicAuthIframe\n ref={iframeRef}\n id={\"civic-auth-iframe\"}\n onLoad={handleIframeLoad}\n />\n </div>\n </div>\n </WrapperComponent>\n );\n }\n\n // if the iframe is not embedded, we can just render the iframe directly\n return (\n <WrapperComponent onClose={onClose} isFrameLoaded={isIframeContentLoaded}>\n <CivicAuthIframe\n ref={iframeRef}\n id={\"civic-auth-iframe\"}\n onLoad={handleIframeLoad}\n />\n </WrapperComponent>\n );\n};\n\nexport type { CivicAuthIframeContainerProps };\n\nexport { CivicAuthIframeContainer };\n"]}
1
+ {"version":3,"file":"CivicAuthIframeContainer.js","sourceRoot":"","sources":["../../../src/shared/components/CivicAuthIframeContainer.tsx"],"names":[],"mappings":"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","sourcesContent":["\"use client\";\n\nimport React, { useCallback, useEffect, useRef, useState } from \"react\";\nimport { LoadingIcon } from \"@/shared/components/LoadingIcon.js\";\nimport { CloseIcon } from \"@/shared/components/CloseIcon.js\";\nimport { CivicAuthIframe } from \"@/shared/components/CivicAuthIframe.js\";\nimport { useIframe } from \"@/shared/hooks/index.js\";\nimport {\n TOKEN_EXCHANGE_SUCCESS_TEXT,\n TOKEN_EXCHANGE_TRIGGER_TEXT,\n} from \"@/constants.js\";\nimport { useCivicAuthConfig } from \"@/shared/hooks/index.js\";\nimport { useClientTokenExchangeSession } from \"@/shared/hooks/index.js\";\nimport { getIframeRef } from \"../lib/iframeUtils.js\";\nimport { useIsClient } from \"usehooks-ts\";\n\ntype CivicAuthIframeContainerProps = {\n onClose?: () => void;\n closeOnRedirect?: boolean;\n};\n\nfunction NoChrome({\n children,\n}: {\n children: React.ReactNode;\n onClose?: () => void;\n}) {\n return (\n <div data-testid=\"civic-iframe-no-chrome\" style={{ position: \"relative\" }}>\n {children}\n </div>\n );\n}\n\nexport function IframeChrome({\n children,\n onClose,\n isFrameLoaded,\n isRedirecting,\n}: {\n children: React.ReactNode;\n onClose?: () => void;\n isFrameLoaded: boolean;\n isRedirecting?: boolean;\n}) {\n const { setIframeAborted } = useIframe();\n\n return (\n <div\n style={{\n position: \"absolute\",\n left: 0,\n top: 0,\n zIndex: 50,\n display: \"flex\",\n height: \"100vh\",\n width: \"100vw\",\n alignItems: \"center\",\n justifyContent: \"center\",\n backgroundColor: \"rgba(17, 24, 39, 0.5)\",\n backdropFilter: \"blur(4px)\",\n }}\n onClick={() => {\n setIframeAborted(true);\n onClose?.();\n }}\n >\n <div\n data-testid=\"iframe-chrome\"\n style={{\n position: \"relative\",\n overflow: \"hidden\",\n paddingLeft: \"0\",\n paddingRight: \"0\",\n paddingBottom: \"0\",\n width: \"22rem\",\n }}\n onClick={(e) => e.stopPropagation()}\n >\n {isFrameLoaded && !isRedirecting && (\n <button\n style={{\n position: \"absolute\",\n right: \"0.6rem\",\n top: \"0.6rem\",\n cursor: \"pointer\",\n alignItems: \"center\",\n justifyContent: \"center\",\n border: \"none\",\n backgroundColor: \"transparent\",\n padding: \"0.25rem\",\n color: \"#9ca3af\",\n zIndex: 100,\n }}\n onClick={() => {\n setIframeAborted(true);\n onClose?.();\n }}\n >\n <CloseIcon />\n </button>\n )}\n {children}\n </div>\n </div>\n );\n}\n\nconst CivicAuthIframeContainer = ({\n onClose,\n closeOnRedirect = true,\n}: CivicAuthIframeContainerProps) => {\n const config = useCivicAuthConfig();\n const [tokenExchangeUrl, setTokenExchangeUrl] = useState<string | null>(null);\n const { doTokenExchange } = useClientTokenExchangeSession();\n const { iframeRef, iframeMode, backgroundColor, setIframeMounted } =\n useIframe();\n const [isIframeContentLoaded, setIsIframeContentLoaded] = useState(false);\n const [isRedirecting, setIsRedirecting] = useState(false);\n useEffect(() => {\n setIframeMounted(true);\n }, [setIframeMounted]);\n\n useEffect(() => {\n if (tokenExchangeUrl) {\n doTokenExchange?.(tokenExchangeUrl);\n }\n }, [doTokenExchange, tokenExchangeUrl]);\n\n const processIframeUrl = useCallback(() => {\n if (!config) return;\n if (iframeRef && iframeRef.current) {\n const ref = getIframeRef(iframeRef.current)!;\n if (ref?.contentWindow) {\n try {\n const iframeUrl = ref.contentWindow.location.href;\n // we know that oauth has finished when the iframe redirects to our redirectUrl\n if (iframeUrl.startsWith(config.redirectUrl)) {\n const iframeBody = ref.contentWindow.document.body.innerHTML;\n\n // If we're doing a server token exchange, we need to call the server a second time\n // using a fetch so that we're on the same domain and cookies can be sent and read\n // The server will use the presence of the code_verifier cookie to determine whether to do a token exchange or not.\n // On the initial (3rd party) redirect from the auth server, the cookie won't be sent, so the server-side callback route will just render a blank page,\n // and we'll do the exchange request from here, which will include the cookies.\n if (iframeBody.includes(TOKEN_EXCHANGE_TRIGGER_TEXT)) {\n const params = new URL(iframeUrl).searchParams;\n const appUrl = globalThis.window?.location?.origin;\n fetch(\n `${config.redirectUrl}?${params.toString()}&appUrl=${appUrl}`,\n );\n } else {\n // if we're doing token-exchange in the client, we can just set the authResponseUrl\n // to be handled by the auth provider\n // iframeRef.current.setAttribute(\"src\", \"\");\n setTokenExchangeUrl(iframeUrl);\n }\n if (\n iframeBody.includes(TOKEN_EXCHANGE_SUCCESS_TEXT) &&\n config.loginSuccessUrl\n ) {\n globalThis.window.location.href = config.loginSuccessUrl;\n }\n\n if (closeOnRedirect) onClose?.();\n return true; // Successfully processed the URL\n }\n } catch {\n // ignore errors while waiting for redirect\n }\n }\n }\n return false; // Haven't processed the URL yet\n }, [closeOnRedirect, config, iframeRef, onClose]);\n\n const intervalId = useRef<NodeJS.Timeout>();\n\n const handleEscape = useCallback(\n (event: KeyboardEvent) => {\n if (event.key === \"Escape\") {\n onClose?.();\n }\n },\n [onClose],\n );\n\n // handle Escape\n useEffect(() => {\n window.addEventListener(\"keydown\", handleEscape);\n window.addEventListener(\"locationWillChange\", () => {\n console.log(\n \"locationWillChange event triggered, setting isRedirecting to true\",\n );\n // If the location will\n // Show loading state\n setIsRedirecting(true);\n });\n return () => window.removeEventListener(\"keydown\", handleEscape);\n });\n\n const handleIframeLoad = useCallback(() => {\n setIsIframeContentLoaded(true);\n\n const iframeHasUrl = processIframeUrl();\n if (iframeHasUrl && intervalId.current) {\n clearInterval(intervalId.current);\n }\n }, [processIframeUrl, intervalId]);\n\n const WrapperComponent = iframeMode === \"embedded\" ? NoChrome : IframeChrome;\n const isClient = useIsClient();\n // if the iframe is embedded, we need to handle the loading state differently\n if (iframeMode === \"embedded\") {\n return (\n <WrapperComponent onClose={onClose} isFrameLoaded={isIframeContentLoaded}>\n <div\n style={{\n minHeight: isIframeContentLoaded ? \"auto\" : \"225px\",\n backgroundColor: isClient ? backgroundColor : \"#8E949D\",\n borderRadius: \"26px\",\n position: \"relative\",\n transition: \"all 0.5s ease-in-out\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n overflow: \"hidden\",\n }}\n >\n {/* always load the loading spinner in the center of the iframe */}\n {!isIframeContentLoaded && (\n <div\n style={{\n position: \"absolute\",\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n }}\n >\n <LoadingIcon />\n </div>\n )}\n <div\n style={{\n width: \"100%\",\n minWidth: \"100%\",\n alignItems: \"center\",\n justifyContent: \"center\",\n borderRadius: \"26px\",\n overflow: \"hidden\",\n opacity: isIframeContentLoaded ? 1 : 0,\n transition: \"opacity 0.5s ease-in-out\",\n }}\n >\n <CivicAuthIframe\n ref={iframeRef}\n id={\"civic-auth-iframe\"}\n onLoad={handleIframeLoad}\n />\n </div>\n </div>\n </WrapperComponent>\n );\n }\n\n // if the iframe is not embedded, we can just render the iframe directly\n return (\n <WrapperComponent\n onClose={onClose}\n isFrameLoaded={isIframeContentLoaded}\n isRedirecting={isRedirecting}\n >\n <CivicAuthIframe\n ref={iframeRef}\n id={\"civic-auth-iframe\"}\n onLoad={handleIframeLoad}\n isRedirecting={isRedirecting} // Pass the isRedirecting state to the iframe\n />\n </WrapperComponent>\n );\n};\n\nexport type { CivicAuthIframeContainerProps };\n\nexport { CivicAuthIframeContainer };\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"IFrameAndLoading.d.ts","sourceRoot":"","sources":["../../../src/shared/components/IFrameAndLoading.tsx"],"names":[],"mappings":"AAWA,QAAA,MAAM,gBAAgB,mCAGnB;IACD,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,SAAS,EAAE,OAAO,CAAC;IACnB,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC9B,qDAuGA,CAAC;AACF,OAAO,EAAE,gBAAgB,EAAE,CAAC"}
1
+ {"version":3,"file":"IFrameAndLoading.d.ts","sourceRoot":"","sources":["../../../src/shared/components/IFrameAndLoading.tsx"],"names":[],"mappings":"AAWA,QAAA,MAAM,gBAAgB,mCAGnB;IACD,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,SAAS,EAAE,OAAO,CAAC;IACnB,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC9B,qDAwGA,CAAC;AACF,OAAO,EAAE,gBAAgB,EAAE,CAAC"}
@@ -58,7 +58,7 @@ const IFrameAndLoading = ({ error, showIframeOnLogout = false, }) => {
58
58
  setIframeShouldRender(renderIframe);
59
59
  }
60
60
  }, [authStatus, renderIframe, iframeIsVisible]);
61
- return (_jsxs(_Fragment, { children: [iframeShouldRender && (_jsx("div", { style: iframeIsVisible ? { display: "block" } : { display: "none" }, children: _jsx(CivicAuthIframeContainer, { onClose: () => setIframeIsVisible(false) }) })), _jsx("div", { style: showIframeOnLogout && logoutIframeIsVisible
61
+ return (_jsxs(_Fragment, { children: [iframeShouldRender && (_jsx("div", { id: "civic-auth-iframe-container", style: iframeIsVisible ? { display: "block" } : { display: "none" }, children: _jsx(CivicAuthIframeContainer, { onClose: () => setIframeIsVisible(false) }) })), _jsx("div", { style: showIframeOnLogout && logoutIframeIsVisible
62
62
  ? { display: "block" }
63
63
  : { display: "none" }, children: _jsx(CivicAuthLogoutIframeContainer, { isLoading: logoutIframeLoading }) }), error && (_jsx(BlockDisplay, { children: _jsxs("div", { children: ["Error: ", error?.message] }) })), showLoadingOverlay && !error && (_jsx(BlockDisplay, { children: _jsx(LoadingIcon, {}) }))] }));
64
64
  };
@@ -1 +1 @@
1
- {"version":3,"file":"IFrameAndLoading.js","sourceRoot":"","sources":["../../../src/shared/components/IFrameAndLoading.tsx"],"names":[],"mappings":"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","sourcesContent":["import React, { useEffect, useState } from \"react\";\nimport { useIframe } from \"../hooks/useIframe.js\";\nimport { useIsInIframe } from \"../hooks/useIsInIframe.js\";\nimport { CivicAuthIframeContainer } from \"./CivicAuthIframeContainer.js\";\nimport { BlockDisplay } from \"./BlockDisplay.js\";\nimport { LoadingIcon } from \"./LoadingIcon.js\";\nimport { CivicAuthLogoutIframeContainer } from \"./CivicAuthLogoutIframeContainer.js\";\nimport { useSession } from \"../hooks/useSession.js\";\nimport { useAuthStatus } from \"../providers/AuthStatusContext.js\";\nimport { AuthStatus } from \"@/types.js\";\n\nconst IFrameAndLoading = ({\n error,\n showIframeOnLogout = false,\n}: {\n error: Error | null;\n isLoading: boolean;\n showIframeOnLogout?: boolean;\n}) => {\n const isInIframe = useIsInIframe();\n const [logoutIframeLoading, setLogoutIframeLoading] = useState(true);\n const {\n renderIframe,\n iframeIsVisible,\n setIframeIsVisible,\n logoutIframeIsVisible,\n } = useIframe();\n const { authStatus } = useAuthStatus();\n const session = useSession();\n // we show a loading overlay to block the display for the user\n // as the page that loads within the iframe will be the actual customer\n // login page just after authenticatino, which shouldn't be shown to the user during login\n // there's a small period where we're resolving the session and the iframe is showing\n const showLoadingOverlay = isInIframe;\n\n useEffect(() => {\n const handleErrorMessage = (event: MessageEvent) => {\n const thisURL = new URL(window.location.href);\n if (\n !(\n event.origin.endsWith(\"civic.com\") || thisURL.hostname === \"localhost\"\n )\n ) {\n return;\n }\n\n // The login app has thrown an error, so we need to show the logout iframe\n if (\n event.data?.source === \"civicloginApp\" &&\n event.data?.type === \"auth_error\"\n ) {\n setLogoutIframeLoading(false);\n return;\n }\n\n setLogoutIframeLoading(true);\n };\n\n window.addEventListener(\"message\", handleErrorMessage);\n return () => window.removeEventListener(\"message\", handleErrorMessage);\n }, []);\n\n const [iframeShouldRender, setIframeShouldRender] = useState(renderIframe);\n\n useEffect(() => {\n // We can't remove the iframe from the DOM immediately on authentication,\n // because it needs a short window to render a special 'TOKEN_EXCHANGE_SUCCESS' message\n // which the parent needs to detect in order to redirect to the loginSuccessUrl if any.\n // So we wait 500ms to allow that to happen before removing the iframe.\n if (session.data?.authenticated) {\n setTimeout(() => {\n return setIframeShouldRender(false);\n }, 500);\n }\n }, [session.data?.authenticated]);\n\n /**\n * This useEffect resets the iframeShouldRender state when the authStatus changes. We need it\n * as the iframeShouldRender state is set to false when the user is authenticated, but it needs to be reset\n */\n useEffect(() => {\n if (authStatus !== AuthStatus.AUTHENTICATED) {\n setIframeShouldRender(renderIframe);\n }\n }, [authStatus, renderIframe, iframeIsVisible]);\n\n return (\n <>\n {/* when the user is authenticated we shouldn't render the iframe anymore\n so that we clear the session for the next time */}\n {iframeShouldRender && (\n <div\n style={iframeIsVisible ? { display: \"block\" } : { display: \"none\" }}\n >\n <CivicAuthIframeContainer onClose={() => setIframeIsVisible(false)} />\n </div>\n )}\n\n <div\n style={\n showIframeOnLogout && logoutIframeIsVisible\n ? { display: \"block\" }\n : { display: \"none\" }\n }\n >\n <CivicAuthLogoutIframeContainer isLoading={logoutIframeLoading} />\n </div>\n\n {error && (\n <BlockDisplay>\n <div>Error: {error?.message}</div>\n </BlockDisplay>\n )}\n\n {showLoadingOverlay && !error && (\n <BlockDisplay>\n <LoadingIcon />\n </BlockDisplay>\n )}\n </>\n );\n};\nexport { IFrameAndLoading };\n"]}
1
+ {"version":3,"file":"IFrameAndLoading.js","sourceRoot":"","sources":["../../../src/shared/components/IFrameAndLoading.tsx"],"names":[],"mappings":"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","sourcesContent":["import React, { useEffect, useState } from \"react\";\nimport { useIframe } from \"../hooks/useIframe.js\";\nimport { useIsInIframe } from \"../hooks/useIsInIframe.js\";\nimport { CivicAuthIframeContainer } from \"./CivicAuthIframeContainer.js\";\nimport { BlockDisplay } from \"./BlockDisplay.js\";\nimport { LoadingIcon } from \"./LoadingIcon.js\";\nimport { CivicAuthLogoutIframeContainer } from \"./CivicAuthLogoutIframeContainer.js\";\nimport { useSession } from \"../hooks/useSession.js\";\nimport { useAuthStatus } from \"../providers/AuthStatusContext.js\";\nimport { AuthStatus } from \"@/types.js\";\n\nconst IFrameAndLoading = ({\n error,\n showIframeOnLogout = false,\n}: {\n error: Error | null;\n isLoading: boolean;\n showIframeOnLogout?: boolean;\n}) => {\n const isInIframe = useIsInIframe();\n const [logoutIframeLoading, setLogoutIframeLoading] = useState(true);\n const {\n renderIframe,\n iframeIsVisible,\n setIframeIsVisible,\n logoutIframeIsVisible,\n } = useIframe();\n const { authStatus } = useAuthStatus();\n const session = useSession();\n // we show a loading overlay to block the display for the user\n // as the page that loads within the iframe will be the actual customer\n // login page just after authenticatino, which shouldn't be shown to the user during login\n // there's a small period where we're resolving the session and the iframe is showing\n const showLoadingOverlay = isInIframe;\n\n useEffect(() => {\n const handleErrorMessage = (event: MessageEvent) => {\n const thisURL = new URL(window.location.href);\n if (\n !(\n event.origin.endsWith(\"civic.com\") || thisURL.hostname === \"localhost\"\n )\n ) {\n return;\n }\n\n // The login app has thrown an error, so we need to show the logout iframe\n if (\n event.data?.source === \"civicloginApp\" &&\n event.data?.type === \"auth_error\"\n ) {\n setLogoutIframeLoading(false);\n return;\n }\n\n setLogoutIframeLoading(true);\n };\n\n window.addEventListener(\"message\", handleErrorMessage);\n return () => window.removeEventListener(\"message\", handleErrorMessage);\n }, []);\n\n const [iframeShouldRender, setIframeShouldRender] = useState(renderIframe);\n\n useEffect(() => {\n // We can't remove the iframe from the DOM immediately on authentication,\n // because it needs a short window to render a special 'TOKEN_EXCHANGE_SUCCESS' message\n // which the parent needs to detect in order to redirect to the loginSuccessUrl if any.\n // So we wait 500ms to allow that to happen before removing the iframe.\n if (session.data?.authenticated) {\n setTimeout(() => {\n return setIframeShouldRender(false);\n }, 500);\n }\n }, [session.data?.authenticated]);\n\n /**\n * This useEffect resets the iframeShouldRender state when the authStatus changes. We need it\n * as the iframeShouldRender state is set to false when the user is authenticated, but it needs to be reset\n */\n useEffect(() => {\n if (authStatus !== AuthStatus.AUTHENTICATED) {\n setIframeShouldRender(renderIframe);\n }\n }, [authStatus, renderIframe, iframeIsVisible]);\n\n return (\n <>\n {/* when the user is authenticated we shouldn't render the iframe anymore\n so that we clear the session for the next time */}\n {iframeShouldRender && (\n <div\n id=\"civic-auth-iframe-container\"\n style={iframeIsVisible ? { display: \"block\" } : { display: \"none\" }}\n >\n <CivicAuthIframeContainer onClose={() => setIframeIsVisible(false)} />\n </div>\n )}\n\n <div\n style={\n showIframeOnLogout && logoutIframeIsVisible\n ? { display: \"block\" }\n : { display: \"none\" }\n }\n >\n <CivicAuthLogoutIframeContainer isLoading={logoutIframeLoading} />\n </div>\n\n {error && (\n <BlockDisplay>\n <div>Error: {error?.message}</div>\n </BlockDisplay>\n )}\n\n {showLoadingOverlay && !error && (\n <BlockDisplay>\n <LoadingIcon />\n </BlockDisplay>\n )}\n </>\n );\n};\nexport { IFrameAndLoading };\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"useSignIn.d.ts","sourceRoot":"","sources":["../../../src/shared/hooks/useSignIn.ts"],"names":[],"mappings":"AAGA,OAAO,EACL,UAAU,EACV,KAAK,WAAW,EAEjB,MAAM,YAAY,CAAC;AAGpB,OAAO,EAAc,KAAK,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAQpE,KAAK,WAAW,GAAG;IACjB,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,UAAU,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACjC,WAAW,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAClC,WAAW,EAAE,WAAW,CAAC;CAC1B,CAAC;AAcF;;GAEG;AACH,QAAA,MAAM,SAAS,4DAC2C,WAAW;kBAgQ9B,OAAO,CAAC,IAAI,CAAC;;uBAxGR,OAAO,CAAC,IAAI,CAAC;;;CAoSxD,CAAC;AAEF,OAAO,EAAE,SAAS,EAAE,CAAC"}
1
+ {"version":3,"file":"useSignIn.d.ts","sourceRoot":"","sources":["../../../src/shared/hooks/useSignIn.ts"],"names":[],"mappings":"AAGA,OAAO,EACL,UAAU,EACV,KAAK,WAAW,EAEjB,MAAM,YAAY,CAAC;AAGpB,OAAO,EAAc,KAAK,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAQpE,KAAK,WAAW,GAAG;IACjB,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,UAAU,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACjC,WAAW,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAClC,WAAW,EAAE,WAAW,CAAC;CAC1B,CAAC;AAcF;;GAEG;AACH,QAAA,MAAM,SAAS,4DAC2C,WAAW;kBAkQ9B,OAAO,CAAC,IAAI,CAAC;;uBAxGR,OAAO,CAAC,IAAI,CAAC;;;CAsSxD,CAAC;AAEF,OAAO,EAAE,SAAS,EAAE,CAAC"}
@@ -73,7 +73,7 @@ const useSignIn = ({ pkceConsumer, preSignOut, postSignOut, displayMode } = {
73
73
  const authInitiator = useMemo(() => {
74
74
  if (!civicAuthConfig)
75
75
  return null;
76
- const { clientId, redirectUrl, logoutUrl, loginSuccessUrl, logoutRedirectUrl, nonce, oauthServer, endpoints, scopes, } = civicAuthConfig;
76
+ const { clientId, redirectUrl, logoutUrl, loginSuccessUrl, logoutRedirectUrl, nonce, oauthServer, endpoints, scopes, autoRedirect, } = civicAuthConfig;
77
77
  return new BrowserAuthenticationInitiator({
78
78
  pkceConsumer: pkceConsumer || new BrowserPublicClientPKCEProducer(),
79
79
  clientId,
@@ -87,6 +87,7 @@ const useSignIn = ({ pkceConsumer, preSignOut, postSignOut, displayMode } = {
87
87
  endpointOverrides: endpoints,
88
88
  nonce,
89
89
  framework: civicAuthConfig.framework,
90
+ autoRedirect,
90
91
  }, setDesignOption);
91
92
  }, [civicAuthConfig, displayMode, pkceConsumer, setDesignOption]);
92
93
  // Cleanup resources when component unmounts
@@ -206,10 +207,11 @@ const useSignIn = ({ pkceConsumer, preSignOut, postSignOut, displayMode } = {
206
207
  // Public sign-in method
207
208
  const signIn = useCallback(async () => {
208
209
  if (displayMode === "iframe") {
209
- setIframeIsVisible(true);
210
+ const result = await authInitiator?.handleUserInteractionBrowserCorsFailsSilently();
211
+ setIframeIsVisible(!result?.isRedirecting);
210
212
  }
211
213
  return startSignIn();
212
- }, [startSignIn, displayMode, setIframeIsVisible]);
214
+ }, [displayMode, startSignIn, setIframeIsVisible, authInitiator]);
213
215
  // Sign-out method
214
216
  const signOut = useCallback(async () => {
215
217
  const idToken = session?.idToken;