@civic/auth 0.7.0 → 0.7.1-beta.2

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 (149) hide show
  1. package/CHANGELOG.md +5 -0
  2. package/README.md +19 -1
  3. package/dist/nextjs/config.d.ts +1 -0
  4. package/dist/nextjs/config.d.ts.map +1 -1
  5. package/dist/nextjs/config.js +1 -1
  6. package/dist/nextjs/config.js.map +1 -1
  7. package/dist/nextjs/hooks/useRefresh.d.ts.map +1 -1
  8. package/dist/nextjs/hooks/useRefresh.js +7 -1
  9. package/dist/nextjs/hooks/useRefresh.js.map +1 -1
  10. package/dist/nextjs/routeHandler.d.ts.map +1 -1
  11. package/dist/nextjs/routeHandler.js +7 -0
  12. package/dist/nextjs/routeHandler.js.map +1 -1
  13. package/dist/reactjs/components/SignInButton.d.ts.map +1 -1
  14. package/dist/reactjs/components/SignInButton.js +8 -3
  15. package/dist/reactjs/components/SignInButton.js.map +1 -1
  16. package/dist/reactjs/components/SignOutButton.d.ts.map +1 -1
  17. package/dist/reactjs/components/SignOutButton.js +3 -1
  18. package/dist/reactjs/components/SignOutButton.js.map +1 -1
  19. package/dist/reactjs/components/UserButton.d.ts.map +1 -1
  20. package/dist/reactjs/components/UserButton.js +11 -6
  21. package/dist/reactjs/components/UserButton.js.map +1 -1
  22. package/dist/reactjs/components/index.d.ts +5 -5
  23. package/dist/reactjs/components/index.d.ts.map +1 -1
  24. package/dist/reactjs/components/index.js +5 -5
  25. package/dist/reactjs/components/index.js.map +1 -1
  26. package/dist/reactjs/core/GlobalAuthManager.d.ts +120 -0
  27. package/dist/reactjs/core/GlobalAuthManager.d.ts.map +1 -0
  28. package/dist/reactjs/core/GlobalAuthManager.js +296 -0
  29. package/dist/reactjs/core/GlobalAuthManager.js.map +1 -0
  30. package/dist/reactjs/hooks/index.d.ts +2 -2
  31. package/dist/reactjs/hooks/index.d.ts.map +1 -1
  32. package/dist/reactjs/hooks/index.js +2 -2
  33. package/dist/reactjs/hooks/index.js.map +1 -1
  34. package/dist/reactjs/hooks/useToken.d.ts +13 -0
  35. package/dist/reactjs/hooks/useToken.d.ts.map +1 -0
  36. package/dist/reactjs/hooks/useToken.js +48 -0
  37. package/dist/reactjs/hooks/useToken.js.map +1 -0
  38. package/dist/reactjs/hooks/useUser.d.ts +20 -2
  39. package/dist/reactjs/hooks/useUser.d.ts.map +1 -1
  40. package/dist/reactjs/hooks/useUser.js +163 -7
  41. package/dist/reactjs/hooks/useUser.js.map +1 -1
  42. package/dist/reactjs/index.d.ts +6 -2
  43. package/dist/reactjs/index.d.ts.map +1 -1
  44. package/dist/reactjs/index.js +7 -1
  45. package/dist/reactjs/index.js.map +1 -1
  46. package/dist/reactjs/providers/CivicAuthContext.d.ts +40 -0
  47. package/dist/reactjs/providers/CivicAuthContext.d.ts.map +1 -0
  48. package/dist/reactjs/providers/CivicAuthContext.js +303 -0
  49. package/dist/reactjs/providers/CivicAuthContext.js.map +1 -0
  50. package/dist/reactjs/providers/CivicAuthProvider.d.ts +20 -4
  51. package/dist/reactjs/providers/CivicAuthProvider.d.ts.map +1 -1
  52. package/dist/reactjs/providers/CivicAuthProvider.js +46 -25
  53. package/dist/reactjs/providers/CivicAuthProvider.js.map +1 -1
  54. package/dist/reactjs/providers/index.d.ts +2 -2
  55. package/dist/reactjs/providers/index.d.ts.map +1 -1
  56. package/dist/reactjs/providers/index.js +4 -2
  57. package/dist/reactjs/providers/index.js.map +1 -1
  58. package/dist/server/ServerAuthenticationResolver.d.ts.map +1 -1
  59. package/dist/server/ServerAuthenticationResolver.js +28 -11
  60. package/dist/server/ServerAuthenticationResolver.js.map +1 -1
  61. package/dist/server/config.d.ts +2 -0
  62. package/dist/server/config.d.ts.map +1 -1
  63. package/dist/server/config.js.map +1 -1
  64. package/dist/server/login.d.ts +2 -2
  65. package/dist/server/login.d.ts.map +1 -1
  66. package/dist/server/login.js +7 -2
  67. package/dist/server/login.js.map +1 -1
  68. package/dist/services/AuthenticationService.d.ts +1 -1
  69. package/dist/services/AuthenticationService.d.ts.map +1 -1
  70. package/dist/services/AuthenticationService.js +2 -2
  71. package/dist/services/AuthenticationService.js.map +1 -1
  72. package/dist/shared/components/CivicAuthIframe.js +1 -1
  73. package/dist/shared/components/CivicAuthIframe.js.map +1 -1
  74. package/dist/shared/components/CivicAuthIframeContainer.js +2 -2
  75. package/dist/shared/components/CivicAuthIframeContainer.js.map +1 -1
  76. package/dist/shared/hooks/index.d.ts +1 -2
  77. package/dist/shared/hooks/index.d.ts.map +1 -1
  78. package/dist/shared/hooks/index.js +1 -2
  79. package/dist/shared/hooks/index.js.map +1 -1
  80. package/dist/shared/hooks/useClientTokenExchangeSession.d.ts +7 -0
  81. package/dist/shared/hooks/useClientTokenExchangeSession.d.ts.map +1 -0
  82. package/dist/shared/hooks/useClientTokenExchangeSession.js +17 -0
  83. package/dist/shared/hooks/useClientTokenExchangeSession.js.map +1 -0
  84. package/dist/shared/lib/BrowserAuthenticationRefresher.js +3 -3
  85. package/dist/shared/lib/BrowserAuthenticationRefresher.js.map +1 -1
  86. package/dist/shared/lib/types.d.ts +1 -1
  87. package/dist/shared/lib/types.js +1 -1
  88. package/dist/shared/lib/types.js.map +1 -1
  89. package/dist/shared/lib/util.d.ts +5 -6
  90. package/dist/shared/lib/util.d.ts.map +1 -1
  91. package/dist/shared/lib/util.js +66 -75
  92. package/dist/shared/lib/util.js.map +1 -1
  93. package/dist/shared/providers/CivicAuthConfigContext.d.ts +2 -2
  94. package/dist/shared/providers/CivicAuthConfigContext.d.ts.map +1 -1
  95. package/dist/shared/providers/CivicAuthConfigContext.js +1 -1
  96. package/dist/shared/providers/CivicAuthConfigContext.js.map +1 -1
  97. package/dist/shared/providers/TokenProvider.d.ts.map +1 -1
  98. package/dist/shared/providers/TokenProvider.js +4 -7
  99. package/dist/shared/providers/TokenProvider.js.map +1 -1
  100. package/dist/shared/version.d.ts +1 -1
  101. package/dist/shared/version.d.ts.map +1 -1
  102. package/dist/shared/version.js +1 -1
  103. package/dist/shared/version.js.map +1 -1
  104. package/dist/types.d.ts +2 -2
  105. package/dist/types.js.map +1 -1
  106. package/dist/utils.d.ts +8 -0
  107. package/dist/utils.d.ts.map +1 -1
  108. package/dist/utils.js +23 -0
  109. package/dist/utils.js.map +1 -1
  110. package/dist/vanillajs/auth/CivicAuth.d.ts +12 -0
  111. package/dist/vanillajs/auth/CivicAuth.d.ts.map +1 -1
  112. package/dist/vanillajs/auth/CivicAuth.js +88 -5
  113. package/dist/vanillajs/auth/CivicAuth.js.map +1 -1
  114. package/dist/vanillajs/auth/SessionManager.d.ts +7 -1
  115. package/dist/vanillajs/auth/SessionManager.d.ts.map +1 -1
  116. package/dist/vanillajs/auth/SessionManager.js +34 -3
  117. package/dist/vanillajs/auth/SessionManager.js.map +1 -1
  118. package/dist/vanillajs/auth/TokenRefresher.js +2 -2
  119. package/dist/vanillajs/auth/TokenRefresher.js.map +1 -1
  120. package/dist/vanillajs/auth/config/ConfigProcessor.d.ts.map +1 -1
  121. package/dist/vanillajs/auth/config/ConfigProcessor.js +7 -2
  122. package/dist/vanillajs/auth/config/ConfigProcessor.js.map +1 -1
  123. package/dist/vanillajs/auth/types/AuthTypes.d.ts +3 -0
  124. package/dist/vanillajs/auth/types/AuthTypes.d.ts.map +1 -1
  125. package/dist/vanillajs/auth/types/AuthTypes.js.map +1 -1
  126. package/dist/vanillajs/index.d.ts +2 -0
  127. package/dist/vanillajs/index.d.ts.map +1 -1
  128. package/dist/vanillajs/index.js +2 -0
  129. package/dist/vanillajs/index.js.map +1 -1
  130. package/dist/vanillajs/types/index.d.ts +1 -1
  131. package/dist/vanillajs/types/index.d.ts.map +1 -1
  132. package/dist/vanillajs/types/index.js.map +1 -1
  133. package/dist/vanillajs/utils/auth-utils.d.ts +14 -0
  134. package/dist/vanillajs/utils/auth-utils.d.ts.map +1 -1
  135. package/dist/vanillajs/utils/auth-utils.js +39 -0
  136. package/dist/vanillajs/utils/auth-utils.js.map +1 -1
  137. package/package.json +3 -3
  138. package/dist/reactjs/hooks/useClientTokenExchangeSession.d.ts +0 -3
  139. package/dist/reactjs/hooks/useClientTokenExchangeSession.d.ts.map +0 -1
  140. package/dist/reactjs/hooks/useClientTokenExchangeSession.js +0 -13
  141. package/dist/reactjs/hooks/useClientTokenExchangeSession.js.map +0 -1
  142. package/dist/reactjs/providers/AuthProvider.d.ts +0 -10
  143. package/dist/reactjs/providers/AuthProvider.d.ts.map +0 -1
  144. package/dist/reactjs/providers/AuthProvider.js +0 -79
  145. package/dist/reactjs/providers/AuthProvider.js.map +0 -1
  146. package/dist/reactjs/providers/ClientTokenExchangeSessionProvider.d.ts +0 -17
  147. package/dist/reactjs/providers/ClientTokenExchangeSessionProvider.d.ts.map +0 -1
  148. package/dist/reactjs/providers/ClientTokenExchangeSessionProvider.js +0 -190
  149. package/dist/reactjs/providers/ClientTokenExchangeSessionProvider.js.map +0 -1
