@civic/auth 0.7.0-beta.1 → 0.7.1-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +5 -0
- package/README.md +19 -1
- package/dist/nextjs/config.d.ts +1 -0
- package/dist/nextjs/config.d.ts.map +1 -1
- package/dist/nextjs/config.js +2 -4
- package/dist/nextjs/config.js.map +1 -1
- package/dist/nextjs/hooks/useRefresh.d.ts.map +1 -1
- package/dist/nextjs/hooks/useRefresh.js +7 -1
- package/dist/nextjs/hooks/useRefresh.js.map +1 -1
- package/dist/nextjs/hooks/useUserCookie.d.ts.map +1 -1
- package/dist/nextjs/hooks/useUserCookie.js.map +1 -1
- package/dist/nextjs/providers/NextAuthProvider.d.ts.map +1 -1
- package/dist/nextjs/providers/NextAuthProvider.js +4 -3
- package/dist/nextjs/providers/NextAuthProvider.js.map +1 -1
- package/dist/nextjs/routeHandler.d.ts.map +1 -1
- package/dist/nextjs/routeHandler.js +7 -0
- package/dist/nextjs/routeHandler.js.map +1 -1
- package/dist/reactjs/components/SignInButton.d.ts.map +1 -1
- package/dist/reactjs/components/SignInButton.js +8 -3
- package/dist/reactjs/components/SignInButton.js.map +1 -1
- package/dist/reactjs/components/SignOutButton.d.ts.map +1 -1
- package/dist/reactjs/components/SignOutButton.js +3 -1
- package/dist/reactjs/components/SignOutButton.js.map +1 -1
- package/dist/reactjs/components/UserButton.d.ts.map +1 -1
- package/dist/reactjs/components/UserButton.js +11 -6
- package/dist/reactjs/components/UserButton.js.map +1 -1
- package/dist/reactjs/components/index.d.ts +5 -5
- package/dist/reactjs/components/index.d.ts.map +1 -1
- package/dist/reactjs/components/index.js +5 -5
- package/dist/reactjs/components/index.js.map +1 -1
- package/dist/reactjs/core/GlobalAuthManager.d.ts +120 -0
- package/dist/reactjs/core/GlobalAuthManager.d.ts.map +1 -0
- package/dist/reactjs/core/GlobalAuthManager.js +296 -0
- package/dist/reactjs/core/GlobalAuthManager.js.map +1 -0
- package/dist/reactjs/hooks/index.d.ts +2 -2
- package/dist/reactjs/hooks/index.d.ts.map +1 -1
- package/dist/reactjs/hooks/index.js +2 -2
- package/dist/reactjs/hooks/index.js.map +1 -1
- package/dist/reactjs/hooks/useToken.d.ts +13 -0
- package/dist/reactjs/hooks/useToken.d.ts.map +1 -0
- package/dist/reactjs/hooks/useToken.js +48 -0
- package/dist/reactjs/hooks/useToken.js.map +1 -0
- package/dist/reactjs/hooks/useUser.d.ts +20 -2
- package/dist/reactjs/hooks/useUser.d.ts.map +1 -1
- package/dist/reactjs/hooks/useUser.js +163 -7
- package/dist/reactjs/hooks/useUser.js.map +1 -1
- package/dist/reactjs/index.d.ts +6 -2
- package/dist/reactjs/index.d.ts.map +1 -1
- package/dist/reactjs/index.js +7 -1
- package/dist/reactjs/index.js.map +1 -1
- package/dist/reactjs/providers/CivicAuthContext.d.ts +40 -0
- package/dist/reactjs/providers/CivicAuthContext.d.ts.map +1 -0
- package/dist/reactjs/providers/CivicAuthContext.js +303 -0
- package/dist/reactjs/providers/CivicAuthContext.js.map +1 -0
- package/dist/reactjs/providers/CivicAuthProvider.d.ts +20 -4
- package/dist/reactjs/providers/CivicAuthProvider.d.ts.map +1 -1
- package/dist/reactjs/providers/CivicAuthProvider.js +46 -24
- package/dist/reactjs/providers/CivicAuthProvider.js.map +1 -1
- package/dist/reactjs/providers/index.d.ts +2 -2
- package/dist/reactjs/providers/index.d.ts.map +1 -1
- package/dist/reactjs/providers/index.js +4 -2
- package/dist/reactjs/providers/index.js.map +1 -1
- package/dist/server/ServerAuthenticationResolver.d.ts.map +1 -1
- package/dist/server/ServerAuthenticationResolver.js +28 -11
- package/dist/server/ServerAuthenticationResolver.js.map +1 -1
- package/dist/server/config.d.ts +2 -0
- package/dist/server/config.d.ts.map +1 -1
- package/dist/server/config.js.map +1 -1
- package/dist/server/login.d.ts +2 -2
- package/dist/server/login.d.ts.map +1 -1
- package/dist/server/login.js +7 -2
- package/dist/server/login.js.map +1 -1
- package/dist/services/AuthenticationService.d.ts +1 -1
- package/dist/services/AuthenticationService.d.ts.map +1 -1
- package/dist/services/AuthenticationService.js +2 -2
- package/dist/services/AuthenticationService.js.map +1 -1
- package/dist/shared/components/CivicAuthIframe.js +1 -1
- package/dist/shared/components/CivicAuthIframe.js.map +1 -1
- package/dist/shared/components/CivicAuthIframeContainer.js +2 -2
- package/dist/shared/components/CivicAuthIframeContainer.js.map +1 -1
- package/dist/shared/hooks/index.d.ts +1 -2
- package/dist/shared/hooks/index.d.ts.map +1 -1
- package/dist/shared/hooks/index.js +1 -2
- package/dist/shared/hooks/index.js.map +1 -1
- package/dist/shared/hooks/useClientTokenExchangeSession.d.ts +7 -0
- package/dist/shared/hooks/useClientTokenExchangeSession.d.ts.map +1 -0
- package/dist/shared/hooks/useClientTokenExchangeSession.js +17 -0
- package/dist/shared/hooks/useClientTokenExchangeSession.js.map +1 -0
- package/dist/shared/hooks/useSignIn.d.ts +4 -9
- package/dist/shared/hooks/useSignIn.d.ts.map +1 -1
- package/dist/shared/hooks/useSignIn.js +42 -75
- package/dist/shared/hooks/useSignIn.js.map +1 -1
- package/dist/shared/lib/BrowserAuthenticationRefresher.js +3 -3
- package/dist/shared/lib/BrowserAuthenticationRefresher.js.map +1 -1
- package/dist/shared/lib/types.d.ts +1 -1
- package/dist/shared/lib/types.js +1 -1
- package/dist/shared/lib/types.js.map +1 -1
- package/dist/shared/lib/util.d.ts +5 -6
- package/dist/shared/lib/util.d.ts.map +1 -1
- package/dist/shared/lib/util.js +66 -75
- package/dist/shared/lib/util.js.map +1 -1
- package/dist/shared/providers/AuthContext.d.ts +2 -7
- package/dist/shared/providers/AuthContext.d.ts.map +1 -1
- package/dist/shared/providers/AuthContext.js.map +1 -1
- package/dist/shared/providers/CivicAuthConfigContext.d.ts +2 -2
- package/dist/shared/providers/CivicAuthConfigContext.d.ts.map +1 -1
- package/dist/shared/providers/CivicAuthConfigContext.js +1 -1
- package/dist/shared/providers/CivicAuthConfigContext.js.map +1 -1
- package/dist/shared/providers/TokenProvider.d.ts.map +1 -1
- package/dist/shared/providers/TokenProvider.js +4 -7
- package/dist/shared/providers/TokenProvider.js.map +1 -1
- package/dist/shared/providers/UserProvider.d.ts +1 -5
- package/dist/shared/providers/UserProvider.d.ts.map +1 -1
- package/dist/shared/providers/UserProvider.js.map +1 -1
- package/dist/shared/version.d.ts +1 -1
- package/dist/shared/version.js +1 -1
- package/dist/shared/version.js.map +1 -1
- package/dist/types.d.ts +2 -2
- package/dist/types.js.map +1 -1
- package/dist/utils.d.ts +8 -0
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +23 -0
- package/dist/utils.js.map +1 -1
- package/dist/vanillajs/auth/CivicAuth.d.ts +12 -0
- package/dist/vanillajs/auth/CivicAuth.d.ts.map +1 -1
- package/dist/vanillajs/auth/CivicAuth.js +88 -5
- package/dist/vanillajs/auth/CivicAuth.js.map +1 -1
- package/dist/vanillajs/auth/SessionManager.d.ts +7 -1
- package/dist/vanillajs/auth/SessionManager.d.ts.map +1 -1
- package/dist/vanillajs/auth/SessionManager.js +34 -3
- package/dist/vanillajs/auth/SessionManager.js.map +1 -1
- package/dist/vanillajs/auth/TokenRefresher.js +2 -2
- package/dist/vanillajs/auth/TokenRefresher.js.map +1 -1
- package/dist/vanillajs/auth/config/ConfigProcessor.d.ts.map +1 -1
- package/dist/vanillajs/auth/config/ConfigProcessor.js +7 -2
- package/dist/vanillajs/auth/config/ConfigProcessor.js.map +1 -1
- package/dist/vanillajs/auth/types/AuthTypes.d.ts +3 -0
- package/dist/vanillajs/auth/types/AuthTypes.d.ts.map +1 -1
- package/dist/vanillajs/auth/types/AuthTypes.js.map +1 -1
- package/dist/vanillajs/index.d.ts +2 -0
- package/dist/vanillajs/index.d.ts.map +1 -1
- package/dist/vanillajs/index.js +2 -0
- package/dist/vanillajs/index.js.map +1 -1
- package/dist/vanillajs/types/index.d.ts +1 -1
- package/dist/vanillajs/types/index.d.ts.map +1 -1
- package/dist/vanillajs/types/index.js.map +1 -1
- package/dist/vanillajs/utils/auth-utils.d.ts +14 -0
- package/dist/vanillajs/utils/auth-utils.d.ts.map +1 -1
- package/dist/vanillajs/utils/auth-utils.js +39 -0
- package/dist/vanillajs/utils/auth-utils.js.map +1 -1
- package/package.json +1 -1
- package/dist/reactjs/hooks/useClientTokenExchangeSession.d.ts +0 -3
- package/dist/reactjs/hooks/useClientTokenExchangeSession.d.ts.map +0 -1
- package/dist/reactjs/hooks/useClientTokenExchangeSession.js +0 -13
- package/dist/reactjs/hooks/useClientTokenExchangeSession.js.map +0 -1
- package/dist/reactjs/providers/AuthProvider.d.ts +0 -10
- package/dist/reactjs/providers/AuthProvider.d.ts.map +0 -1
- package/dist/reactjs/providers/AuthProvider.js +0 -79
- package/dist/reactjs/providers/AuthProvider.js.map +0 -1
- package/dist/reactjs/providers/ClientTokenExchangeSessionProvider.d.ts +0 -17
- package/dist/reactjs/providers/ClientTokenExchangeSessionProvider.d.ts.map +0 -1
- package/dist/reactjs/providers/ClientTokenExchangeSessionProvider.js +0 -190
- package/dist/reactjs/providers/ClientTokenExchangeSessionProvider.js.map +0 -1
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GlobalAuthManager - Singleton Authentication State Manager
|
|
3
|
+
*
|
|
4
|
+
* This module provides a global singleton that manages authentication state across a React application
|
|
5
|
+
* without requiring React Context providers or prop drilling. It acts as a centralized authentication
|
|
6
|
+
* manager that wraps the CivicAuth vanilla JavaScript library and provides a React-friendly interface.
|
|
7
|
+
*
|
|
8
|
+
* Key Features:
|
|
9
|
+
* - Singleton pattern ensures single auth instance across the entire app
|
|
10
|
+
* - Eliminates need for React Context providers and reduces bundle size
|
|
11
|
+
* - Manages authentication state (user, session, loading, errors)
|
|
12
|
+
* - Handles sign-in/sign-out flows with event-driven updates
|
|
13
|
+
* - Provides idempotent initialization (safe to call multiple times)
|
|
14
|
+
* - Supports multiple React hooks subscribing to the same auth state
|
|
15
|
+
* - Automatic session refresh and user data synchronization
|
|
16
|
+
*
|
|
17
|
+
* Usage:
|
|
18
|
+
* - Initialize once in your app with authentication configuration
|
|
19
|
+
* - Use React hooks (useCivicAuth, useAuth, etc.) to access auth state
|
|
20
|
+
* - The manager handles all underlying CivicAuth SDK interactions
|
|
21
|
+
* - State updates are automatically propagated to all subscribed components
|
|
22
|
+
*
|
|
23
|
+
* This design pattern is particularly useful for:
|
|
24
|
+
* - Large applications with many components needing auth state
|
|
25
|
+
* - Avoiding provider wrapper hell in React component trees
|
|
26
|
+
* - Ensuring consistent auth state across disconnected component hierarchies
|
|
27
|
+
* - Server-side rendering scenarios where providers might be problematic
|
|
28
|
+
*/
|
|
29
|
+
import { CivicAuth, AuthenticationEvents, AuthEvent, } from "../../vanillajs/index.js";
|
|
30
|
+
/**
|
|
31
|
+
* Global singleton that manages CivicAuth instance for React hooks
|
|
32
|
+
* Eliminates the need for React providers
|
|
33
|
+
*/
|
|
34
|
+
class GlobalAuthManager {
|
|
35
|
+
static instance = null;
|
|
36
|
+
auth = null;
|
|
37
|
+
events = null;
|
|
38
|
+
config = null;
|
|
39
|
+
listeners = new Set();
|
|
40
|
+
callbacks = {};
|
|
41
|
+
initializationPromise = null;
|
|
42
|
+
state = {
|
|
43
|
+
user: null,
|
|
44
|
+
session: null,
|
|
45
|
+
isLoading: false,
|
|
46
|
+
authStatus: "unauthenticated",
|
|
47
|
+
error: null,
|
|
48
|
+
displayMode: undefined,
|
|
49
|
+
};
|
|
50
|
+
constructor() {
|
|
51
|
+
// Private constructor for singleton
|
|
52
|
+
}
|
|
53
|
+
static getInstance() {
|
|
54
|
+
if (!GlobalAuthManager.instance) {
|
|
55
|
+
GlobalAuthManager.instance = new GlobalAuthManager();
|
|
56
|
+
}
|
|
57
|
+
return GlobalAuthManager.instance;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Initialize auth with config (idempotent)
|
|
61
|
+
* Returns the same promise for concurrent calls with same config
|
|
62
|
+
*/
|
|
63
|
+
async initialize(config) {
|
|
64
|
+
// If we have a promise and same config, return existing promise
|
|
65
|
+
if (this.initializationPromise &&
|
|
66
|
+
this.config &&
|
|
67
|
+
this.isSameConfig(config)) {
|
|
68
|
+
return this.initializationPromise;
|
|
69
|
+
}
|
|
70
|
+
// If different config, reset everything
|
|
71
|
+
if (this.config && !this.isSameConfig(config)) {
|
|
72
|
+
this.initializationPromise = null;
|
|
73
|
+
await this.cleanup();
|
|
74
|
+
}
|
|
75
|
+
// Create new initialization promise if needed
|
|
76
|
+
if (!this.initializationPromise) {
|
|
77
|
+
this.initializationPromise = this._doInitialize(config);
|
|
78
|
+
}
|
|
79
|
+
return this.initializationPromise;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Private method that does the actual initialization work
|
|
83
|
+
*/
|
|
84
|
+
async _doInitialize(config) {
|
|
85
|
+
this.config = config;
|
|
86
|
+
this.callbacks = {
|
|
87
|
+
onSignIn: config.onSignIn,
|
|
88
|
+
onSignOut: config.onSignOut,
|
|
89
|
+
};
|
|
90
|
+
this.setState({ isLoading: true, error: null });
|
|
91
|
+
try {
|
|
92
|
+
this.events = new AuthenticationEvents();
|
|
93
|
+
this.setupEventListeners();
|
|
94
|
+
const authConfig = {
|
|
95
|
+
clientId: config.clientId,
|
|
96
|
+
oauthServerBaseUrl: config.config?.oauthServer,
|
|
97
|
+
scopes: config.scopes || [
|
|
98
|
+
"openid",
|
|
99
|
+
"profile",
|
|
100
|
+
"email",
|
|
101
|
+
"offline_access",
|
|
102
|
+
],
|
|
103
|
+
displayMode: config.displayMode || "iframe",
|
|
104
|
+
iframeDisplayMode: config.iframeMode || "modal",
|
|
105
|
+
nonce: config.nonce,
|
|
106
|
+
authProcessTimeout: config.authProcessTimeout || 120000,
|
|
107
|
+
events: this.events,
|
|
108
|
+
logging: {
|
|
109
|
+
enabled: true,
|
|
110
|
+
level: "debug",
|
|
111
|
+
},
|
|
112
|
+
};
|
|
113
|
+
// Only add redirectUrl if provided
|
|
114
|
+
if (config.redirectUrl) {
|
|
115
|
+
authConfig.redirectUrl = config.redirectUrl;
|
|
116
|
+
}
|
|
117
|
+
// Only add logoutRedirectUrl if provided
|
|
118
|
+
if (config.logoutRedirectUrl) {
|
|
119
|
+
authConfig.logoutRedirectUrl = config.logoutRedirectUrl;
|
|
120
|
+
}
|
|
121
|
+
this.auth = await CivicAuth.create(authConfig);
|
|
122
|
+
// Check initial auth state
|
|
123
|
+
const isAuthenticated = await this.auth.isAuthenticated();
|
|
124
|
+
if (isAuthenticated) {
|
|
125
|
+
await this.refreshUserAndSession();
|
|
126
|
+
this.setState({ authStatus: "authenticated" });
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
this.setState({ authStatus: "unauthenticated" });
|
|
130
|
+
}
|
|
131
|
+
this.setState({
|
|
132
|
+
isLoading: false,
|
|
133
|
+
displayMode: config.displayMode,
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
catch (error) {
|
|
137
|
+
// Reset promise on error so it can be retried
|
|
138
|
+
this.initializationPromise = null;
|
|
139
|
+
const authError = error instanceof Error
|
|
140
|
+
? error
|
|
141
|
+
: new Error("Auth initialization failed");
|
|
142
|
+
this.setState({
|
|
143
|
+
error: authError,
|
|
144
|
+
authStatus: "error",
|
|
145
|
+
isLoading: false,
|
|
146
|
+
});
|
|
147
|
+
throw authError;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Subscribe to state changes
|
|
152
|
+
*/
|
|
153
|
+
subscribe(listener) {
|
|
154
|
+
this.listeners.add(listener);
|
|
155
|
+
return () => this.listeners.delete(listener);
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Get current state
|
|
159
|
+
*/
|
|
160
|
+
getState() {
|
|
161
|
+
return { ...this.state };
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Sign in
|
|
165
|
+
*/
|
|
166
|
+
async signIn() {
|
|
167
|
+
if (!this.auth) {
|
|
168
|
+
throw new Error("Auth not initialized");
|
|
169
|
+
}
|
|
170
|
+
const { user } = await this.auth.startAuthentication();
|
|
171
|
+
await this.refreshUserAndSession();
|
|
172
|
+
// Ensure we have a user to return
|
|
173
|
+
if (!user) {
|
|
174
|
+
throw new Error("Authentication succeeded but no user was returned");
|
|
175
|
+
}
|
|
176
|
+
// Return the user object
|
|
177
|
+
return { user };
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Sign out
|
|
181
|
+
*/
|
|
182
|
+
async signOut() {
|
|
183
|
+
if (!this.auth) {
|
|
184
|
+
throw new Error("Auth not initialized");
|
|
185
|
+
}
|
|
186
|
+
await this.auth.logout();
|
|
187
|
+
this.setState({
|
|
188
|
+
user: null,
|
|
189
|
+
session: null,
|
|
190
|
+
authStatus: "unauthenticated",
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Check if config is the same (for idempotent initialization)
|
|
195
|
+
*/
|
|
196
|
+
isSameConfig(newConfig) {
|
|
197
|
+
if (!this.config)
|
|
198
|
+
return false;
|
|
199
|
+
return (this.config.clientId === newConfig.clientId &&
|
|
200
|
+
this.config.config?.oauthServer === newConfig.config?.oauthServer &&
|
|
201
|
+
this.config.displayMode === newConfig.displayMode &&
|
|
202
|
+
this.config.nonce === newConfig.nonce);
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Setup event listeners for auth state changes
|
|
206
|
+
*/
|
|
207
|
+
setupEventListeners() {
|
|
208
|
+
if (!this.events)
|
|
209
|
+
return;
|
|
210
|
+
this.events.on(AuthEvent.SIGN_IN_STARTED, () => {
|
|
211
|
+
this.setState({
|
|
212
|
+
isLoading: true,
|
|
213
|
+
authStatus: "authenticating",
|
|
214
|
+
error: null,
|
|
215
|
+
});
|
|
216
|
+
});
|
|
217
|
+
this.events.on(AuthEvent.SIGN_IN_COMPLETE, () => {
|
|
218
|
+
this.setState({
|
|
219
|
+
isLoading: false,
|
|
220
|
+
authStatus: "authenticated",
|
|
221
|
+
error: null,
|
|
222
|
+
});
|
|
223
|
+
this.refreshUserAndSession();
|
|
224
|
+
this.callbacks.onSignIn?.();
|
|
225
|
+
});
|
|
226
|
+
this.events.on(AuthEvent.SIGN_IN_ERROR, (event) => {
|
|
227
|
+
const errorDetail = event?.detail || "Authentication failed";
|
|
228
|
+
const authError = new Error(errorDetail);
|
|
229
|
+
this.setState({
|
|
230
|
+
isLoading: false,
|
|
231
|
+
authStatus: "error",
|
|
232
|
+
error: authError,
|
|
233
|
+
});
|
|
234
|
+
this.callbacks.onSignIn?.(authError);
|
|
235
|
+
});
|
|
236
|
+
this.events.on(AuthEvent.SIGN_OUT_STARTED, () => {
|
|
237
|
+
this.setState({
|
|
238
|
+
isLoading: true,
|
|
239
|
+
authStatus: "signing_out",
|
|
240
|
+
error: null,
|
|
241
|
+
});
|
|
242
|
+
});
|
|
243
|
+
this.events.on(AuthEvent.SIGN_OUT_COMPLETE, () => {
|
|
244
|
+
this.setState({
|
|
245
|
+
isLoading: false,
|
|
246
|
+
authStatus: "unauthenticated",
|
|
247
|
+
user: null,
|
|
248
|
+
session: null,
|
|
249
|
+
error: null,
|
|
250
|
+
});
|
|
251
|
+
this.callbacks.onSignOut?.();
|
|
252
|
+
});
|
|
253
|
+
this.events.on(AuthEvent.USER_SESSION_CHANGED, () => {
|
|
254
|
+
this.refreshUserAndSession();
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* Refresh user and session data
|
|
259
|
+
*/
|
|
260
|
+
async refreshUserAndSession() {
|
|
261
|
+
if (!this.auth)
|
|
262
|
+
return;
|
|
263
|
+
try {
|
|
264
|
+
const [session, user] = await Promise.all([
|
|
265
|
+
this.auth.getCurrentSession(),
|
|
266
|
+
this.auth.getCurrentUser(),
|
|
267
|
+
]);
|
|
268
|
+
this.setState({ session, user });
|
|
269
|
+
}
|
|
270
|
+
catch (error) {
|
|
271
|
+
const sessionError = error instanceof Error ? error : new Error("Failed to get session");
|
|
272
|
+
this.setState({ error: sessionError });
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Update state and notify listeners
|
|
277
|
+
*/
|
|
278
|
+
setState(updates) {
|
|
279
|
+
this.state = { ...this.state, ...updates };
|
|
280
|
+
this.listeners.forEach((listener) => listener(this.state));
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* Cleanup auth instance
|
|
284
|
+
*/
|
|
285
|
+
async cleanup() {
|
|
286
|
+
if (this.auth) {
|
|
287
|
+
await this.auth.destroy();
|
|
288
|
+
this.auth = null;
|
|
289
|
+
}
|
|
290
|
+
this.events = null;
|
|
291
|
+
this.config = null;
|
|
292
|
+
this.initializationPromise = null; // Reset promise for clean re-initialization
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
export { GlobalAuthManager };
|
|
296
|
+
//# sourceMappingURL=GlobalAuthManager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GlobalAuthManager.js","sourceRoot":"","sources":["../../../src/reactjs/core/GlobalAuthManager.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * GlobalAuthManager - Singleton Authentication State Manager\n *\n * This module provides a global singleton that manages authentication state across a React application\n * without requiring React Context providers or prop drilling. It acts as a centralized authentication\n * manager that wraps the CivicAuth vanilla JavaScript library and provides a React-friendly interface.\n *\n * Key Features:\n * - Singleton pattern ensures single auth instance across the entire app\n * - Eliminates need for React Context providers and reduces bundle size\n * - Manages authentication state (user, session, loading, errors)\n * - Handles sign-in/sign-out flows with event-driven updates\n * - Provides idempotent initialization (safe to call multiple times)\n * - Supports multiple React hooks subscribing to the same auth state\n * - Automatic session refresh and user data synchronization\n *\n * Usage:\n * - Initialize once in your app with authentication configuration\n * - Use React hooks (useCivicAuth, useAuth, etc.) to access auth state\n * - The manager handles all underlying CivicAuth SDK interactions\n * - State updates are automatically propagated to all subscribed components\n *\n * This design pattern is particularly useful for:\n * - Large applications with many components needing auth state\n * - Avoiding provider wrapper hell in React component trees\n * - Ensuring consistent auth state across disconnected component hierarchies\n * - Server-side rendering scenarios where providers might be problematic\n */\n\nimport {\n CivicAuth,\n AuthenticationEvents,\n AuthEvent,\n} from \"../../vanillajs/index.js\";\nimport type {\n User,\n Session,\n CivicAuthClientConfig,\n} from \"../../vanillajs/index.js\";\nimport type { DisplayMode } from \"../../types.js\";\n\n// Event payload interfaces\ninterface SignInErrorEvent {\n detail: string;\n}\n\nexport interface GlobalAuthConfig {\n clientId: string;\n redirectUrl?: string;\n config?: {\n oauthServer?: string;\n };\n displayMode?: DisplayMode;\n iframeMode?: \"modal\" | \"embedded\";\n nonce?: string;\n logoutRedirectUrl?: string;\n scopes?: string[];\n authProcessTimeout?: number;\n onSignIn?: (error?: Error) => void;\n onSignOut?: () => void;\n}\n\nexport type AuthStatus =\n | \"authenticated\"\n | \"unauthenticated\"\n | \"authenticating\"\n | \"error\"\n | \"signing_out\";\n\nexport interface GlobalAuthState {\n user: User | null;\n session: Session | null;\n isLoading: boolean;\n authStatus: AuthStatus;\n error: Error | null;\n displayMode?: DisplayMode;\n}\n\ntype StateListener = (state: GlobalAuthState) => void;\n\n/**\n * Global singleton that manages CivicAuth instance for React hooks\n * Eliminates the need for React providers\n */\nclass GlobalAuthManager {\n private static instance: GlobalAuthManager | null = null;\n private auth: CivicAuth | null = null;\n private events: AuthenticationEvents | null = null;\n private config: GlobalAuthConfig | null = null;\n private listeners = new Set<StateListener>();\n private callbacks: {\n onSignIn?: (error?: Error) => void;\n onSignOut?: () => void;\n } = {};\n private initializationPromise: Promise<void> | null = null;\n\n private state: GlobalAuthState = {\n user: null,\n session: null,\n isLoading: false,\n authStatus: \"unauthenticated\",\n error: null,\n displayMode: undefined,\n };\n\n private constructor() {\n // Private constructor for singleton\n }\n\n static getInstance(): GlobalAuthManager {\n if (!GlobalAuthManager.instance) {\n GlobalAuthManager.instance = new GlobalAuthManager();\n }\n return GlobalAuthManager.instance;\n }\n\n /**\n * Initialize auth with config (idempotent)\n * Returns the same promise for concurrent calls with same config\n */\n async initialize(config: GlobalAuthConfig): Promise<void> {\n // If we have a promise and same config, return existing promise\n if (\n this.initializationPromise &&\n this.config &&\n this.isSameConfig(config)\n ) {\n return this.initializationPromise;\n }\n\n // If different config, reset everything\n if (this.config && !this.isSameConfig(config)) {\n this.initializationPromise = null;\n await this.cleanup();\n }\n\n // Create new initialization promise if needed\n if (!this.initializationPromise) {\n this.initializationPromise = this._doInitialize(config);\n }\n\n return this.initializationPromise;\n }\n\n /**\n * Private method that does the actual initialization work\n */\n private async _doInitialize(config: GlobalAuthConfig): Promise<void> {\n this.config = config;\n this.callbacks = {\n onSignIn: config.onSignIn,\n onSignOut: config.onSignOut,\n };\n this.setState({ isLoading: true, error: null });\n\n try {\n this.events = new AuthenticationEvents();\n this.setupEventListeners();\n\n const authConfig: CivicAuthClientConfig = {\n clientId: config.clientId,\n oauthServerBaseUrl: config.config?.oauthServer,\n scopes: config.scopes || [\n \"openid\",\n \"profile\",\n \"email\",\n \"offline_access\",\n ],\n displayMode: config.displayMode || \"iframe\",\n iframeDisplayMode: config.iframeMode || \"modal\",\n nonce: config.nonce,\n authProcessTimeout: config.authProcessTimeout || 120000,\n events: this.events,\n logging: {\n enabled: true,\n level: \"debug\" as const,\n },\n };\n\n // Only add redirectUrl if provided\n if (config.redirectUrl) {\n authConfig.redirectUrl = config.redirectUrl;\n }\n\n // Only add logoutRedirectUrl if provided\n if (config.logoutRedirectUrl) {\n authConfig.logoutRedirectUrl = config.logoutRedirectUrl;\n }\n\n this.auth = await CivicAuth.create(authConfig);\n\n // Check initial auth state\n const isAuthenticated = await this.auth.isAuthenticated();\n if (isAuthenticated) {\n await this.refreshUserAndSession();\n this.setState({ authStatus: \"authenticated\" });\n } else {\n this.setState({ authStatus: \"unauthenticated\" });\n }\n\n this.setState({\n isLoading: false,\n displayMode: config.displayMode,\n });\n } catch (error) {\n // Reset promise on error so it can be retried\n this.initializationPromise = null;\n\n const authError =\n error instanceof Error\n ? error\n : new Error(\"Auth initialization failed\");\n this.setState({\n error: authError,\n authStatus: \"error\",\n isLoading: false,\n });\n throw authError;\n }\n }\n\n /**\n * Subscribe to state changes\n */\n subscribe(listener: StateListener): () => void {\n this.listeners.add(listener);\n return () => this.listeners.delete(listener);\n }\n\n /**\n * Get current state\n */\n getState(): GlobalAuthState {\n return { ...this.state };\n }\n\n /**\n * Sign in\n */\n async signIn(): Promise<{ user: User }> {\n if (!this.auth) {\n throw new Error(\"Auth not initialized\");\n }\n\n const { user } = await this.auth.startAuthentication();\n await this.refreshUserAndSession();\n\n // Ensure we have a user to return\n if (!user) {\n throw new Error(\"Authentication succeeded but no user was returned\");\n }\n\n // Return the user object\n return { user };\n }\n\n /**\n * Sign out\n */\n async signOut(): Promise<void> {\n if (!this.auth) {\n throw new Error(\"Auth not initialized\");\n }\n\n await this.auth.logout();\n this.setState({\n user: null,\n session: null,\n authStatus: \"unauthenticated\",\n });\n }\n\n /**\n * Check if config is the same (for idempotent initialization)\n */\n private isSameConfig(newConfig: GlobalAuthConfig): boolean {\n if (!this.config) return false;\n return (\n this.config.clientId === newConfig.clientId &&\n this.config.config?.oauthServer === newConfig.config?.oauthServer &&\n this.config.displayMode === newConfig.displayMode &&\n this.config.nonce === newConfig.nonce\n );\n }\n\n /**\n * Setup event listeners for auth state changes\n */\n private setupEventListeners(): void {\n if (!this.events) return;\n\n this.events.on(AuthEvent.SIGN_IN_STARTED, () => {\n this.setState({\n isLoading: true,\n authStatus: \"authenticating\",\n error: null,\n });\n });\n\n this.events.on(AuthEvent.SIGN_IN_COMPLETE, () => {\n this.setState({\n isLoading: false,\n authStatus: \"authenticated\",\n error: null,\n });\n this.refreshUserAndSession();\n this.callbacks.onSignIn?.();\n });\n\n this.events.on(AuthEvent.SIGN_IN_ERROR, (event?: SignInErrorEvent) => {\n const errorDetail = event?.detail || \"Authentication failed\";\n const authError = new Error(errorDetail);\n this.setState({\n isLoading: false,\n authStatus: \"error\",\n error: authError,\n });\n this.callbacks.onSignIn?.(authError);\n });\n\n this.events.on(AuthEvent.SIGN_OUT_STARTED, () => {\n this.setState({\n isLoading: true,\n authStatus: \"signing_out\",\n error: null,\n });\n });\n\n this.events.on(AuthEvent.SIGN_OUT_COMPLETE, () => {\n this.setState({\n isLoading: false,\n authStatus: \"unauthenticated\",\n user: null,\n session: null,\n error: null,\n });\n this.callbacks.onSignOut?.();\n });\n\n this.events.on(AuthEvent.USER_SESSION_CHANGED, () => {\n this.refreshUserAndSession();\n });\n }\n\n /**\n * Refresh user and session data\n */\n private async refreshUserAndSession(): Promise<void> {\n if (!this.auth) return;\n\n try {\n const [session, user] = await Promise.all([\n this.auth.getCurrentSession(),\n this.auth.getCurrentUser(),\n ]);\n\n this.setState({ session, user });\n } catch (error) {\n const sessionError =\n error instanceof Error ? error : new Error(\"Failed to get session\");\n this.setState({ error: sessionError });\n }\n }\n\n /**\n * Update state and notify listeners\n */\n private setState(updates: Partial<GlobalAuthState>): void {\n this.state = { ...this.state, ...updates };\n this.listeners.forEach((listener) => listener(this.state));\n }\n\n /**\n * Cleanup auth instance\n */\n private async cleanup(): Promise<void> {\n if (this.auth) {\n await this.auth.destroy();\n this.auth = null;\n }\n this.events = null;\n this.config = null;\n this.initializationPromise = null; // Reset promise for clean re-initialization\n }\n}\n\nexport { GlobalAuthManager };\n"]}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { useUser } from "
|
|
2
|
-
export { useToken } from "
|
|
1
|
+
export { useUser, type UserContextType } from "./useUser.js";
|
|
2
|
+
export { useToken, type TokenContextType } from "./useToken.js";
|
|
3
3
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/reactjs/hooks/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/reactjs/hooks/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,cAAc,CAAC;AAC7D,OAAO,EAAE,QAAQ,EAAE,KAAK,gBAAgB,EAAE,MAAM,eAAe,CAAC"}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { useUser } from "
|
|
2
|
-
export { useToken } from "
|
|
1
|
+
export { useUser } from "./useUser.js";
|
|
2
|
+
export { useToken } from "./useToken.js";
|
|
3
3
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/reactjs/hooks/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/reactjs/hooks/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAwB,MAAM,cAAc,CAAC;AAC7D,OAAO,EAAE,QAAQ,EAAyB,MAAM,eAAe,CAAC","sourcesContent":["export { useUser, type UserContextType } from \"./useUser.js\";\nexport { useToken, type TokenContextType } from \"./useToken.js\";\n"]}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { ForwardedTokens } from "../../types.js";
|
|
2
|
+
import type { GlobalAuthConfig } from "../core/GlobalAuthManager.js";
|
|
3
|
+
export interface TokenContextType {
|
|
4
|
+
idToken?: string | null;
|
|
5
|
+
accessToken?: string | null;
|
|
6
|
+
refreshToken?: string | null;
|
|
7
|
+
forwardedTokens?: ForwardedTokens;
|
|
8
|
+
isLoading: boolean;
|
|
9
|
+
error: Error | null;
|
|
10
|
+
}
|
|
11
|
+
declare const useToken: (config?: GlobalAuthConfig) => TokenContextType;
|
|
12
|
+
export { useToken };
|
|
13
|
+
//# sourceMappingURL=useToken.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useToken.d.ts","sourceRoot":"","sources":["../../../src/reactjs/hooks/useToken.ts"],"names":[],"mappings":"AAiCA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACtD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAErE,MAAM,WAAW,gBAAgB;IAC/B,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,eAAe,CAAC,EAAE,eAAe,CAAC;IAClC,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;CACrB;AAED,QAAA,MAAM,QAAQ,YAAa,gBAAgB,KAAG,gBAuB7C,CAAC;AAEF,OAAO,EAAE,QAAQ,EAAE,CAAC"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useToken Hook
|
|
3
|
+
*
|
|
4
|
+
* A backwards-compatible token hook that extracts token-related properties from useUser.
|
|
5
|
+
* This hook provides access to authentication tokens without user profile information.
|
|
6
|
+
*
|
|
7
|
+
* Use this hook when you:
|
|
8
|
+
* - Only need access to tokens (idToken, accessToken, refreshToken, forwardedTokens)
|
|
9
|
+
* - Want to maintain backwards compatibility with existing code
|
|
10
|
+
* - Don't need user profile information
|
|
11
|
+
*
|
|
12
|
+
* This hook supports the same authentication patterns as useUser with automatic fallback:
|
|
13
|
+
* 1. Provider-based (legacy): Uses CivicAuthProvider or CivicNextAuthProvider
|
|
14
|
+
* 2. Provider-free (modern): Direct configuration via useToken(config)
|
|
15
|
+
*
|
|
16
|
+
* Usage Examples:
|
|
17
|
+
*
|
|
18
|
+
* // With provider (existing approach)
|
|
19
|
+
* <CivicAuthProvider clientId="..." config={{ oauthServer: "..." }}>
|
|
20
|
+
* const { accessToken, idToken, forwardedTokens } = useToken();
|
|
21
|
+
* </CivicAuthProvider>
|
|
22
|
+
*
|
|
23
|
+
* // Without provider (new approach) - direct configuration
|
|
24
|
+
* const { accessToken, idToken, refreshToken } = useToken({
|
|
25
|
+
* clientId: "your-client-id",
|
|
26
|
+
* config: { oauthServer: "https://auth.civic.com/oauth/" },
|
|
27
|
+
* displayMode: "iframe",
|
|
28
|
+
* scopes: ["openid", "profile", "email"]
|
|
29
|
+
* });
|
|
30
|
+
*/
|
|
31
|
+
"use client";
|
|
32
|
+
import { useMemo } from "react";
|
|
33
|
+
import { useUser } from "./useUser.js";
|
|
34
|
+
const useToken = (config) => {
|
|
35
|
+
// Leverage the existing useUser hook which handles all the fallback logic
|
|
36
|
+
const { idToken, accessToken, refreshToken, forwardedTokens, isLoading, error, } = useUser(config);
|
|
37
|
+
// Return only token-related properties for backwards compatibility
|
|
38
|
+
return useMemo(() => ({
|
|
39
|
+
idToken,
|
|
40
|
+
accessToken,
|
|
41
|
+
refreshToken,
|
|
42
|
+
forwardedTokens,
|
|
43
|
+
isLoading,
|
|
44
|
+
error,
|
|
45
|
+
}), [idToken, accessToken, refreshToken, forwardedTokens, isLoading, error]);
|
|
46
|
+
};
|
|
47
|
+
export { useToken };
|
|
48
|
+
//# sourceMappingURL=useToken.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useToken.js","sourceRoot":"","sources":["../../../src/reactjs/hooks/useToken.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,YAAY,CAAC;AACb,OAAO,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AAChC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAavC,MAAM,QAAQ,GAAG,CAAC,MAAyB,EAAoB,EAAE;IAC/D,0EAA0E;IAC1E,MAAM,EACJ,OAAO,EACP,WAAW,EACX,YAAY,EACZ,eAAe,EACf,SAAS,EACT,KAAK,GACN,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAEpB,mEAAmE;IACnE,OAAO,OAAO,CACZ,GAAG,EAAE,CAAC,CAAC;QACL,OAAO;QACP,WAAW;QACX,YAAY;QACZ,eAAe;QACf,SAAS;QACT,KAAK;KACN,CAAC,EACF,CAAC,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,eAAe,EAAE,SAAS,EAAE,KAAK,CAAC,CACxE,CAAC;AACJ,CAAC,CAAC;AAEF,OAAO,EAAE,QAAQ,EAAE,CAAC","sourcesContent":["/**\n * useToken Hook\n *\n * A backwards-compatible token hook that extracts token-related properties from useUser.\n * This hook provides access to authentication tokens without user profile information.\n *\n * Use this hook when you:\n * - Only need access to tokens (idToken, accessToken, refreshToken, forwardedTokens)\n * - Want to maintain backwards compatibility with existing code\n * - Don't need user profile information\n *\n * This hook supports the same authentication patterns as useUser with automatic fallback:\n * 1. Provider-based (legacy): Uses CivicAuthProvider or CivicNextAuthProvider\n * 2. Provider-free (modern): Direct configuration via useToken(config)\n *\n * Usage Examples:\n *\n * // With provider (existing approach)\n * <CivicAuthProvider clientId=\"...\" config={{ oauthServer: \"...\" }}>\n * const { accessToken, idToken, forwardedTokens } = useToken();\n * </CivicAuthProvider>\n *\n * // Without provider (new approach) - direct configuration\n * const { accessToken, idToken, refreshToken } = useToken({\n * clientId: \"your-client-id\",\n * config: { oauthServer: \"https://auth.civic.com/oauth/\" },\n * displayMode: \"iframe\",\n * scopes: [\"openid\", \"profile\", \"email\"]\n * });\n */\n\"use client\";\nimport { useMemo } from \"react\";\nimport { useUser } from \"./useUser.js\";\nimport type { ForwardedTokens } from \"../../types.js\";\nimport type { GlobalAuthConfig } from \"../core/GlobalAuthManager.js\";\n\nexport interface TokenContextType {\n idToken?: string | null;\n accessToken?: string | null;\n refreshToken?: string | null;\n forwardedTokens?: ForwardedTokens;\n isLoading: boolean;\n error: Error | null;\n}\n\nconst useToken = (config?: GlobalAuthConfig): TokenContextType => {\n // Leverage the existing useUser hook which handles all the fallback logic\n const {\n idToken,\n accessToken,\n refreshToken,\n forwardedTokens,\n isLoading,\n error,\n } = useUser(config);\n\n // Return only token-related properties for backwards compatibility\n return useMemo(\n () => ({\n idToken,\n accessToken,\n refreshToken,\n forwardedTokens,\n isLoading,\n error,\n }),\n [idToken, accessToken, refreshToken, forwardedTokens, isLoading, error],\n );\n};\n\nexport { useToken };\n"]}
|
|
@@ -1,4 +1,22 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import type { User, ForwardedTokens } from "../../types.js";
|
|
2
|
+
import type { AuthStatus } from "../../types.js";
|
|
3
|
+
import type { DisplayMode } from "../../types.js";
|
|
4
|
+
import { type GlobalAuthConfig } from "../core/GlobalAuthManager.js";
|
|
5
|
+
export interface UserContextType<T extends Record<string, unknown> = Record<string, never>> {
|
|
6
|
+
user: User<T> | null;
|
|
7
|
+
idToken?: string | null;
|
|
8
|
+
accessToken?: string | null;
|
|
9
|
+
refreshToken?: string | null;
|
|
10
|
+
forwardedTokens?: ForwardedTokens;
|
|
11
|
+
isLoading: boolean;
|
|
12
|
+
authStatus: AuthStatus;
|
|
13
|
+
error: Error | null;
|
|
14
|
+
signIn: () => Promise<{
|
|
15
|
+
user: User<T>;
|
|
16
|
+
}>;
|
|
17
|
+
signOut: () => Promise<void>;
|
|
18
|
+
displayMode?: DisplayMode;
|
|
19
|
+
}
|
|
20
|
+
declare const useUser: <T extends Record<string, unknown> = Record<string, never>>(config?: GlobalAuthConfig) => UserContextType<T>;
|
|
3
21
|
export { useUser };
|
|
4
22
|
//# sourceMappingURL=useUser.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useUser.d.ts","sourceRoot":"","sources":["../../../src/reactjs/hooks/useUser.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"useUser.d.ts","sourceRoot":"","sources":["../../../src/reactjs/hooks/useUser.ts"],"names":[],"mappings":"AAyCA,OAAO,KAAK,EAAE,IAAI,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAC5D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAEL,KAAK,gBAAgB,EAEtB,MAAM,8BAA8B,CAAC;AAGtC,MAAM,WAAW,eAAe,CAC9B,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC;IAEzD,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,eAAe,CAAC,EAAE,eAAe,CAAC;IAClC,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,EAAE,UAAU,CAAC;IACvB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,MAAM,EAAE,MAAM,OAAO,CAAC;QAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,CAAA;KAAE,CAAC,CAAC;IACzC,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7B,WAAW,CAAC,EAAE,WAAW,CAAC;CAC3B;AAED,QAAA,MAAM,OAAO,GAAI,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,mCACvC,gBAAgB,KACxB,eAAe,CAAC,CAAC,CA2InB,CAAC;AAEF,OAAO,EAAE,OAAO,EAAE,CAAC"}
|
|
@@ -1,12 +1,168 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useUser Hook
|
|
3
|
+
*
|
|
4
|
+
* A comprehensive user session hook that provides full user data including profile information,
|
|
5
|
+
* authentication tokens, and authentication state. Supports generic typing for custom user data.
|
|
6
|
+
*
|
|
7
|
+
* Use this hook when you:
|
|
8
|
+
* - Need access to user profile information (user object)
|
|
9
|
+
* - Need authentication tokens (JWT, access, refresh tokens)
|
|
10
|
+
* - Are working with custom user data types
|
|
11
|
+
* - Need comprehensive user session data
|
|
12
|
+
* - Want backward compatibility with legacy UserContext
|
|
13
|
+
*
|
|
14
|
+
* This hook supports two authentication patterns with automatic fallback:
|
|
15
|
+
* 1. Provider-based (legacy): Uses CivicAuthProvider or CivicNextAuthProvider
|
|
16
|
+
* 2. Provider-free (modern): Direct configuration via useUser(config)
|
|
17
|
+
*
|
|
18
|
+
* Usage Examples:
|
|
19
|
+
*
|
|
20
|
+
* // With provider (existing approach - NextJS/React providers)
|
|
21
|
+
* <CivicAuthProvider clientId="..." config={{ oauthServer: "..." }}>
|
|
22
|
+
* const { user, isLoading, signIn } = useUser();
|
|
23
|
+
* </CivicAuthProvider>
|
|
24
|
+
*
|
|
25
|
+
* // Without provider (new approach) - direct configuration
|
|
26
|
+
* const { user, authStatus, signOut } = useUser({
|
|
27
|
+
* clientId: "your-client-id",
|
|
28
|
+
* config: { oauthServer: "https://auth.civic.com/oauth/" },
|
|
29
|
+
* displayMode: "iframe", // or "redirect", "popup", etc.
|
|
30
|
+
* scopes: ["openid", "profile", "email"],
|
|
31
|
+
* onSignIn: (error) => console.log("Sign in completed", error),
|
|
32
|
+
* onSignOut: () => console.log("Sign out completed")
|
|
33
|
+
* });
|
|
34
|
+
*
|
|
35
|
+
* // Generic typing for custom user data
|
|
36
|
+
* interface CustomUser { customField: string; }
|
|
37
|
+
* const { user } = useUser<CustomUser>(); // user will be User<CustomUser> | null
|
|
38
|
+
*/
|
|
1
39
|
"use client";
|
|
2
|
-
import { useContext } from "react";
|
|
3
|
-
import { UserContext
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
40
|
+
import { useContext, useState, useEffect, useCallback, useMemo } from "react";
|
|
41
|
+
import { UserContext } from "../../shared/providers/UserProvider.js";
|
|
42
|
+
import { GlobalAuthManager, } from "../core/GlobalAuthManager.js";
|
|
43
|
+
import { extractTokensFromSession } from "../../vanillajs/utils/auth-utils.js";
|
|
44
|
+
const useUser = (config) => {
|
|
45
|
+
// Always call context hooks unconditionally (rules of hooks)
|
|
46
|
+
const sharedContext = useContext(UserContext);
|
|
47
|
+
// State for global manager approach
|
|
48
|
+
const [globalState, setGlobalState] = useState(null);
|
|
49
|
+
// Determine which approach to use
|
|
50
|
+
const hasProviderContext = sharedContext;
|
|
51
|
+
const shouldUseGlobal = !hasProviderContext;
|
|
52
|
+
// Initialize global manager if no provider context
|
|
53
|
+
useEffect(() => {
|
|
54
|
+
if (!shouldUseGlobal)
|
|
55
|
+
return;
|
|
56
|
+
const manager = GlobalAuthManager.getInstance();
|
|
57
|
+
// If config is provided, initialize with it
|
|
58
|
+
if (config) {
|
|
59
|
+
const initializeAuth = async () => {
|
|
60
|
+
try {
|
|
61
|
+
await manager.initialize(config);
|
|
62
|
+
}
|
|
63
|
+
catch (error) {
|
|
64
|
+
console.error("Failed to initialize auth:", error);
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
initializeAuth();
|
|
68
|
+
}
|
|
69
|
+
// Subscribe to state changes
|
|
70
|
+
const unsubscribe = manager.subscribe((newState) => {
|
|
71
|
+
setGlobalState(newState);
|
|
72
|
+
});
|
|
73
|
+
// Get current state
|
|
74
|
+
setGlobalState(manager.getState());
|
|
75
|
+
return unsubscribe;
|
|
76
|
+
}, [shouldUseGlobal, config]);
|
|
77
|
+
// Global manager sign in/out functions
|
|
78
|
+
const globalSignIn = useCallback(async () => {
|
|
79
|
+
const manager = GlobalAuthManager.getInstance();
|
|
80
|
+
await manager.signIn();
|
|
81
|
+
// Get the user after sign in
|
|
82
|
+
const state = manager.getState();
|
|
83
|
+
if (!state.user) {
|
|
84
|
+
throw new Error("Authentication succeeded but no user was returned");
|
|
85
|
+
}
|
|
86
|
+
return { user: state.user };
|
|
87
|
+
}, []);
|
|
88
|
+
const globalSignOut = useCallback(async () => {
|
|
89
|
+
const manager = GlobalAuthManager.getInstance();
|
|
90
|
+
await manager.signOut();
|
|
91
|
+
}, []);
|
|
92
|
+
// Extract tokens from global state
|
|
93
|
+
const globalTokens = useMemo(() => {
|
|
94
|
+
return extractTokensFromSession(globalState?.session || null);
|
|
95
|
+
}, [globalState?.session]);
|
|
96
|
+
// Create wrapper functions for different signIn signatures
|
|
97
|
+
const wrapSharedSignIn = useCallback(async () => {
|
|
98
|
+
if (sharedContext) {
|
|
99
|
+
await sharedContext.signIn(); // This returns void
|
|
100
|
+
// Get user from context after sign in
|
|
101
|
+
if (sharedContext.user) {
|
|
102
|
+
return { user: sharedContext.user };
|
|
103
|
+
}
|
|
104
|
+
// We don't return a user yet in nextjs until the next refactor
|
|
105
|
+
return { user: null };
|
|
106
|
+
}
|
|
107
|
+
throw new Error("Shared context not available");
|
|
108
|
+
}, [sharedContext]);
|
|
109
|
+
// ========================================================================
|
|
110
|
+
// FALLBACK PRIORITY SYSTEM - Two authentication context approaches
|
|
111
|
+
// ========================================================================
|
|
112
|
+
// 1. DEPRECATED UserContext (ACTIVE - Used by NextJS)
|
|
113
|
+
// Framework-agnostic shared context from UserProvider
|
|
114
|
+
// Location: shared/providers/UserProvider.tsx
|
|
115
|
+
// Usage: NextJS example uses CivicNextAuthProvider → UserProvider → UserContext
|
|
116
|
+
if (sharedContext) {
|
|
117
|
+
return {
|
|
118
|
+
user: sharedContext.user,
|
|
119
|
+
idToken: sharedContext.idToken,
|
|
120
|
+
accessToken: sharedContext.accessToken,
|
|
121
|
+
refreshToken: undefined, // Not available in shared context
|
|
122
|
+
forwardedTokens: sharedContext.forwardedTokens,
|
|
123
|
+
isLoading: sharedContext.isLoading,
|
|
124
|
+
authStatus: sharedContext.authStatus,
|
|
125
|
+
error: sharedContext.error,
|
|
126
|
+
signIn: wrapSharedSignIn,
|
|
127
|
+
signOut: sharedContext.signOut,
|
|
128
|
+
displayMode: sharedContext.displayMode,
|
|
129
|
+
};
|
|
8
130
|
}
|
|
9
|
-
|
|
131
|
+
// 2. GlobalAuthManager (MODERN - Provider-free approach)
|
|
132
|
+
// Singleton-based state management, eliminates need for React providers
|
|
133
|
+
// Location: reactjs/core/GlobalAuthManager.ts
|
|
134
|
+
// Usage: React example uses CivicAuthProvider → GlobalAuthManager internally
|
|
135
|
+
// Can also be used directly: useUser({ clientId: "...", config: {...} })
|
|
136
|
+
if (globalState) {
|
|
137
|
+
return {
|
|
138
|
+
user: globalState.user,
|
|
139
|
+
idToken: globalTokens.idToken,
|
|
140
|
+
accessToken: globalTokens.accessToken,
|
|
141
|
+
refreshToken: globalTokens.refreshToken,
|
|
142
|
+
forwardedTokens: globalTokens.forwardedTokens,
|
|
143
|
+
isLoading: globalState.isLoading,
|
|
144
|
+
authStatus: globalState.authStatus,
|
|
145
|
+
error: globalState.error,
|
|
146
|
+
signIn: globalSignIn,
|
|
147
|
+
signOut: globalSignOut,
|
|
148
|
+
displayMode: globalState.displayMode,
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
// If no context and no global state, provide default loading state
|
|
152
|
+
// This happens when CivicAuthProvider is present but GlobalAuthManager hasn't initialized yet
|
|
153
|
+
return {
|
|
154
|
+
user: null,
|
|
155
|
+
idToken: null,
|
|
156
|
+
accessToken: null,
|
|
157
|
+
refreshToken: null,
|
|
158
|
+
forwardedTokens: undefined,
|
|
159
|
+
isLoading: true,
|
|
160
|
+
authStatus: "unauthenticated",
|
|
161
|
+
error: null,
|
|
162
|
+
signIn: globalSignIn,
|
|
163
|
+
signOut: globalSignOut,
|
|
164
|
+
displayMode: config?.displayMode,
|
|
165
|
+
};
|
|
10
166
|
};
|
|
11
167
|
export { useUser };
|
|
12
168
|
//# sourceMappingURL=useUser.js.map
|