@civic/auth 0.9.1-beta.1 → 0.9.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.
- package/CHANGELOG.md +4 -0
- package/dist/lib/logger.d.ts +6 -0
- package/dist/lib/logger.d.ts.map +1 -1
- package/dist/lib/logger.js +7 -0
- package/dist/lib/logger.js.map +1 -1
- package/dist/nextjs/config.d.ts +2 -5
- package/dist/nextjs/config.d.ts.map +1 -1
- package/dist/nextjs/config.js +4 -57
- package/dist/nextjs/config.js.map +1 -1
- package/dist/react-router-7/components/UserButton.d.ts +15 -0
- package/dist/react-router-7/components/UserButton.d.ts.map +1 -0
- package/dist/react-router-7/components/UserButton.js +110 -0
- package/dist/react-router-7/components/UserButton.js.map +1 -0
- package/dist/react-router-7/components/UserButtonPresentation.d.ts +10 -0
- package/dist/react-router-7/components/UserButtonPresentation.d.ts.map +1 -0
- package/dist/react-router-7/components/UserButtonPresentation.js +19 -0
- package/dist/react-router-7/components/UserButtonPresentation.js.map +1 -0
- package/dist/react-router-7/config.d.ts +113 -0
- package/dist/react-router-7/config.d.ts.map +1 -0
- package/dist/react-router-7/config.js +88 -0
- package/dist/react-router-7/config.js.map +1 -0
- package/dist/react-router-7/cookies.d.ts +41 -0
- package/dist/react-router-7/cookies.d.ts.map +1 -0
- package/dist/react-router-7/cookies.js +194 -0
- package/dist/react-router-7/cookies.js.map +1 -0
- package/dist/react-router-7/index.d.ts +10 -0
- package/dist/react-router-7/index.d.ts.map +1 -0
- package/dist/react-router-7/index.js +12 -0
- package/dist/react-router-7/index.js.map +1 -0
- package/dist/react-router-7/routeHandler.d.ts +54 -0
- package/dist/react-router-7/routeHandler.d.ts.map +1 -0
- package/dist/react-router-7/routeHandler.js +397 -0
- package/dist/react-router-7/routeHandler.js.map +1 -0
- package/dist/react-router-7/useUser.d.ts +40 -0
- package/dist/react-router-7/useUser.d.ts.map +1 -0
- package/dist/react-router-7/useUser.js +102 -0
- package/dist/react-router-7/useUser.js.map +1 -0
- package/dist/reactjs/core/GlobalAuthManager.d.ts +6 -4
- package/dist/reactjs/core/GlobalAuthManager.d.ts.map +1 -1
- package/dist/reactjs/core/GlobalAuthManager.js +17 -6
- package/dist/reactjs/core/GlobalAuthManager.js.map +1 -1
- package/dist/reactjs/hooks/useUser.js.map +1 -1
- package/dist/server/session.d.ts.map +1 -1
- package/dist/server/session.js +1 -0
- package/dist/server/session.js.map +1 -1
- package/dist/services/AuthenticationService.d.ts.map +1 -1
- package/dist/services/AuthenticationService.js +0 -5
- package/dist/services/AuthenticationService.js.map +1 -1
- package/dist/shared/hooks/useCivicAuthConfig.d.ts +1 -1
- package/dist/shared/hooks/useCivicAuthConfig.d.ts.map +1 -1
- package/dist/shared/lib/cookieConfig.d.ts +46 -0
- package/dist/shared/lib/cookieConfig.d.ts.map +1 -0
- package/dist/shared/lib/cookieConfig.js +99 -0
- package/dist/shared/lib/cookieConfig.js.map +1 -0
- package/dist/shared/lib/util.d.ts +5 -0
- package/dist/shared/lib/util.d.ts.map +1 -1
- package/dist/shared/lib/util.js +65 -3
- package/dist/shared/lib/util.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 +1 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/vanillajs/auth/CivicAuth.d.ts +1 -1
- package/dist/vanillajs/auth/CivicAuth.d.ts.map +1 -1
- package/dist/vanillajs/auth/CivicAuth.js +33 -12
- package/dist/vanillajs/auth/CivicAuth.js.map +1 -1
- package/dist/vanillajs/auth/config/ConfigProcessor.d.ts.map +1 -1
- package/dist/vanillajs/auth/config/ConfigProcessor.js +16 -2
- package/dist/vanillajs/auth/config/ConfigProcessor.js.map +1 -1
- package/dist/vanillajs/auth/handlers/LogoutHandler.d.ts +57 -0
- package/dist/vanillajs/auth/handlers/LogoutHandler.d.ts.map +1 -0
- package/dist/vanillajs/auth/handlers/LogoutHandler.js +246 -0
- package/dist/vanillajs/auth/handlers/LogoutHandler.js.map +1 -0
- package/dist/vanillajs/auth/handlers/MessageHandler.d.ts.map +1 -1
- package/dist/vanillajs/auth/handlers/MessageHandler.js +3 -0
- package/dist/vanillajs/auth/handlers/MessageHandler.js.map +1 -1
- package/dist/vanillajs/iframe/IframeManager.d.ts.map +1 -1
- package/dist/vanillajs/iframe/IframeManager.js +13 -0
- package/dist/vanillajs/iframe/IframeManager.js.map +1 -1
- package/package.json +11 -3
|
@@ -0,0 +1,397 @@
|
|
|
1
|
+
import { redirect } from "react-router";
|
|
2
|
+
import { CivicAuth } from "@civic/auth/server";
|
|
3
|
+
import { ReactRouterCookieStorage } from "./cookies.js";
|
|
4
|
+
import { resolveAuthConfig } from "./config.js";
|
|
5
|
+
import { getProtocolFromRequest } from "../shared/lib/util.js";
|
|
6
|
+
/**
|
|
7
|
+
* Fields that are safe to expose to the frontend
|
|
8
|
+
*/
|
|
9
|
+
const WHITELISTED_FRONTEND_FIELDS = [
|
|
10
|
+
"clientId",
|
|
11
|
+
"oauthServer",
|
|
12
|
+
"callbackUrl",
|
|
13
|
+
"logoutCallbackUrl",
|
|
14
|
+
"loginUrl",
|
|
15
|
+
"baseUrl",
|
|
16
|
+
"logoutUrl",
|
|
17
|
+
];
|
|
18
|
+
/**
|
|
19
|
+
* Create auth route handlers for React Router - backend endpoints compatible with VanillaJS frontend integration
|
|
20
|
+
* These routes work similar to the Express example, using server-side CivicAuth SDK
|
|
21
|
+
*/
|
|
22
|
+
export function createRouteHandlers(configOverrides = {}) {
|
|
23
|
+
const config = resolveAuthConfig(configOverrides);
|
|
24
|
+
/**
|
|
25
|
+
* Gets a default base URL when no baseUrl is configured
|
|
26
|
+
* Uses request headers to determine protocol when possible
|
|
27
|
+
*/
|
|
28
|
+
const getDefaultBaseUrl = (request) => {
|
|
29
|
+
const protocol = getProtocolFromRequest(request);
|
|
30
|
+
const host = request ? new URL(request.url).host : "localhost:5191";
|
|
31
|
+
return `${protocol}//${host}`;
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* Resolves configuration with proper fallbacks based on request context
|
|
35
|
+
* @param request - The request object to extract host for fallbacks
|
|
36
|
+
* @returns Resolved configuration with all fallbacks applied
|
|
37
|
+
*/
|
|
38
|
+
const resolveConfigWithFallbacks = (request) => {
|
|
39
|
+
const host = request
|
|
40
|
+
? `${getProtocolFromRequest(request)}//${new URL(request.url).host}`
|
|
41
|
+
: (config.baseUrl ?? getDefaultBaseUrl(request));
|
|
42
|
+
return {
|
|
43
|
+
clientId: config.clientId,
|
|
44
|
+
oauthServer: config.oauthServer,
|
|
45
|
+
callbackUrl: config.callbackUrl ?? `${host}/auth/callback`,
|
|
46
|
+
logoutCallbackUrl: config.logoutCallbackUrl ?? `${host}`,
|
|
47
|
+
loginUrl: config.loginUrl ?? `${host}/auth/login`,
|
|
48
|
+
baseUrl: config.baseUrl ?? host,
|
|
49
|
+
loginSuccessUrl: config.loginSuccessUrl ?? `${host}`,
|
|
50
|
+
logoutUrl: config.logoutUrl ?? `${host}`,
|
|
51
|
+
};
|
|
52
|
+
};
|
|
53
|
+
/**
|
|
54
|
+
* Gets the whitelisted frontend configuration with proper fallbacks
|
|
55
|
+
* Only exposes fields that are safe for frontend consumption
|
|
56
|
+
* @param request - The request object to extract host for fallbacks
|
|
57
|
+
* @returns The whitelisted configuration object with fallbacks applied
|
|
58
|
+
*/
|
|
59
|
+
const getWhitelistedFrontEndConfig = (request) => {
|
|
60
|
+
const resolved = resolveConfigWithFallbacks(request);
|
|
61
|
+
// Filter resolved config to only include whitelisted fields
|
|
62
|
+
return WHITELISTED_FRONTEND_FIELDS.reduce((acc, key) => {
|
|
63
|
+
acc[key] = resolved[key];
|
|
64
|
+
return acc;
|
|
65
|
+
}, {});
|
|
66
|
+
};
|
|
67
|
+
/**
|
|
68
|
+
* Helper to create CivicAuth instance for a request
|
|
69
|
+
*/
|
|
70
|
+
const createCivicAuth = (request) => {
|
|
71
|
+
const cookieStorage = new ReactRouterCookieStorage(request);
|
|
72
|
+
const resolvedConfig = resolveConfigWithFallbacks(request);
|
|
73
|
+
const civicAuth = new CivicAuth(cookieStorage, {
|
|
74
|
+
clientId: resolvedConfig.clientId,
|
|
75
|
+
redirectUrl: resolvedConfig.callbackUrl,
|
|
76
|
+
oauthServer: resolvedConfig.oauthServer,
|
|
77
|
+
postLogoutRedirectUrl: resolvedConfig.logoutCallbackUrl,
|
|
78
|
+
loginSuccessUrl: resolvedConfig.loginSuccessUrl,
|
|
79
|
+
loginUrl: resolvedConfig.loginUrl,
|
|
80
|
+
});
|
|
81
|
+
return {
|
|
82
|
+
civicAuth,
|
|
83
|
+
// Use the original cookieStorage instance that we properly configured with setRequest()
|
|
84
|
+
cookieStorage,
|
|
85
|
+
};
|
|
86
|
+
};
|
|
87
|
+
/**
|
|
88
|
+
* Helper to create response with cookie headers
|
|
89
|
+
* Following React Router pattern: add serialized cookies as "Set-Cookie" headers
|
|
90
|
+
*/
|
|
91
|
+
const createResponseWithCookies = (body, init, cookieStorage) => {
|
|
92
|
+
const headers = new Headers(init.headers);
|
|
93
|
+
// Add cookie headers from storage - each one is a complete "Set-Cookie" header from cookie.serialize()
|
|
94
|
+
const cookieHeaders = cookieStorage.getCookieHeaders();
|
|
95
|
+
cookieHeaders.forEach((cookieHeader) => {
|
|
96
|
+
headers.append("Set-Cookie", cookieHeader);
|
|
97
|
+
});
|
|
98
|
+
return new Response(body, {
|
|
99
|
+
...init,
|
|
100
|
+
headers,
|
|
101
|
+
});
|
|
102
|
+
};
|
|
103
|
+
/**
|
|
104
|
+
* Helper to create redirect with cookie headers
|
|
105
|
+
* Following React Router pattern: add serialized cookies as "Set-Cookie" headers
|
|
106
|
+
*/
|
|
107
|
+
const redirectWithCookies = (url, cookieStorage, init) => {
|
|
108
|
+
const headers = new Headers(init?.headers);
|
|
109
|
+
// Add cookie headers from storage - each one is a complete "Set-Cookie" header from cookie.serialize()
|
|
110
|
+
const cookieHeaders = cookieStorage.getCookieHeaders();
|
|
111
|
+
cookieHeaders.forEach((cookieHeader) => {
|
|
112
|
+
headers.append("Set-Cookie", cookieHeader);
|
|
113
|
+
});
|
|
114
|
+
// Set Location header for proper redirect
|
|
115
|
+
headers.set("Location", url);
|
|
116
|
+
return new Response(null, {
|
|
117
|
+
...init,
|
|
118
|
+
status: 302,
|
|
119
|
+
headers,
|
|
120
|
+
});
|
|
121
|
+
};
|
|
122
|
+
const handlers = {
|
|
123
|
+
/**
|
|
124
|
+
* Login loader - backend OAuth login initiation endpoint
|
|
125
|
+
* Uses CivicAuth.buildLoginUrl() like Express example
|
|
126
|
+
*/
|
|
127
|
+
loginLoader: async ({ request }) => {
|
|
128
|
+
const incomingUrl = new URL(request.url);
|
|
129
|
+
const frontendState = incomingUrl.searchParams.get("state");
|
|
130
|
+
// const returnTo = incomingUrl.searchParams.get("returnTo") || "/";
|
|
131
|
+
try {
|
|
132
|
+
const { civicAuth, cookieStorage } = createCivicAuth(request);
|
|
133
|
+
const url = await civicAuth.buildLoginUrl({
|
|
134
|
+
state: frontendState || undefined,
|
|
135
|
+
});
|
|
136
|
+
const response = redirectWithCookies(url.toString(), cookieStorage);
|
|
137
|
+
return response;
|
|
138
|
+
}
|
|
139
|
+
catch (error) {
|
|
140
|
+
console.error("[LOGIN_HANDLER] Backend login error:", error);
|
|
141
|
+
return redirect("/?error=login_failed");
|
|
142
|
+
}
|
|
143
|
+
},
|
|
144
|
+
/**
|
|
145
|
+
* Callback loader - backend OAuth callback endpoint
|
|
146
|
+
* Uses CivicAuth.handleCallback() like Express example
|
|
147
|
+
*/
|
|
148
|
+
callbackLoader: async ({ request }) => {
|
|
149
|
+
try {
|
|
150
|
+
const url = new URL(request.url);
|
|
151
|
+
const code = url.searchParams.get("code");
|
|
152
|
+
const state = url.searchParams.get("state");
|
|
153
|
+
const error = url.searchParams.get("error");
|
|
154
|
+
if (error) {
|
|
155
|
+
console.error("OAuth error in callback:", error);
|
|
156
|
+
return redirect("/?error=oauth_error");
|
|
157
|
+
}
|
|
158
|
+
if (!code || !state) {
|
|
159
|
+
throw new Error("Missing code or state parameter");
|
|
160
|
+
}
|
|
161
|
+
const { civicAuth, cookieStorage } = createCivicAuth(request);
|
|
162
|
+
// Convert React Router request to the format expected by handleCallback
|
|
163
|
+
const handleCallbackRequest = {
|
|
164
|
+
headers: Object.fromEntries(request.headers.entries()),
|
|
165
|
+
};
|
|
166
|
+
// For non-iframe requests, use the original handleCallback logic
|
|
167
|
+
const result = await civicAuth.handleCallback({
|
|
168
|
+
code,
|
|
169
|
+
state,
|
|
170
|
+
req: handleCallbackRequest,
|
|
171
|
+
});
|
|
172
|
+
if (result.redirectTo) {
|
|
173
|
+
return redirectWithCookies(result.redirectTo, cookieStorage);
|
|
174
|
+
}
|
|
175
|
+
if (result.content) {
|
|
176
|
+
// Handle both string content and object content
|
|
177
|
+
if (typeof result.content === "string") {
|
|
178
|
+
return createResponseWithCookies(result.content, {
|
|
179
|
+
status: 200,
|
|
180
|
+
headers: {
|
|
181
|
+
"Content-Type": "text/html",
|
|
182
|
+
},
|
|
183
|
+
}, cookieStorage);
|
|
184
|
+
}
|
|
185
|
+
else {
|
|
186
|
+
// Object content (JSON response)
|
|
187
|
+
return createResponseWithCookies(JSON.stringify(result.content), {
|
|
188
|
+
status: 200,
|
|
189
|
+
headers: {
|
|
190
|
+
"Content-Type": "application/json",
|
|
191
|
+
},
|
|
192
|
+
}, cookieStorage);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
// Fallback redirect
|
|
196
|
+
return redirectWithCookies("/", cookieStorage);
|
|
197
|
+
}
|
|
198
|
+
catch (error) {
|
|
199
|
+
console.error("[CALLBACK_HANDLER] OAuth callback error:", error);
|
|
200
|
+
return redirect("/?error=callback_failed");
|
|
201
|
+
}
|
|
202
|
+
},
|
|
203
|
+
/**
|
|
204
|
+
* Logout loader - backend logout endpoint
|
|
205
|
+
* Uses CivicAuth.buildLogoutRedirectUrl() and clearTokens() like Express example
|
|
206
|
+
*/
|
|
207
|
+
logoutLoader: async ({ request }) => {
|
|
208
|
+
try {
|
|
209
|
+
const { civicAuth, cookieStorage } = createCivicAuth(request);
|
|
210
|
+
const frontendState = new URL(request.url).searchParams.get("state");
|
|
211
|
+
const logoutUrl = await civicAuth.buildLogoutRedirectUrl({
|
|
212
|
+
state: frontendState || undefined,
|
|
213
|
+
});
|
|
214
|
+
await civicAuth.clearTokens();
|
|
215
|
+
const url = new URL(logoutUrl.toString());
|
|
216
|
+
// Remove the state parameter to avoid it showing up in the frontend URL
|
|
217
|
+
url.searchParams.delete("state");
|
|
218
|
+
return redirectWithCookies(url.toString(), cookieStorage);
|
|
219
|
+
}
|
|
220
|
+
catch (error) {
|
|
221
|
+
console.error("[LOGOUT_HANDLER] Logout error:", error);
|
|
222
|
+
// If logout URL generation fails, clear tokens and redirect to home (Express pattern)
|
|
223
|
+
try {
|
|
224
|
+
const { civicAuth, cookieStorage } = createCivicAuth(request);
|
|
225
|
+
await civicAuth.clearTokens();
|
|
226
|
+
return redirectWithCookies("/", cookieStorage);
|
|
227
|
+
}
|
|
228
|
+
catch (clearError) {
|
|
229
|
+
console.error("[LOGOUT_HANDLER] Failed to clear tokens:", clearError);
|
|
230
|
+
return redirect("/");
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
},
|
|
234
|
+
/**
|
|
235
|
+
* User endpoint - returns current user data as JSON
|
|
236
|
+
* Uses CivicAuth.isLoggedIn() and getUser() like Express example
|
|
237
|
+
*/
|
|
238
|
+
userLoader: async ({ request }) => {
|
|
239
|
+
try {
|
|
240
|
+
const { civicAuth, cookieStorage } = createCivicAuth(request);
|
|
241
|
+
const isLoggedIn = await civicAuth.isLoggedIn();
|
|
242
|
+
if (!isLoggedIn) {
|
|
243
|
+
return createResponseWithCookies(JSON.stringify({ error: "Not authenticated" }), {
|
|
244
|
+
status: 401,
|
|
245
|
+
headers: { "Content-Type": "application/json" },
|
|
246
|
+
}, cookieStorage);
|
|
247
|
+
}
|
|
248
|
+
const user = await civicAuth.getUser();
|
|
249
|
+
return createResponseWithCookies(JSON.stringify({ user }), {
|
|
250
|
+
status: 200,
|
|
251
|
+
headers: { "Content-Type": "application/json" },
|
|
252
|
+
}, cookieStorage);
|
|
253
|
+
}
|
|
254
|
+
catch (error) {
|
|
255
|
+
console.error("[USER_HANDLER] User endpoint error:", error);
|
|
256
|
+
return new Response(JSON.stringify({ error: "Internal server error" }), {
|
|
257
|
+
status: 500,
|
|
258
|
+
headers: { "Content-Type": "application/json" },
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
},
|
|
262
|
+
/**
|
|
263
|
+
* Refresh endpoint - refreshes access tokens
|
|
264
|
+
* Uses CivicAuth.refreshTokens() like Express example
|
|
265
|
+
*/
|
|
266
|
+
refreshLoader: async ({ request }) => {
|
|
267
|
+
try {
|
|
268
|
+
const { civicAuth, cookieStorage } = createCivicAuth(request);
|
|
269
|
+
const isLoggedIn = await civicAuth.isLoggedIn();
|
|
270
|
+
if (!isLoggedIn) {
|
|
271
|
+
return createResponseWithCookies(JSON.stringify({ error: "Not authenticated" }), {
|
|
272
|
+
status: 401,
|
|
273
|
+
headers: { "Content-Type": "application/json" },
|
|
274
|
+
}, cookieStorage);
|
|
275
|
+
}
|
|
276
|
+
await civicAuth.refreshTokens();
|
|
277
|
+
return createResponseWithCookies(JSON.stringify({ success: true, message: "Tokens refreshed" }), {
|
|
278
|
+
status: 200,
|
|
279
|
+
headers: { "Content-Type": "application/json" },
|
|
280
|
+
}, cookieStorage);
|
|
281
|
+
}
|
|
282
|
+
catch (error) {
|
|
283
|
+
console.error("[REFRESH_HANDLER] Token refresh error:", error);
|
|
284
|
+
return new Response(JSON.stringify({ error: "Token refresh failed" }), {
|
|
285
|
+
status: 500,
|
|
286
|
+
headers: { "Content-Type": "application/json" },
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
},
|
|
290
|
+
/**
|
|
291
|
+
* Get user data from session (for SSR)
|
|
292
|
+
* Uses CivicAuth.isLoggedIn() and getUser() like Express example
|
|
293
|
+
*/
|
|
294
|
+
getUser: async (request) => {
|
|
295
|
+
try {
|
|
296
|
+
const { civicAuth } = createCivicAuth(request);
|
|
297
|
+
const isLoggedIn = await civicAuth.isLoggedIn();
|
|
298
|
+
if (!isLoggedIn) {
|
|
299
|
+
return null;
|
|
300
|
+
}
|
|
301
|
+
return await civicAuth.getUser();
|
|
302
|
+
}
|
|
303
|
+
catch (error) {
|
|
304
|
+
console.error("[GETUSER_HANDLER] getUser error:", error);
|
|
305
|
+
return null;
|
|
306
|
+
}
|
|
307
|
+
},
|
|
308
|
+
/**
|
|
309
|
+
* Get auth data including user and config (for SSR)
|
|
310
|
+
* Returns user data, config, and other auth-related data needed by the app under a civic key
|
|
311
|
+
*/
|
|
312
|
+
getAuthData: async (request) => {
|
|
313
|
+
try {
|
|
314
|
+
const { civicAuth } = createCivicAuth(request);
|
|
315
|
+
const isLoggedIn = await civicAuth.isLoggedIn();
|
|
316
|
+
const user = isLoggedIn ? await civicAuth.getUser() : null;
|
|
317
|
+
// Get the whitelisted config with proper fallbacks using the request
|
|
318
|
+
const configWithFallbacks = getWhitelistedFrontEndConfig(request);
|
|
319
|
+
return {
|
|
320
|
+
civic: {
|
|
321
|
+
user,
|
|
322
|
+
config: configWithFallbacks,
|
|
323
|
+
isLoggedIn,
|
|
324
|
+
},
|
|
325
|
+
};
|
|
326
|
+
}
|
|
327
|
+
catch (error) {
|
|
328
|
+
console.error("[GETAUTHDATA_HANDLER] getAuthData error:", error);
|
|
329
|
+
// Even in error cases, provide config with fallbacks
|
|
330
|
+
const configWithFallbacks = getWhitelistedFrontEndConfig(request);
|
|
331
|
+
return {
|
|
332
|
+
civic: {
|
|
333
|
+
user: null,
|
|
334
|
+
config: configWithFallbacks,
|
|
335
|
+
isLoggedIn: false,
|
|
336
|
+
},
|
|
337
|
+
};
|
|
338
|
+
}
|
|
339
|
+
},
|
|
340
|
+
};
|
|
341
|
+
/**
|
|
342
|
+
* Creates a loader function that handles all auth routes
|
|
343
|
+
* @example
|
|
344
|
+
* // In your auth.$.tsx route file:
|
|
345
|
+
* export const loader = createAuthLoader();
|
|
346
|
+
*/
|
|
347
|
+
const createAuthLoader = () => {
|
|
348
|
+
return async (args) => {
|
|
349
|
+
// Get the auth path from the URL
|
|
350
|
+
const authPath = args.params["*"];
|
|
351
|
+
// Route to the appropriate handler
|
|
352
|
+
switch (authPath) {
|
|
353
|
+
case "login":
|
|
354
|
+
return handlers.loginLoader(args);
|
|
355
|
+
case "callback":
|
|
356
|
+
return handlers.callbackLoader(args);
|
|
357
|
+
case "refresh":
|
|
358
|
+
return handlers.refreshLoader(args);
|
|
359
|
+
case "logout":
|
|
360
|
+
return handlers.logoutLoader(args);
|
|
361
|
+
case "user":
|
|
362
|
+
return handlers.userLoader(args);
|
|
363
|
+
default:
|
|
364
|
+
// Return 404 for unknown auth paths
|
|
365
|
+
return new Response("Not Found", { status: 404 });
|
|
366
|
+
}
|
|
367
|
+
};
|
|
368
|
+
};
|
|
369
|
+
/**
|
|
370
|
+
* Creates an action function that handles POST requests to auth routes
|
|
371
|
+
* @example
|
|
372
|
+
* // In your auth.$.tsx route file:
|
|
373
|
+
* export const action = createAuthAction();
|
|
374
|
+
*/
|
|
375
|
+
const createAuthAction = () => {
|
|
376
|
+
return async (args) => {
|
|
377
|
+
// Get the auth path from the URL
|
|
378
|
+
const authPath = args.params["*"];
|
|
379
|
+
// Route to the appropriate handler for POST requests
|
|
380
|
+
switch (authPath) {
|
|
381
|
+
case "refresh":
|
|
382
|
+
return handlers.refreshLoader(args); // Same logic for refresh regardless of GET/POST
|
|
383
|
+
default:
|
|
384
|
+
// Return 405 Method Not Allowed for unsupported POST paths
|
|
385
|
+
return new Response("Method Not Allowed", { status: 405 });
|
|
386
|
+
}
|
|
387
|
+
};
|
|
388
|
+
};
|
|
389
|
+
return {
|
|
390
|
+
...handlers,
|
|
391
|
+
createAuthLoader,
|
|
392
|
+
createAuthAction,
|
|
393
|
+
resolveConfigWithFallbacks,
|
|
394
|
+
getWhitelistedFrontEndConfig,
|
|
395
|
+
};
|
|
396
|
+
}
|
|
397
|
+
//# sourceMappingURL=routeHandler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"routeHandler.js","sourceRoot":"","sources":["../../src/react-router-7/routeHandler.ts"],"names":[],"mappings":"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","sourcesContent":["import { redirect, type LoaderFunctionArgs } from \"react-router\";\nimport { CivicAuth } from \"@civic/auth/server\";\nimport { ReactRouterCookieStorage } from \"./cookies.js\";\nimport { resolveAuthConfig } from \"./config.js\";\nimport type {\n AuthConfig,\n ResolvedAuthConfig,\n WhitelistedFrontEndConfig,\n} from \"./config.js\";\nimport { getProtocolFromRequest } from \"@/shared/lib/util.js\";\n\n/**\n * Fields that are safe to expose to the frontend\n */\nconst WHITELISTED_FRONTEND_FIELDS = [\n \"clientId\",\n \"oauthServer\",\n \"callbackUrl\",\n \"logoutCallbackUrl\",\n \"loginUrl\",\n \"baseUrl\",\n \"logoutUrl\",\n] as const;\n\n/**\n * Create auth route handlers for React Router - backend endpoints compatible with VanillaJS frontend integration\n * These routes work similar to the Express example, using server-side CivicAuth SDK\n */\nexport function createRouteHandlers(configOverrides: Partial<AuthConfig> = {}) {\n const config = resolveAuthConfig(configOverrides);\n\n /**\n * Gets a default base URL when no baseUrl is configured\n * Uses request headers to determine protocol when possible\n */\n const getDefaultBaseUrl = (request?: Request): string => {\n const protocol = getProtocolFromRequest(request);\n const host = request ? new URL(request.url).host : \"localhost:5191\";\n\n return `${protocol}//${host}`;\n };\n\n /**\n * Resolves configuration with proper fallbacks based on request context\n * @param request - The request object to extract host for fallbacks\n * @returns Resolved configuration with all fallbacks applied\n */\n const resolveConfigWithFallbacks = (\n request?: Request,\n ): ResolvedAuthConfig => {\n const host = request\n ? `${getProtocolFromRequest(request)}//${new URL(request.url).host}`\n : (config.baseUrl ?? getDefaultBaseUrl(request));\n\n return {\n clientId: config.clientId,\n oauthServer: config.oauthServer,\n callbackUrl: config.callbackUrl ?? `${host}/auth/callback`,\n logoutCallbackUrl: config.logoutCallbackUrl ?? `${host}`,\n loginUrl: config.loginUrl ?? `${host}/auth/login`,\n baseUrl: config.baseUrl ?? host,\n loginSuccessUrl: config.loginSuccessUrl ?? `${host}`,\n logoutUrl: config.logoutUrl ?? `${host}`,\n };\n };\n\n /**\n * Gets the whitelisted frontend configuration with proper fallbacks\n * Only exposes fields that are safe for frontend consumption\n * @param request - The request object to extract host for fallbacks\n * @returns The whitelisted configuration object with fallbacks applied\n */\n const getWhitelistedFrontEndConfig = (\n request?: Request,\n ): WhitelistedFrontEndConfig => {\n const resolved = resolveConfigWithFallbacks(request);\n\n // Filter resolved config to only include whitelisted fields\n return WHITELISTED_FRONTEND_FIELDS.reduce((acc, key) => {\n acc[key] = resolved[key];\n return acc;\n }, {} as WhitelistedFrontEndConfig);\n };\n\n /**\n * Helper to create CivicAuth instance for a request\n */\n const createCivicAuth = (request: Request) => {\n const cookieStorage = new ReactRouterCookieStorage(request);\n\n const resolvedConfig = resolveConfigWithFallbacks(request);\n\n const civicAuth = new CivicAuth(cookieStorage, {\n clientId: resolvedConfig.clientId,\n redirectUrl: resolvedConfig.callbackUrl,\n oauthServer: resolvedConfig.oauthServer,\n postLogoutRedirectUrl: resolvedConfig.logoutCallbackUrl,\n loginSuccessUrl: resolvedConfig.loginSuccessUrl,\n loginUrl: resolvedConfig.loginUrl,\n });\n\n return {\n civicAuth,\n // Use the original cookieStorage instance that we properly configured with setRequest()\n cookieStorage,\n };\n };\n\n /**\n * Helper to create response with cookie headers\n * Following React Router pattern: add serialized cookies as \"Set-Cookie\" headers\n */\n const createResponseWithCookies = (\n body: string,\n init: ResponseInit,\n cookieStorage: ReactRouterCookieStorage,\n ): Response => {\n const headers = new Headers(init.headers);\n\n // Add cookie headers from storage - each one is a complete \"Set-Cookie\" header from cookie.serialize()\n const cookieHeaders = cookieStorage.getCookieHeaders();\n\n cookieHeaders.forEach((cookieHeader) => {\n headers.append(\"Set-Cookie\", cookieHeader);\n });\n\n return new Response(body, {\n ...init,\n headers,\n });\n };\n\n /**\n * Helper to create redirect with cookie headers\n * Following React Router pattern: add serialized cookies as \"Set-Cookie\" headers\n */\n const redirectWithCookies = (\n url: string,\n cookieStorage: ReactRouterCookieStorage,\n init?: ResponseInit,\n ): Response => {\n const headers = new Headers(init?.headers);\n\n // Add cookie headers from storage - each one is a complete \"Set-Cookie\" header from cookie.serialize()\n const cookieHeaders = cookieStorage.getCookieHeaders();\n\n cookieHeaders.forEach((cookieHeader) => {\n headers.append(\"Set-Cookie\", cookieHeader);\n });\n\n // Set Location header for proper redirect\n headers.set(\"Location\", url);\n\n return new Response(null, {\n ...init,\n status: 302,\n headers,\n });\n };\n\n const handlers = {\n /**\n * Login loader - backend OAuth login initiation endpoint\n * Uses CivicAuth.buildLoginUrl() like Express example\n */\n loginLoader: async ({ request }: LoaderFunctionArgs) => {\n const incomingUrl = new URL(request.url);\n const frontendState = incomingUrl.searchParams.get(\"state\");\n // const returnTo = incomingUrl.searchParams.get(\"returnTo\") || \"/\";\n\n try {\n const { civicAuth, cookieStorage } = createCivicAuth(request);\n\n const url = await civicAuth.buildLoginUrl({\n state: frontendState || undefined,\n });\n\n const response = redirectWithCookies(url.toString(), cookieStorage);\n\n return response;\n } catch (error) {\n console.error(\"[LOGIN_HANDLER] Backend login error:\", error);\n return redirect(\"/?error=login_failed\");\n }\n },\n\n /**\n * Callback loader - backend OAuth callback endpoint\n * Uses CivicAuth.handleCallback() like Express example\n */\n callbackLoader: async ({ request }: LoaderFunctionArgs) => {\n try {\n const url = new URL(request.url);\n const code = url.searchParams.get(\"code\");\n const state = url.searchParams.get(\"state\");\n const error = url.searchParams.get(\"error\");\n\n if (error) {\n console.error(\"OAuth error in callback:\", error);\n return redirect(\"/?error=oauth_error\");\n }\n\n if (!code || !state) {\n throw new Error(\"Missing code or state parameter\");\n }\n\n const { civicAuth, cookieStorage } = createCivicAuth(request);\n\n // Convert React Router request to the format expected by handleCallback\n const handleCallbackRequest = {\n headers: Object.fromEntries(request.headers.entries()),\n };\n\n // For non-iframe requests, use the original handleCallback logic\n const result = await civicAuth.handleCallback({\n code,\n state,\n req: handleCallbackRequest,\n });\n\n if (result.redirectTo) {\n return redirectWithCookies(result.redirectTo, cookieStorage);\n }\n\n if (result.content) {\n // Handle both string content and object content\n if (typeof result.content === \"string\") {\n return createResponseWithCookies(\n result.content,\n {\n status: 200,\n headers: {\n \"Content-Type\": \"text/html\",\n },\n },\n cookieStorage,\n );\n } else {\n // Object content (JSON response)\n return createResponseWithCookies(\n JSON.stringify(result.content),\n {\n status: 200,\n headers: {\n \"Content-Type\": \"application/json\",\n },\n },\n cookieStorage,\n );\n }\n }\n\n // Fallback redirect\n return redirectWithCookies(\"/\", cookieStorage);\n } catch (error) {\n console.error(\"[CALLBACK_HANDLER] OAuth callback error:\", error);\n return redirect(\"/?error=callback_failed\");\n }\n },\n\n /**\n * Logout loader - backend logout endpoint\n * Uses CivicAuth.buildLogoutRedirectUrl() and clearTokens() like Express example\n */\n logoutLoader: async ({ request }: LoaderFunctionArgs) => {\n try {\n const { civicAuth, cookieStorage } = createCivicAuth(request);\n const frontendState = new URL(request.url).searchParams.get(\"state\");\n\n const logoutUrl = await civicAuth.buildLogoutRedirectUrl({\n state: frontendState || undefined,\n });\n\n await civicAuth.clearTokens();\n\n const url = new URL(logoutUrl.toString());\n // Remove the state parameter to avoid it showing up in the frontend URL\n url.searchParams.delete(\"state\");\n\n return redirectWithCookies(url.toString(), cookieStorage);\n } catch (error) {\n console.error(\"[LOGOUT_HANDLER] Logout error:\", error);\n // If logout URL generation fails, clear tokens and redirect to home (Express pattern)\n try {\n const { civicAuth, cookieStorage } = createCivicAuth(request);\n await civicAuth.clearTokens();\n return redirectWithCookies(\"/\", cookieStorage);\n } catch (clearError) {\n console.error(\"[LOGOUT_HANDLER] Failed to clear tokens:\", clearError);\n return redirect(\"/\");\n }\n }\n },\n\n /**\n * User endpoint - returns current user data as JSON\n * Uses CivicAuth.isLoggedIn() and getUser() like Express example\n */\n userLoader: async ({ request }: LoaderFunctionArgs) => {\n try {\n const { civicAuth, cookieStorage } = createCivicAuth(request);\n\n const isLoggedIn = await civicAuth.isLoggedIn();\n\n if (!isLoggedIn) {\n return createResponseWithCookies(\n JSON.stringify({ error: \"Not authenticated\" }),\n {\n status: 401,\n headers: { \"Content-Type\": \"application/json\" },\n },\n cookieStorage,\n );\n }\n\n const user = await civicAuth.getUser();\n\n return createResponseWithCookies(\n JSON.stringify({ user }),\n {\n status: 200,\n headers: { \"Content-Type\": \"application/json\" },\n },\n cookieStorage,\n );\n } catch (error) {\n console.error(\"[USER_HANDLER] User endpoint error:\", error);\n return new Response(\n JSON.stringify({ error: \"Internal server error\" }),\n {\n status: 500,\n headers: { \"Content-Type\": \"application/json\" },\n },\n );\n }\n },\n\n /**\n * Refresh endpoint - refreshes access tokens\n * Uses CivicAuth.refreshTokens() like Express example\n */\n refreshLoader: async ({ request }: LoaderFunctionArgs) => {\n try {\n const { civicAuth, cookieStorage } = createCivicAuth(request);\n\n const isLoggedIn = await civicAuth.isLoggedIn();\n if (!isLoggedIn) {\n return createResponseWithCookies(\n JSON.stringify({ error: \"Not authenticated\" }),\n {\n status: 401,\n headers: { \"Content-Type\": \"application/json\" },\n },\n cookieStorage,\n );\n }\n\n await civicAuth.refreshTokens();\n\n return createResponseWithCookies(\n JSON.stringify({ success: true, message: \"Tokens refreshed\" }),\n {\n status: 200,\n headers: { \"Content-Type\": \"application/json\" },\n },\n cookieStorage,\n );\n } catch (error) {\n console.error(\"[REFRESH_HANDLER] Token refresh error:\", error);\n return new Response(JSON.stringify({ error: \"Token refresh failed\" }), {\n status: 500,\n headers: { \"Content-Type\": \"application/json\" },\n });\n }\n },\n\n /**\n * Get user data from session (for SSR)\n * Uses CivicAuth.isLoggedIn() and getUser() like Express example\n */\n getUser: async (request: Request) => {\n try {\n const { civicAuth } = createCivicAuth(request);\n\n const isLoggedIn = await civicAuth.isLoggedIn();\n if (!isLoggedIn) {\n return null;\n }\n\n return await civicAuth.getUser();\n } catch (error) {\n console.error(\"[GETUSER_HANDLER] getUser error:\", error);\n return null;\n }\n },\n\n /**\n * Get auth data including user and config (for SSR)\n * Returns user data, config, and other auth-related data needed by the app under a civic key\n */\n getAuthData: async (request: Request) => {\n try {\n const { civicAuth } = createCivicAuth(request);\n\n const isLoggedIn = await civicAuth.isLoggedIn();\n const user = isLoggedIn ? await civicAuth.getUser() : null;\n\n // Get the whitelisted config with proper fallbacks using the request\n const configWithFallbacks = getWhitelistedFrontEndConfig(request);\n\n return {\n civic: {\n user,\n config: configWithFallbacks,\n isLoggedIn,\n },\n };\n } catch (error) {\n console.error(\"[GETAUTHDATA_HANDLER] getAuthData error:\", error);\n // Even in error cases, provide config with fallbacks\n const configWithFallbacks = getWhitelistedFrontEndConfig(request);\n return {\n civic: {\n user: null,\n config: configWithFallbacks,\n isLoggedIn: false,\n },\n };\n }\n },\n };\n\n /**\n * Creates a loader function that handles all auth routes\n * @example\n * // In your auth.$.tsx route file:\n * export const loader = createAuthLoader();\n */\n const createAuthLoader = () => {\n return async (args: LoaderFunctionArgs) => {\n // Get the auth path from the URL\n const authPath = args.params[\"*\"];\n\n // Route to the appropriate handler\n switch (authPath) {\n case \"login\":\n return handlers.loginLoader(args);\n\n case \"callback\":\n return handlers.callbackLoader(args);\n\n case \"refresh\":\n return handlers.refreshLoader(args);\n\n case \"logout\":\n return handlers.logoutLoader(args);\n\n case \"user\":\n return handlers.userLoader(args);\n\n default:\n // Return 404 for unknown auth paths\n return new Response(\"Not Found\", { status: 404 });\n }\n };\n };\n\n /**\n * Creates an action function that handles POST requests to auth routes\n * @example\n * // In your auth.$.tsx route file:\n * export const action = createAuthAction();\n */\n const createAuthAction = () => {\n return async (args: LoaderFunctionArgs) => {\n // Get the auth path from the URL\n const authPath = args.params[\"*\"];\n\n // Route to the appropriate handler for POST requests\n switch (authPath) {\n case \"refresh\":\n return handlers.refreshLoader(args); // Same logic for refresh regardless of GET/POST\n\n default:\n // Return 405 Method Not Allowed for unsupported POST paths\n return new Response(\"Method Not Allowed\", { status: 405 });\n }\n };\n };\n\n return {\n ...handlers,\n createAuthLoader,\n createAuthAction,\n resolveConfigWithFallbacks,\n getWhitelistedFrontEndConfig,\n };\n}\n"]}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { type AuthResult, type CivicAuthClientConfig, type User } from "@civic/auth/vanillajs";
|
|
2
|
+
import type { AuthConfig } from "./config.js";
|
|
3
|
+
export type SignInConfig = Pick<CivicAuthClientConfig, "displayMode" | "clientId" | "redirectUrl" | "logoutRedirectUrl" | "targetContainerElement">;
|
|
4
|
+
export interface CivicAuthData {
|
|
5
|
+
user: User | null;
|
|
6
|
+
isLoggedIn: boolean;
|
|
7
|
+
config: AuthConfig;
|
|
8
|
+
}
|
|
9
|
+
export interface RootLoaderData {
|
|
10
|
+
civic: CivicAuthData;
|
|
11
|
+
}
|
|
12
|
+
export interface AuthData {
|
|
13
|
+
isLoggedIn: boolean;
|
|
14
|
+
user: User | null;
|
|
15
|
+
loginUrl: string;
|
|
16
|
+
logoutUrl: string;
|
|
17
|
+
isAuthenticating: boolean;
|
|
18
|
+
signIn: (config?: SignInConfig) => Promise<AuthResult>;
|
|
19
|
+
signOut: (baseUrl?: string) => Promise<void>;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Hook to access auth data from the root loader
|
|
23
|
+
* @returns CivicAuthData - The civic auth data from the root loader
|
|
24
|
+
*/
|
|
25
|
+
export declare function useAuthData(): CivicAuthData | undefined;
|
|
26
|
+
/**
|
|
27
|
+
* Hook to access authentication state and user information (SSR pattern)
|
|
28
|
+
* This is the primary hook for React Router 7 applications using server-side rendering
|
|
29
|
+
* Enhanced with GlobalAuthManager for better state management
|
|
30
|
+
* @returns Authentication state and user information from server-side rendering
|
|
31
|
+
*/
|
|
32
|
+
export declare function useUser(): {
|
|
33
|
+
user: import("../types.js").BaseUser | null;
|
|
34
|
+
isLoggedIn: boolean;
|
|
35
|
+
isAuthenticating: boolean;
|
|
36
|
+
signIn: (config?: SignInConfig) => Promise<AuthResult>;
|
|
37
|
+
signOut: () => Promise<void>;
|
|
38
|
+
config: AuthConfig;
|
|
39
|
+
};
|
|
40
|
+
//# sourceMappingURL=useUser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useUser.d.ts","sourceRoot":"","sources":["../../src/react-router-7/useUser.ts"],"names":[],"mappings":"AACA,OAAO,EACL,KAAK,UAAU,EACf,KAAK,qBAAqB,EAC1B,KAAK,IAAI,EACV,MAAM,uBAAuB,CAAC;AAM/B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAG9C,MAAM,MAAM,YAAY,GAAG,IAAI,CAC7B,qBAAqB,EACnB,aAAa,GACb,UAAU,GACV,aAAa,GACb,mBAAmB,GACnB,wBAAwB,CAC3B,CAAC;AAGF,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,IAAI,GAAG,IAAI,CAAC;IAClB,UAAU,EAAE,OAAO,CAAC;IACpB,MAAM,EAAE,UAAU,CAAC;CACpB;AAGD,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,aAAa,CAAC;CACtB;AAGD,MAAM,WAAW,QAAQ;IACvB,UAAU,EAAE,OAAO,CAAC;IACpB,IAAI,EAAE,IAAI,GAAG,IAAI,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,MAAM,EAAE,CAAC,MAAM,CAAC,EAAE,YAAY,KAAK,OAAO,CAAC,UAAU,CAAC,CAAC;IACvD,OAAO,EAAE,CAAC,OAAO,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9C;AAED;;;GAGG;AACH,wBAAgB,WAAW,IAAI,aAAa,GAAG,SAAS,CAKvD;AAED;;;;;GAKG;AACH,wBAAgB,OAAO;;;;sBA4CU,YAAY;;YAhFnC,UAAU;EA2HnB"}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { useMatches, useRevalidator } from "react-router";
|
|
2
|
+
import {} from "@civic/auth/vanillajs";
|
|
3
|
+
import { GlobalAuthManager, } from "../reactjs/core/GlobalAuthManager.js";
|
|
4
|
+
import { useEffect, useMemo, useState } from "react";
|
|
5
|
+
/**
|
|
6
|
+
* Hook to access auth data from the root loader
|
|
7
|
+
* @returns CivicAuthData - The civic auth data from the root loader
|
|
8
|
+
*/
|
|
9
|
+
export function useAuthData() {
|
|
10
|
+
const matches = useMatches();
|
|
11
|
+
const rootMatch = matches.find((match) => match.id === "root");
|
|
12
|
+
const data = rootMatch?.data;
|
|
13
|
+
return data?.civic;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Hook to access authentication state and user information (SSR pattern)
|
|
17
|
+
* This is the primary hook for React Router 7 applications using server-side rendering
|
|
18
|
+
* Enhanced with GlobalAuthManager for better state management
|
|
19
|
+
* @returns Authentication state and user information from server-side rendering
|
|
20
|
+
*/
|
|
21
|
+
export function useUser() {
|
|
22
|
+
const authData = useAuthData();
|
|
23
|
+
const revalidator = useRevalidator();
|
|
24
|
+
const [authManager] = useState(() => GlobalAuthManager.getInstance());
|
|
25
|
+
const [isAuthenticating, setIsAuthenticating] = useState(false);
|
|
26
|
+
if (!authData) {
|
|
27
|
+
throw new Error(`Auth data not found. Make sure to use createRootAuthLoader in your root route.
|
|
28
|
+
|
|
29
|
+
You might be seeing this error if:
|
|
30
|
+
- Your root loader is failing
|
|
31
|
+
- There's another part failing to return the civic data`);
|
|
32
|
+
}
|
|
33
|
+
const initialConfig = useMemo(() => {
|
|
34
|
+
return {
|
|
35
|
+
clientId: authData.config.clientId,
|
|
36
|
+
loginUrl: authData.config.loginUrl,
|
|
37
|
+
displayMode: "iframe",
|
|
38
|
+
framework: "react-router",
|
|
39
|
+
config: {
|
|
40
|
+
oauthServer: authData.config.oauthServer,
|
|
41
|
+
},
|
|
42
|
+
onSignIn: (error) => {
|
|
43
|
+
if (!error) {
|
|
44
|
+
revalidator.revalidate();
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
onSignOut: () => {
|
|
48
|
+
revalidator.revalidate();
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
}, [revalidator, authData]);
|
|
52
|
+
useEffect(() => {
|
|
53
|
+
const initialize = async () => {
|
|
54
|
+
await authManager.initialize(initialConfig);
|
|
55
|
+
};
|
|
56
|
+
initialize();
|
|
57
|
+
}, [authManager, initialConfig]);
|
|
58
|
+
// Create signIn function that leverages GlobalAuthManager
|
|
59
|
+
const signIn = async (config) => {
|
|
60
|
+
setIsAuthenticating(true);
|
|
61
|
+
try {
|
|
62
|
+
if (config) {
|
|
63
|
+
await authManager.initialize({
|
|
64
|
+
...initialConfig,
|
|
65
|
+
...config,
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
const result = await authManager.signIn();
|
|
69
|
+
// Return in AuthResult format for compatibility
|
|
70
|
+
return result;
|
|
71
|
+
}
|
|
72
|
+
catch (error) {
|
|
73
|
+
console.error("Sign-in failed:", error);
|
|
74
|
+
throw error;
|
|
75
|
+
}
|
|
76
|
+
finally {
|
|
77
|
+
setIsAuthenticating(false);
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
// Create signOut function that leverages GlobalAuthManager
|
|
81
|
+
const signOut = async () => {
|
|
82
|
+
try {
|
|
83
|
+
await authManager.signOut();
|
|
84
|
+
// The onSignOut callback will handle revalidation
|
|
85
|
+
}
|
|
86
|
+
catch (error) {
|
|
87
|
+
console.error("Sign-out failed:", error);
|
|
88
|
+
// Still try redirecting to logout URL as fallback
|
|
89
|
+
window.location.href = "/auth/logout";
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
// Ensure we have a valid user object or null
|
|
93
|
+
return {
|
|
94
|
+
...authData,
|
|
95
|
+
user: authData.user || null,
|
|
96
|
+
isLoggedIn: !!authData.user,
|
|
97
|
+
isAuthenticating,
|
|
98
|
+
signIn,
|
|
99
|
+
signOut,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=useUser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useUser.js","sourceRoot":"","sources":["../../src/react-router-7/useUser.ts"],"names":[],"mappings":"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","sourcesContent":["import { useMatches, useRevalidator } from \"react-router\";\nimport {\n type AuthResult,\n type CivicAuthClientConfig,\n type User,\n} from \"@civic/auth/vanillajs\";\nimport {\n GlobalAuthManager,\n type GlobalAuthConfig,\n} from \"../reactjs/core/GlobalAuthManager.js\";\nimport { useEffect, useMemo, useState } from \"react\";\nimport type { AuthConfig } from \"./config.js\";\n\n// Configuration type for signIn function\nexport type SignInConfig = Pick<\n CivicAuthClientConfig,\n | \"displayMode\"\n | \"clientId\"\n | \"redirectUrl\"\n | \"logoutRedirectUrl\"\n | \"targetContainerElement\"\n>;\n\n// Type for the civic auth data structure from the root loader\nexport interface CivicAuthData {\n user: User | null;\n isLoggedIn: boolean;\n config: AuthConfig;\n}\n\n// Type for the complete root loader data structure\nexport interface RootLoaderData {\n civic: CivicAuthData;\n}\n\n// Type for the auth data that will be available in the root loader (SSR pattern)\nexport interface AuthData {\n isLoggedIn: boolean;\n user: User | null;\n loginUrl: string;\n logoutUrl: string;\n isAuthenticating: boolean;\n signIn: (config?: SignInConfig) => Promise<AuthResult>;\n signOut: (baseUrl?: string) => Promise<void>;\n}\n\n/**\n * Hook to access auth data from the root loader\n * @returns CivicAuthData - The civic auth data from the root loader\n */\nexport function useAuthData(): CivicAuthData | undefined {\n const matches = useMatches();\n const rootMatch = matches.find((match) => match.id === \"root\");\n const data = rootMatch?.data as RootLoaderData | undefined;\n return data?.civic;\n}\n\n/**\n * Hook to access authentication state and user information (SSR pattern)\n * This is the primary hook for React Router 7 applications using server-side rendering\n * Enhanced with GlobalAuthManager for better state management\n * @returns Authentication state and user information from server-side rendering\n */\nexport function useUser() {\n const authData = useAuthData();\n const revalidator = useRevalidator();\n const [authManager] = useState(() => GlobalAuthManager.getInstance());\n const [isAuthenticating, setIsAuthenticating] = useState(false);\n\n if (!authData) {\n throw new Error(\n `Auth data not found. Make sure to use createRootAuthLoader in your root route.\n\nYou might be seeing this error if:\n- Your root loader is failing\n- There's another part failing to return the civic data`,\n );\n }\n\n const initialConfig: GlobalAuthConfig = useMemo(() => {\n return {\n clientId: authData.config.clientId,\n loginUrl: authData.config.loginUrl,\n displayMode: \"iframe\",\n framework: \"react-router\",\n config: {\n oauthServer: authData.config.oauthServer,\n },\n onSignIn: (error) => {\n if (!error) {\n revalidator.revalidate();\n }\n },\n onSignOut: () => {\n revalidator.revalidate();\n },\n };\n }, [revalidator, authData]);\n\n useEffect(() => {\n const initialize = async () => {\n await authManager.initialize(initialConfig);\n };\n initialize();\n }, [authManager, initialConfig]);\n\n // Create signIn function that leverages GlobalAuthManager\n const signIn = async (config?: SignInConfig) => {\n setIsAuthenticating(true);\n try {\n if (config) {\n await authManager.initialize({\n ...initialConfig,\n ...config,\n });\n }\n\n const result = await authManager.signIn();\n\n // Return in AuthResult format for compatibility\n return result as AuthResult;\n } catch (error) {\n console.error(\"Sign-in failed:\", error);\n throw error;\n } finally {\n setIsAuthenticating(false);\n }\n };\n\n // Create signOut function that leverages GlobalAuthManager\n const signOut = async () => {\n try {\n await authManager.signOut();\n // The onSignOut callback will handle revalidation\n } catch (error) {\n console.error(\"Sign-out failed:\", error);\n // Still try redirecting to logout URL as fallback\n window.location.href = \"/auth/logout\";\n }\n };\n\n // Ensure we have a valid user object or null\n return {\n ...authData,\n user: authData.user || null,\n isLoggedIn: !!authData.user,\n isAuthenticating,\n signIn,\n signOut,\n };\n}\n"]}
|
|
@@ -27,15 +27,17 @@
|
|
|
27
27
|
* - Server-side rendering scenarios where providers might be problematic
|
|
28
28
|
*/
|
|
29
29
|
import type { User, Session } from "../../vanillajs/index.js";
|
|
30
|
-
import type {
|
|
30
|
+
import type { FrameworkType } from "../../types.js";
|
|
31
|
+
import type { VanillaJSDisplayMode } from "../../vanillajs/auth/types/AuthTypes.js";
|
|
31
32
|
import type { LoggingConfig } from "../../vanillajs/auth/types/AuthTypes.js";
|
|
32
33
|
export interface GlobalAuthConfig {
|
|
33
|
-
clientId
|
|
34
|
+
clientId?: string;
|
|
34
35
|
redirectUrl?: string;
|
|
36
|
+
loginUrl?: string;
|
|
35
37
|
config?: {
|
|
36
38
|
oauthServer?: string;
|
|
37
39
|
};
|
|
38
|
-
displayMode?:
|
|
40
|
+
displayMode?: VanillaJSDisplayMode;
|
|
39
41
|
iframeMode?: "modal" | "embedded";
|
|
40
42
|
nonce?: string;
|
|
41
43
|
logoutRedirectUrl?: string;
|
|
@@ -56,7 +58,7 @@ export interface GlobalAuthState {
|
|
|
56
58
|
isLoading: boolean;
|
|
57
59
|
authStatus: AuthStatus;
|
|
58
60
|
error: Error | null;
|
|
59
|
-
displayMode?:
|
|
61
|
+
displayMode?: VanillaJSDisplayMode;
|
|
60
62
|
isPreloaded?: boolean;
|
|
61
63
|
}
|
|
62
64
|
type StateListener = (state: GlobalAuthState) => void;
|