@@ -1,79 +0,0 @@
1
- "use client";
2
- import { jsx as _jsx, jsxs as _jsxs } from "@emotion/react/jsx-runtime";
3
- import React, { useEffect, useMemo, useState } from "react";
4
- import {} from "../../types.js";
5
- import { AuthContext } from "../../shared/providers/AuthContext.js";
6
- import { useSignIn } from "../../shared/hooks/useSignIn.js";
7
- import { useCivicAuthConfig } from "../../shared/hooks/useCivicAuthConfig.js";
8
- import { useSession } from "../../shared/hooks/useSession.js";
9
- import { IFrameAndLoading } from "../../shared/components/IFrameAndLoading.js";
10
- import { useIsInIframe } from "../../shared/hooks/useIsInIframe.js";
11
- import { useRefresh } from "../../shared/hooks/useRefresh.js";
12
- // Global this object setup
13
- let globalThisObject;
14
- if (typeof window !== "undefined") {
15
- globalThisObject = window;
16
- }
17
- else if (typeof global !== "undefined") {
18
- globalThisObject = global;
19
- }
20
- else {
21
- globalThisObject = Function("return this")();
22
- }
23
- globalThisObject.globalThis = globalThisObject;
24
- const AuthProvider = ({ children, onSignIn, onSignOut, pkceConsumer, displayMode = "iframe", }) => {
25
- const authConfig = useCivicAuthConfig();
26
- const { signIn, signOut, authStatus } = useSignIn({
27
- preSignOut: onSignOut,
28
- pkceConsumer,
29
- displayMode,
30
- });
31
- const [localSessionData, setLocalSessionData] = useState();
32
- const { data: session, error: tokenExchangeError, isLoading: tokenExchangeInProgress, } = useSession();
33
- useEffect(() => {
34
- if (session) {
35
- setLocalSessionData(session);
36
- if (session.authenticated) {
37
- onSignIn?.();
38
- }
39
- }
40
- }, [onSignIn, session]);
41
- const isAuthenticated = useMemo(() => {
42
- return !!localSessionData?.idToken;
43
- }, [localSessionData]);
44
- // The startSignIn functionality has been moved to ClientTokenExchangeSessionProvider
45
- // to prevent race conditions with validateExistingSession
46
- const isInIframe = useIsInIframe();
47
- // if the SDK loads in an iframe, we show the loading spinner until we know the auth state
48
- // but don't keep showing it indefinitely if it's just the isInIframe status
49
- const isLoading = tokenExchangeInProgress ||
50
- !authConfig ||
51
- (isInIframe && !localSessionData?.authenticated);
52
- const { error: refreshError } = useRefresh(session);
53
- useEffect(() => {
54
- if (refreshError) {
55
- console.error("Error refreshing token, signingOut...", refreshError);
56
- signOut();
57
- }
58
- }, [refreshError, signOut]);
59
- const value = useMemo(() => ({
60
- isLoading,
61
- error: tokenExchangeError,
62
- signOut,
63
- authStatus,
64
- isAuthenticated,
65
- signIn,
66
- displayMode,
67
- }), [
68
- isLoading,
69
- tokenExchangeError,
70
- signOut,
71
- authStatus,
72
- isAuthenticated,
73
- signIn,
74
- displayMode,
75
- ]);
76
- return (_jsxs(AuthContext.Provider, { value: value, children: [_jsx(IFrameAndLoading, { error: tokenExchangeError, isLoading: isLoading }), children] }));
77
- };
78
- export { AuthProvider };
79
- //# sourceMappingURL=AuthProvider.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"AuthProvider.js","sourceRoot":"","sources":["../../../src/reactjs/providers/AuthProvider.tsx"],"names":[],"mappings":"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","sourcesContent":["\"use client\";\n\nimport React, { useEffect, useMemo, useState } from \"react\";\nimport { type SessionData } from \"@/types.js\";\nimport { AuthContext } from \"@/shared/providers/AuthContext.js\";\nimport type { PKCEConsumer } from \"@/services/types.js\";\nimport { useSignIn } from \"@/shared/hooks/useSignIn.js\";\nimport { useCivicAuthConfig } from \"@/shared/hooks/useCivicAuthConfig.js\";\nimport { useSession } from \"@/shared/hooks/useSession.js\";\nimport { IFrameAndLoading } from \"@/shared/components/IFrameAndLoading.js\";\nimport type { AuthProviderProps } from \"@/shared/providers/types.js\";\nimport { useIsInIframe } from \"@/shared/hooks/useIsInIframe.js\";\nimport { useRefresh } from \"@/shared/hooks/useRefresh.js\";\n\n// Global this object setup\nlet globalThisObject;\nif (typeof window !== \"undefined\") {\n globalThisObject = window;\n} else if (typeof global !== \"undefined\") {\n globalThisObject = global;\n} else {\n globalThisObject = Function(\"return this\")();\n}\nglobalThisObject.globalThis = globalThisObject;\n\nexport type InternalAuthProviderProps = AuthProviderProps & {\n sessionData?: SessionData;\n pkceConsumer?: PKCEConsumer;\n};\n\nconst AuthProvider = ({\n children,\n onSignIn,\n onSignOut,\n pkceConsumer,\n displayMode = \"iframe\",\n}: InternalAuthProviderProps) => {\n const authConfig = useCivicAuthConfig();\n const { signIn, signOut, authStatus } = useSignIn({\n preSignOut: onSignOut,\n pkceConsumer,\n displayMode,\n });\n\n const [localSessionData, setLocalSessionData] =\n useState<SessionData | null>();\n\n const {\n data: session,\n error: tokenExchangeError,\n isLoading: tokenExchangeInProgress,\n } = useSession();\n\n useEffect(() => {\n if (session) {\n setLocalSessionData(session);\n if (session.authenticated) {\n onSignIn?.();\n }\n }\n }, [onSignIn, session]);\n\n const isAuthenticated = useMemo(() => {\n return !!localSessionData?.idToken;\n }, [localSessionData]);\n\n // The startSignIn functionality has been moved to ClientTokenExchangeSessionProvider\n // to prevent race conditions with validateExistingSession\n\n const isInIframe = useIsInIframe();\n // if the SDK loads in an iframe, we show the loading spinner until we know the auth state\n // but don't keep showing it indefinitely if it's just the isInIframe status\n const isLoading =\n tokenExchangeInProgress ||\n !authConfig ||\n (isInIframe && !localSessionData?.authenticated);\n\n const { error: refreshError } = useRefresh(session);\n\n useEffect(() => {\n if (refreshError) {\n console.error(\"Error refreshing token, signingOut...\", refreshError);\n signOut();\n }\n }, [refreshError, signOut]);\n\n const value = useMemo(\n () => ({\n isLoading,\n error: tokenExchangeError as Error | null,\n signOut,\n authStatus,\n isAuthenticated,\n signIn,\n displayMode,\n }),\n [\n isLoading,\n tokenExchangeError,\n signOut,\n authStatus,\n isAuthenticated,\n signIn,\n displayMode,\n ],\n );\n\n return (\n <AuthContext.Provider value={value}>\n <IFrameAndLoading error={tokenExchangeError} isLoading={isLoading} />\n {children}\n </AuthContext.Provider>\n );\n};\n\nexport { AuthProvider };\n"]}
@@ -1,17 +0,0 @@
1
- import type { ReactNode } from "react";
2
- import React from "react";
3
- import { type SessionData } from "../../types.js";
4
- export type ClientTokenExchangeSessionProviderOutput = {
5
- data: SessionData | null;
6
- error: Error | null;
7
- isLoading: boolean;
8
- doTokenExchange: null | ((url: string) => Promise<void>);
9
- };
10
- declare const ClientTokenExchangeSessionContext: React.Context<ClientTokenExchangeSessionProviderOutput>;
11
- type ClientTokenExchangeSessionContextType = {
12
- children: ReactNode;
13
- };
14
- declare const ClientTokenExchangeSessionProvider: ({ children, }: ClientTokenExchangeSessionContextType) => import("@emotion/react/jsx-runtime").JSX.Element;
15
- export type { ClientTokenExchangeSessionContextType as SessionContextType };
16
- export { ClientTokenExchangeSessionProvider, ClientTokenExchangeSessionContext, };
17
- //# sourceMappingURL=ClientTokenExchangeSessionProvider.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"ClientTokenExchangeSessionProvider.d.ts","sourceRoot":"","sources":["../../../src/reactjs/providers/ClientTokenExchangeSessionProvider.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,KAON,MAAM,OAAO,CAAC;AAIf,OAAO,EAAc,KAAK,WAAW,EAAE,MAAM,YAAY,CAAC;AAU1D,MAAM,MAAM,wCAAwC,GAAG;IACrD,IAAI,EAAE,WAAW,GAAG,IAAI,CAAC;IACzB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,SAAS,EAAE,OAAO,CAAC;IACnB,eAAe,EAAE,IAAI,GAAG,CAAC,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;CAC1D,CAAC;AAcF,QAAA,MAAM,iCAAiC,yDACkC,CAAC;AAE1E,KAAK,qCAAqC,GAAG;IAC3C,QAAQ,EAAE,SAAS,CAAC;CACrB,CAAC;AAEF,QAAA,MAAM,kCAAkC,kBAErC,qCAAqC,qDAyMvC,CAAC;AAEF,YAAY,EAAE,qCAAqC,IAAI,kBAAkB,EAAE,CAAC;AAC5E,OAAO,EACL,kCAAkC,EAClC,iCAAiC,GAClC,CAAC"}
@@ -1,190 +0,0 @@
1
- "use client";
2
- import { jsx as _jsx } from "@emotion/react/jsx-runtime";
3
- import React, { createContext, useCallback, useEffect, useMemo, useState, useRef, } from "react";
4
- import { BrowserAuthenticationService } from "../../services/AuthenticationService.js";
5
- import { isWindowInIframe } from "../../lib/windowUtil.js";
6
- import { AuthStatus } from "../../types.js";
7
- import { useCurrentUrl, useCivicAuthConfig, useSignIn, useIframe, } from "../../shared/hooks/index.js";
8
- import { LocalStorageAdapter } from "../../browser/storage.js";
9
- import { getIframeRef } from "../../shared/lib/iframeUtils.js";
10
- const defaultSession = {
11
- data: {
12
- authenticated: false,
13
- idToken: undefined,
14
- accessToken: undefined,
15
- displayMode: "iframe",
16
- },
17
- error: null,
18
- isLoading: false,
19
- doTokenExchange: null,
20
- };
21
- // Context for exposing session specifically to the TokenProvider
22
- const ClientTokenExchangeSessionContext = createContext(defaultSession);
23
- const ClientTokenExchangeSessionProvider = ({ children, }) => {
24
- const authConfig = useCivicAuthConfig();
25
- const [authService, setAuthService] = useState();
26
- const [error, setError] = useState(null);
27
- const [isLoading, setIsLoading] = useState(false);
28
- const [session, setSession] = useState(null);
29
- const { iframeRef } = useIframe();
30
- const currentUrl = useCurrentUrl();
31
- // Use the signIn hook with iframe displayMode
32
- const { startSignIn, authStatus } = useSignIn({
33
- displayMode: authConfig?.displayMode || "iframe",
34
- });
35
- // this state is used to track if the logout was triggered
36
- // so that we disable auto-start signIn which won't work until the auth-server
37
- // cookies have been fully cleared
38
- const [logoutTriggered, setLogoutTriggered] = useState(false);
39
- // Add a ref to track processed codes
40
- const processedCodes = useRef(new Set());
41
- useEffect(() => {
42
- if (!currentUrl || !authConfig)
43
- return;
44
- const { redirectUrl, clientId, oauthServer, scopes, logoutRedirectUrl, logoutUrl, } = authConfig;
45
- BrowserAuthenticationService.build({
46
- clientId,
47
- redirectUrl,
48
- logoutRedirectUrl,
49
- logoutUrl,
50
- oauthServer,
51
- scopes,
52
- displayMode: "iframe",
53
- }).then(setAuthService);
54
- }, [currentUrl, authConfig]);
55
- const isInIframe = isWindowInIframe(globalThis.window);
56
- const doTokenExchange = useCallback(async (inUrl) => {
57
- if (!authService)
58
- return;
59
- const url = new URL(inUrl);
60
- const code = url.searchParams.get("code");
61
- const state = url.searchParams.get("state");
62
- // Create a unique key for this code/state combination
63
- const exchangeKey = `${code}:${state}`;
64
- // If we've already processed this code, skip it
65
- if (processedCodes.current.has(exchangeKey)) {
66
- console.log("Token exchange already processed for this code");
67
- return;
68
- }
69
- if (code && state) {
70
- try {
71
- // Mark this code as processed before starting the exchange
72
- processedCodes.current.add(exchangeKey);
73
- setIsLoading(true);
74
- await authService.tokenExchange(code, state);
75
- // Explicitly emit completion event after successful token exchange
76
- LocalStorageAdapter.emitter.emit("civic-auth-signin-complete");
77
- }
78
- catch (error) {
79
- setError(error);
80
- setSession({ authenticated: false });
81
- // Emit error event if exchange fails
82
- LocalStorageAdapter.emitter.emit("civic-auth-signin-error", {
83
- error,
84
- });
85
- }
86
- setIsLoading(false);
87
- }
88
- }, [authService]);
89
- const onSignIn = useCallback(async () => {
90
- if (!authService)
91
- return;
92
- const session = await authService.getSessionData();
93
- setSession(session);
94
- }, [authService]);
95
- const onSignOut = useCallback(() => {
96
- setLogoutTriggered(true);
97
- setSession(null);
98
- }, []);
99
- useEffect(() => {
100
- LocalStorageAdapter.emitter.on("signIn", onSignIn);
101
- LocalStorageAdapter.emitter.on("signOut", onSignOut);
102
- return () => {
103
- LocalStorageAdapter.emitter.off("signIn", onSignIn);
104
- LocalStorageAdapter.emitter.off("signOut", onSignOut);
105
- };
106
- }, [onSignIn, onSignOut]);
107
- useEffect(() => {
108
- if (!authConfig) {
109
- setIsLoading(true);
110
- }
111
- else {
112
- setIsLoading(false);
113
- }
114
- }, [authConfig]);
115
- const [validationInProgress, setValidationInProgress] = useState(false);
116
- // Handle page load or refocus
117
- useEffect(() => {
118
- if (!authConfig?.redirectUrl ||
119
- !authService ||
120
- !currentUrl ||
121
- isInIframe ||
122
- isLoading) {
123
- return;
124
- }
125
- // We specifically don't want to abort token refresh operations
126
- // The AbortController is mainly used to prevent token exchange after unmount
127
- const abortController = new AbortController();
128
- const onPageLoad = async () => {
129
- if (validationInProgress ||
130
- authStatus === AuthStatus.SIGNING_OUT ||
131
- authStatus === AuthStatus.AUTHENTICATING)
132
- return;
133
- // if we have existing tokens, then validate them and return the session data
134
- // otherwise check if we have a code in the url and exchange it for tokens
135
- // if we have neither, initiate sign-in flow
136
- setValidationInProgress(true);
137
- try {
138
- const existingSessionData = await authService.validateExistingSession();
139
- if (existingSessionData.authenticated) {
140
- setSession(existingSessionData);
141
- return;
142
- }
143
- // If we have a code in the URL, attempt token exchange
144
- if (new URL(currentUrl).searchParams.get("code")) {
145
- await doTokenExchange(currentUrl);
146
- return;
147
- }
148
- // No valid session and no code in URL - initiate sign-in
149
- // But only if we're not in an iframe (to prevent infinite loops in embedded scenarios)
150
- if (!isInIframe && authConfig) {
151
- const ref = getIframeRef(iframeRef?.current, true);
152
- // if logout was triggered, we don't want to auto-start sign-in
153
- // as the auth-server cookies will not be cleared yet
154
- if (ref && authConfig?.displayMode === "iframe" && !logoutTriggered) {
155
- startSignIn();
156
- }
157
- }
158
- }
159
- catch (error) {
160
- console.error("Error during session validation:", error);
161
- }
162
- finally {
163
- setValidationInProgress(false);
164
- }
165
- };
166
- onPageLoad();
167
- return () => {
168
- abortController.abort();
169
- };
170
- // eslint-disable-next-line react-hooks/exhaustive-deps
171
- }, [
172
- authConfig,
173
- authService,
174
- currentUrl,
175
- doTokenExchange,
176
- isInIframe,
177
- isLoading,
178
- startSignIn,
179
- logoutTriggered,
180
- ]);
181
- const value = useMemo(() => ({
182
- data: session,
183
- error,
184
- isLoading,
185
- doTokenExchange: authService ? doTokenExchange : null,
186
- }), [session, error, isLoading, authService, doTokenExchange]);
187
- return (_jsx(ClientTokenExchangeSessionContext.Provider, { value: value, children: children }));
188
- };
189
- export { ClientTokenExchangeSessionProvider, ClientTokenExchangeSessionContext, };
190
- //# sourceMappingURL=ClientTokenExchangeSessionProvider.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"ClientTokenExchangeSessionProvider.js","sourceRoot":"","sources":["../../../src/reactjs/providers/ClientTokenExchangeSessionProvider.tsx"],"names":[],"mappings":"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","sourcesContent":["\"use client\";\nimport type { ReactNode } from \"react\";\nimport React, {\n createContext,\n useCallback,\n useEffect,\n useMemo,\n useState,\n useRef,\n} from \"react\";\nimport { BrowserAuthenticationService } from \"@/services/AuthenticationService.js\";\nimport type { AuthenticationResolver } from \"@/services/types.js\";\nimport { isWindowInIframe } from \"@/lib/windowUtil.js\";\nimport { AuthStatus, type SessionData } from \"@/types.js\";\nimport {\n useCurrentUrl,\n useCivicAuthConfig,\n useSignIn,\n useIframe,\n} from \"@/shared/hooks/index.js\";\nimport { LocalStorageAdapter } from \"@/browser/storage.js\";\nimport { getIframeRef } from \"@/shared/lib/iframeUtils.js\";\n\nexport type ClientTokenExchangeSessionProviderOutput = {\n data: SessionData | null;\n error: Error | null;\n isLoading: boolean;\n doTokenExchange: null | ((url: string) => Promise<void>);\n};\nconst defaultSession: ClientTokenExchangeSessionProviderOutput = {\n data: {\n authenticated: false,\n idToken: undefined,\n accessToken: undefined,\n displayMode: \"iframe\",\n },\n error: null,\n isLoading: false,\n doTokenExchange: null,\n};\n\n// Context for exposing session specifically to the TokenProvider\nconst ClientTokenExchangeSessionContext =\n createContext<ClientTokenExchangeSessionProviderOutput>(defaultSession);\n\ntype ClientTokenExchangeSessionContextType = {\n children: ReactNode;\n};\n\nconst ClientTokenExchangeSessionProvider = ({\n children,\n}: ClientTokenExchangeSessionContextType) => {\n const authConfig = useCivicAuthConfig();\n const [authService, setAuthService] = useState<AuthenticationResolver>();\n const [error, setError] = useState<Error | null>(null);\n const [isLoading, setIsLoading] = useState(false);\n const [session, setSession] = useState<SessionData | null>(null);\n const { iframeRef } = useIframe();\n const currentUrl = useCurrentUrl();\n // Use the signIn hook with iframe displayMode\n const { startSignIn, authStatus } = useSignIn({\n displayMode: authConfig?.displayMode || \"iframe\",\n });\n // this state is used to track if the logout was triggered\n // so that we disable auto-start signIn which won't work until the auth-server\n // cookies have been fully cleared\n const [logoutTriggered, setLogoutTriggered] = useState(false);\n\n // Add a ref to track processed codes\n const processedCodes = useRef(new Set<string>());\n\n useEffect(() => {\n if (!currentUrl || !authConfig) return;\n\n const {\n redirectUrl,\n clientId,\n oauthServer,\n scopes,\n logoutRedirectUrl,\n logoutUrl,\n } = authConfig;\n BrowserAuthenticationService.build({\n clientId,\n redirectUrl,\n logoutRedirectUrl,\n logoutUrl,\n oauthServer,\n scopes,\n displayMode: \"iframe\",\n }).then(setAuthService);\n }, [currentUrl, authConfig]);\n\n const isInIframe = isWindowInIframe(globalThis.window);\n\n const doTokenExchange = useCallback(\n async (inUrl: string) => {\n if (!authService) return;\n const url = new URL(inUrl);\n const code = url.searchParams.get(\"code\");\n const state = url.searchParams.get(\"state\");\n\n // Create a unique key for this code/state combination\n const exchangeKey = `${code}:${state}`;\n\n // If we've already processed this code, skip it\n if (processedCodes.current.has(exchangeKey)) {\n console.log(\"Token exchange already processed for this code\");\n return;\n }\n\n if (code && state) {\n try {\n // Mark this code as processed before starting the exchange\n processedCodes.current.add(exchangeKey);\n setIsLoading(true);\n await authService.tokenExchange(code, state);\n // Explicitly emit completion event after successful token exchange\n LocalStorageAdapter.emitter.emit(\"civic-auth-signin-complete\");\n } catch (error) {\n setError(error as Error);\n setSession({ authenticated: false });\n // Emit error event if exchange fails\n LocalStorageAdapter.emitter.emit(\"civic-auth-signin-error\", {\n error,\n });\n }\n setIsLoading(false);\n }\n },\n [authService],\n );\n\n const onSignIn = useCallback(async () => {\n if (!authService) return;\n const session = await authService.getSessionData();\n setSession(session);\n }, [authService]);\n\n const onSignOut = useCallback(() => {\n setLogoutTriggered(true);\n setSession(null);\n }, []);\n\n useEffect(() => {\n LocalStorageAdapter.emitter.on(\"signIn\", onSignIn);\n LocalStorageAdapter.emitter.on(\"signOut\", onSignOut);\n return () => {\n LocalStorageAdapter.emitter.off(\"signIn\", onSignIn);\n LocalStorageAdapter.emitter.off(\"signOut\", onSignOut);\n };\n }, [onSignIn, onSignOut]);\n\n useEffect(() => {\n if (!authConfig) {\n setIsLoading(true);\n } else {\n setIsLoading(false);\n }\n }, [authConfig]);\n\n const [validationInProgress, setValidationInProgress] = useState(false);\n // Handle page load or refocus\n useEffect(() => {\n if (\n !authConfig?.redirectUrl ||\n !authService ||\n !currentUrl ||\n isInIframe ||\n isLoading\n ) {\n return;\n }\n\n // We specifically don't want to abort token refresh operations\n // The AbortController is mainly used to prevent token exchange after unmount\n const abortController = new AbortController();\n\n const onPageLoad = async () => {\n if (\n validationInProgress ||\n authStatus === AuthStatus.SIGNING_OUT ||\n authStatus === AuthStatus.AUTHENTICATING\n )\n return;\n\n // if we have existing tokens, then validate them and return the session data\n // otherwise check if we have a code in the url and exchange it for tokens\n // if we have neither, initiate sign-in flow\n setValidationInProgress(true);\n\n try {\n const existingSessionData = await authService.validateExistingSession();\n\n if (existingSessionData.authenticated) {\n setSession(existingSessionData);\n return;\n }\n // If we have a code in the URL, attempt token exchange\n if (new URL(currentUrl).searchParams.get(\"code\")) {\n await doTokenExchange(currentUrl);\n return;\n }\n // No valid session and no code in URL - initiate sign-in\n // But only if we're not in an iframe (to prevent infinite loops in embedded scenarios)\n if (!isInIframe && authConfig) {\n const ref = getIframeRef(iframeRef?.current, true);\n // if logout was triggered, we don't want to auto-start sign-in\n // as the auth-server cookies will not be cleared yet\n if (ref && authConfig?.displayMode === \"iframe\" && !logoutTriggered) {\n startSignIn();\n }\n }\n } catch (error) {\n console.error(\"Error during session validation:\", error);\n } finally {\n setValidationInProgress(false);\n }\n };\n\n onPageLoad();\n\n return () => {\n abortController.abort();\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [\n authConfig,\n authService,\n currentUrl,\n doTokenExchange,\n isInIframe,\n isLoading,\n startSignIn,\n logoutTriggered,\n ]);\n\n const value = useMemo(\n () => ({\n data: session,\n error,\n isLoading,\n doTokenExchange: authService ? doTokenExchange : null,\n }),\n [session, error, isLoading, authService, doTokenExchange],\n );\n\n return (\n <ClientTokenExchangeSessionContext.Provider value={value}>\n {children}\n </ClientTokenExchangeSessionContext.Provider>\n );\n};\n\nexport type { ClientTokenExchangeSessionContextType as SessionContextType };\nexport {\n ClientTokenExchangeSessionProvider,\n ClientTokenExchangeSessionContext,\n};\n"]}