@civic/auth 0.0.1-beta.0 → 0.0.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/dist/react.js CHANGED
@@ -80,18 +80,23 @@ var __async = (__this, __arguments, generator) => {
80
80
  // src/react/index.ts
81
81
  var react_exports = {};
82
82
  __export(react_exports, {
83
- CivicProvider: () => CivicProvider,
83
+ CivicAuthProvider: () => CivicAuthProvider,
84
+ CivicNextAuthProvider: () => CivicNextAuthProvider,
85
+ NextLogOut: () => NextLogOut,
86
+ SignInButton: () => SignInButton,
87
+ SignOutButton: () => SignOutButton,
84
88
  UserButton: () => UserButton,
85
89
  useAuth: () => useAuth,
86
- useParams: () => useParams,
90
+ useNextUser: () => useNextUser,
87
91
  useSession: () => useSession,
88
92
  useToken: () => useToken,
89
- useUser: () => useUser
93
+ useUser: () => useUser,
94
+ useUserCookie: () => useUserCookie
90
95
  });
91
96
  module.exports = __toCommonJS(react_exports);
92
97
 
93
98
  // src/react/hooks/useUser.tsx
94
- var import_react10 = require("react");
99
+ var import_react12 = require("react");
95
100
 
96
101
  // src/react/providers/UserProvider.tsx
97
102
  var import_react3 = require("react");
@@ -118,25 +123,24 @@ var useToken = () => {
118
123
  };
119
124
 
120
125
  // src/react/providers/UserProvider.tsx
121
- var import_jwt = require("oslo/jwt");
122
126
  var import_jsx_runtime = require("react/jsx-runtime");
123
127
  var UserContext = (0, import_react3.createContext)(null);
124
128
  var UserProvider = ({
125
- children
129
+ children,
130
+ userInfoService
126
131
  }) => {
127
132
  const { isLoading: authLoading, error: authError } = useAuth();
128
133
  const session = useSession();
129
134
  const { forwardedTokens, idToken, accessToken, refreshToken } = useToken();
130
- const { isAuthenticated, signIn, signOut } = useAuth();
135
+ const { signIn, signOut } = useAuth();
131
136
  const fetchUser = () => __async(void 0, null, function* () {
132
- if (!(session == null ? void 0 : session.idToken)) {
137
+ if (!accessToken || !userInfoService) {
133
138
  return null;
134
139
  }
135
- const parsedJWT = (0, import_jwt.parseJWT)(session.idToken);
136
- if (!parsedJWT) {
140
+ const user2 = yield userInfoService == null ? void 0 : userInfoService.getUserInfo(accessToken, idToken);
141
+ if (!user2) {
137
142
  return null;
138
143
  }
139
- const user2 = parsedJWT.payload;
140
144
  return __spreadProps(__spreadValues({}, user2), {
141
145
  forwardedTokens,
142
146
  idToken,
@@ -147,12 +151,11 @@ var UserProvider = ({
147
151
  const {
148
152
  data: user,
149
153
  isLoading: userLoading,
150
- error: userError,
151
- refetch
154
+ error: userError
152
155
  } = (0, import_react_query.useQuery)({
153
- queryKey: ["user", session == null ? void 0 : session.accessToken],
156
+ queryKey: ["user", session == null ? void 0 : session.idToken],
154
157
  queryFn: fetchUser,
155
- enabled: !!(session == null ? void 0 : session.accessToken)
158
+ enabled: !!(session == null ? void 0 : session.idToken)
156
159
  // Only run the query if we have an access token
157
160
  });
158
161
  const isLoading = authLoading || userLoading;
@@ -161,11 +164,9 @@ var UserProvider = ({
161
164
  UserContext.Provider,
162
165
  {
163
166
  value: {
164
- user,
167
+ user: user != null ? user : null,
165
168
  isLoading,
166
169
  error,
167
- refetch,
168
- isAuthenticated,
169
170
  signIn,
170
171
  signOut
171
172
  },
@@ -177,27 +178,41 @@ var UserProvider = ({
177
178
  // src/react/providers/TokenProvider.tsx
178
179
  var import_react4 = require("react");
179
180
  var import_react_query2 = require("@tanstack/react-query");
180
- var import_jwt2 = require("oslo/jwt");
181
+ var import_jwt = require("oslo/jwt");
182
+
183
+ // src/lib/jwt.ts
184
+ var convertForwardedTokenFormat = (inputTokens) => Object.fromEntries(
185
+ Object.entries(inputTokens).map(([source, tokens]) => [
186
+ source,
187
+ {
188
+ idToken: tokens == null ? void 0 : tokens.id_token,
189
+ accessToken: tokens == null ? void 0 : tokens.access_token,
190
+ refreshToken: tokens == null ? void 0 : tokens.refresh_token
191
+ }
192
+ ])
193
+ );
194
+
195
+ // src/react/providers/TokenProvider.tsx
181
196
  var import_jsx_runtime2 = require("react/jsx-runtime");
182
197
  var TokenContext = (0, import_react4.createContext)(void 0);
183
198
  var TokenProvider = ({ children }) => {
184
199
  const { isLoading, error: authError } = useAuth();
185
200
  const session = useSession();
186
- const queryClient2 = (0, import_react_query2.useQueryClient)();
201
+ const queryClient3 = (0, import_react_query2.useQueryClient)();
187
202
  const refreshTokenMutation = (0, import_react_query2.useMutation)({
188
203
  mutationFn: () => __async(void 0, null, function* () {
189
204
  throw new Error("Method not implemented.");
190
205
  }),
191
206
  onSuccess: () => {
192
- queryClient2.invalidateQueries({ queryKey: ["session"] });
207
+ queryClient3.invalidateQueries({ queryKey: ["session"] });
193
208
  }
194
209
  });
195
210
  const decodeTokens = (0, import_react4.useMemo)(() => {
196
211
  if (!(session == null ? void 0 : session.idToken)) return null;
197
- const parsedJWT = (0, import_jwt2.parseJWT)(session.idToken);
212
+ const parsedJWT = (0, import_jwt.parseJWT)(session.idToken);
198
213
  if (!parsedJWT) return null;
199
214
  const { forwardedTokens } = parsedJWT.payload;
200
- return forwardedTokens;
215
+ return forwardedTokens ? convertForwardedTokenFormat(forwardedTokens) : null;
201
216
  }, [session == null ? void 0 : session.idToken]);
202
217
  const value = (0, import_react4.useMemo)(
203
218
  () => ({
@@ -221,29 +236,32 @@ var TokenProvider = ({ children }) => {
221
236
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(TokenContext.Provider, { value, children });
222
237
  };
223
238
 
224
- // src/react/providers/AuthProvider.tsx
239
+ // src/shared/AuthProvider.tsx
225
240
  var import_react9 = require("react");
226
241
  var import_react_query3 = require("@tanstack/react-query");
227
242
 
228
243
  // src/services/UserInfoService.ts
244
+ var import_jwt3 = require("oslo/jwt");
229
245
  var UserInfoServiceImpl = class {
230
246
  constructor(endpoints) {
231
247
  this.endpoints = endpoints;
232
248
  }
233
- getUserInfo(accessToken) {
249
+ extractUserFromIdToken(idToken) {
250
+ const parsedJWT = (0, import_jwt3.parseJWT)(idToken);
251
+ if (!parsedJWT) {
252
+ return null;
253
+ }
254
+ return parsedJWT.payload;
255
+ }
256
+ getUserInfo(accessToken, idToken) {
234
257
  return __async(this, null, function* () {
235
- return {
236
- id: "user123",
237
- name: "John Doe",
238
- email: "john@example.com",
239
- picture: "https://example.com/john.jpg",
240
- given_name: "John",
241
- family_name: "Doe",
242
- created_at: /* @__PURE__ */ new Date(),
243
- updated_at: /* @__PURE__ */ new Date(),
244
- country: "US",
245
- accessToken
246
- };
258
+ if (idToken) {
259
+ return this.extractUserFromIdToken(idToken);
260
+ }
261
+ const userInfo = yield fetch(this.endpoints.userinfo, {
262
+ headers: { Authorization: `Bearer ${accessToken}` }
263
+ });
264
+ return userInfo.json();
247
265
  });
248
266
  }
249
267
  };
@@ -277,13 +295,14 @@ var generateState = (displayMode) => {
277
295
  uuid: (0, import_uuid.v4)(),
278
296
  displayMode
279
297
  });
280
- return Buffer.from(jsonString).toString("base64");
298
+ return btoa(jsonString);
281
299
  };
282
300
  var displayModeFromState = (state, sessionDisplayMode) => {
283
301
  try {
284
- const jsonString = Buffer.from(state, "base64").toString();
302
+ const jsonString = btoa(state);
285
303
  return JSON.parse(jsonString).displayMode;
286
- } catch (_e) {
304
+ } catch (e) {
305
+ console.error("Failed to parse displayMode from state:", e);
287
306
  return sessionDisplayMode;
288
307
  }
289
308
  };
@@ -316,44 +335,49 @@ var AuthSessionServiceImpl = class {
316
335
  this.clientId = clientId;
317
336
  this.redirectUrl = redirectUrl;
318
337
  this.oauthServer = oauthServer;
338
+ this.inputEndpoints = inputEndpoints;
319
339
  this.codeVerifier = void 0;
320
- this.state = void 0;
321
- this.codeVerifier = (0, import_oauth2.generateCodeVerifier)();
322
- this._endpoints = inputEndpoints;
340
+ this.refreshTokenTimeout = null;
341
+ this.codeVerifier = this.getCodeVerifier();
342
+ this.endpoints = inputEndpoints;
343
+ }
344
+ getCodeVerifier() {
345
+ return (0, import_oauth2.generateCodeVerifier)();
323
346
  }
324
347
  getUserInfoService() {
325
348
  return __async(this, null, function* () {
326
- if (this._userInfoService) {
327
- return this._userInfoService;
349
+ if (this.userInfoService) {
350
+ return this.userInfoService;
328
351
  }
329
352
  const endpoints = yield this.getEndpoints();
330
- this._userInfoService = new UserInfoServiceImpl(endpoints);
331
- return this._userInfoService;
353
+ this.userInfoService = new UserInfoServiceImpl(endpoints);
354
+ return this.userInfoService;
332
355
  });
333
356
  }
334
357
  getEndpoints() {
335
358
  return __async(this, null, function* () {
336
- if (this._endpoints) {
337
- return this._endpoints;
359
+ var _a;
360
+ if ((_a = this.endpoints) == null ? void 0 : _a.auth) {
361
+ return this.endpoints;
338
362
  }
339
- this._endpoints = yield getOauthEndpoints(this.oauthServer);
340
- return this._endpoints;
363
+ const jwksEndpoints = yield getOauthEndpoints(this.oauthServer);
364
+ return this.endpoints ? __spreadValues(__spreadValues({}, this.endpoints), jwksEndpoints) : jwksEndpoints;
341
365
  });
342
366
  }
343
367
  getOauth2Client() {
344
368
  return __async(this, null, function* () {
345
- if (this._oauth2Client) {
346
- return this._oauth2Client;
369
+ if (this.oauth2Client) {
370
+ return this.oauth2Client;
347
371
  }
348
372
  const endpoints = yield this.getEndpoints();
349
- this._oauth2Client = new import_oauth2.OAuth2Client(
373
+ this.oauth2Client = new import_oauth2.OAuth2Client(
350
374
  this.clientId,
351
375
  endpoints.auth,
352
376
  endpoints.token,
353
377
  // this
354
378
  { redirectURI: this.redirectUrl }
355
379
  );
356
- return this._oauth2Client;
380
+ return this.oauth2Client;
357
381
  });
358
382
  }
359
383
  getSessionData() {
@@ -367,25 +391,58 @@ var AuthSessionServiceImpl = class {
367
391
  JSON.stringify(__spreadValues({}, data))
368
392
  );
369
393
  }
370
- getAuthorizationUrl(scopes, displayMode, nonce) {
394
+ getUser() {
395
+ return JSON.parse(
396
+ localStorage.getItem(`civic-auth:${this.clientId}:user`) || "{}"
397
+ );
398
+ }
399
+ setUser(data) {
400
+ localStorage.setItem(
401
+ `civic-auth:${this.clientId}:user`,
402
+ JSON.stringify(data === null ? {} : data)
403
+ );
404
+ }
405
+ clearSessionData() {
406
+ localStorage.setItem(`civic-auth:${this.clientId}`, JSON.stringify({}));
407
+ }
408
+ getAuthorizationUrlWithChallenge(state, scopes) {
371
409
  return __async(this, null, function* () {
372
- const state = generateState(displayMode);
373
- this.state = state;
374
- const existingSessionData = this.getSessionData();
375
- this.updateSessionData(__spreadProps(__spreadValues({}, existingSessionData), {
376
- codeVerifier: this.codeVerifier,
377
- displayMode
378
- }));
410
+ var _a;
379
411
  const oauth2Client = yield this.getOauth2Client();
412
+ if ((_a = this.endpoints) == null ? void 0 : _a.challenge) {
413
+ const challenge = yield fetch(this.endpoints.challenge).then(
414
+ (res) => res.json().then((data) => data.challenge)
415
+ );
416
+ const oAuthUrl2 = yield oauth2Client.createAuthorizationURL({
417
+ state,
418
+ scopes
419
+ });
420
+ oAuthUrl2.searchParams.append("code_challenge", challenge);
421
+ oAuthUrl2.searchParams.append("code_challenge_method", "S256");
422
+ return oAuthUrl2;
423
+ }
380
424
  const oAuthUrl = yield oauth2Client.createAuthorizationURL({
381
425
  state,
382
426
  codeVerifier: this.codeVerifier,
383
427
  codeChallengeMethod: "S256",
384
428
  scopes
385
429
  });
430
+ return oAuthUrl;
431
+ });
432
+ }
433
+ getAuthorizationUrl(scopes, displayMode, nonce) {
434
+ return __async(this, null, function* () {
435
+ const state = generateState(displayMode);
436
+ const existingSessionData = this.getSessionData();
437
+ this.updateSessionData(__spreadProps(__spreadValues({}, existingSessionData), {
438
+ codeVerifier: this.codeVerifier,
439
+ displayMode
440
+ }));
441
+ const oAuthUrl = yield this.getAuthorizationUrlWithChallenge(state, scopes);
386
442
  if (nonce) {
387
443
  oAuthUrl.searchParams.append("nonce", nonce);
388
444
  }
445
+ oAuthUrl.searchParams.append("prompt", "consent");
389
446
  return oAuthUrl.toString();
390
447
  });
391
448
  }
@@ -435,7 +492,7 @@ var AuthSessionServiceImpl = class {
435
492
  if (!authorizationCode || !returnedState) {
436
493
  throw new Error("Invalid authorization response");
437
494
  }
438
- const codeVerifier = this.getSessionData().codeVerifier;
495
+ const codeVerifier = session.codeVerifier;
439
496
  const oauth2Client = yield this.getOauth2Client();
440
497
  const tokens = yield oauth2Client.validateAuthorizationCode(
441
498
  authorizationCode,
@@ -462,10 +519,14 @@ var AuthSessionServiceImpl = class {
462
519
  state: returnedState,
463
520
  accessToken: tokens.access_token,
464
521
  refreshToken: tokens.refresh_token,
522
+ timestamp: Date.now(),
465
523
  expiresIn: tokens.expires_in
466
524
  });
467
525
  this.updateSessionData(session);
526
+ const user = yield (yield this.getUserInfoService()).getUserInfo(tokens.access_token, tokens.id_token || null);
527
+ this.setUser(user);
468
528
  }
529
+ this.setupTokenRefresh(session);
469
530
  if (session.displayMode === "new_tab") {
470
531
  window.close();
471
532
  } else if (session.displayMode === "redirect") {
@@ -473,6 +534,24 @@ var AuthSessionServiceImpl = class {
473
534
  return session;
474
535
  });
475
536
  }
537
+ setupTokenRefresh(session) {
538
+ if (this.refreshTokenTimeout) {
539
+ clearTimeout(this.refreshTokenTimeout);
540
+ }
541
+ if (session.expiresIn) {
542
+ const elapsedTime = Date.now() - (session.timestamp || 0);
543
+ const remainingTime = session.expiresIn * 1e3 - elapsedTime;
544
+ const refreshTime = Math.max(0, remainingTime - 6e4);
545
+ this.refreshTokenTimeout = setTimeout(() => {
546
+ this.refreshToken().then((newSession) => {
547
+ console.log("Token refreshed successfully", newSession);
548
+ }).catch((error) => {
549
+ console.error("Failed to refresh token:", error);
550
+ this.updateSessionData({});
551
+ });
552
+ }, refreshTime);
553
+ }
554
+ }
476
555
  refreshToken() {
477
556
  return __async(this, null, function* () {
478
557
  const sessionData = this.getSessionData();
@@ -488,9 +567,11 @@ var AuthSessionServiceImpl = class {
488
567
  authenticated: true,
489
568
  accessToken: tokens.access_token,
490
569
  refreshToken: tokens.refresh_token,
570
+ timestamp: Date.now(),
491
571
  expiresIn: tokens.expires_in
492
572
  });
493
573
  this.updateSessionData(session);
574
+ this.setupTokenRefresh(session);
494
575
  return session;
495
576
  });
496
577
  }
@@ -501,7 +582,10 @@ var AuthSessionServiceImpl = class {
501
582
  throw new Error("No access token available");
502
583
  }
503
584
  const userInfoService = yield this.getUserInfoService();
504
- return userInfoService.getUserInfo(sessionData.accessToken);
585
+ return userInfoService.getUserInfo(
586
+ sessionData.accessToken,
587
+ sessionData.idToken || null
588
+ );
505
589
  });
506
590
  }
507
591
  /**
@@ -530,10 +614,7 @@ var AuthSessionServiceImpl = class {
530
614
  );
531
615
  returnPayload.accessToken = accessTokenResponse.payload;
532
616
  if (tokens.refresh_token) {
533
- const refreshResponse = yield jose.jwtVerify(tokens.refresh_token, JWKS, {
534
- issuer: getIssuerVariations(this.oauthServer)
535
- });
536
- returnPayload.refreshToken = refreshResponse.payload;
617
+ returnPayload.refreshToken = tokens.refresh_token;
537
618
  }
538
619
  return returnPayload;
539
620
  });
@@ -556,7 +637,9 @@ var AuthSessionServiceImpl = class {
556
637
  return sessionData;
557
638
  } catch (error) {
558
639
  console.warn("Failed to validate existing tokens", error);
559
- const unAuthenticatedSession = __spreadProps(__spreadValues({}, sessionData), { authenticated: false });
640
+ const unAuthenticatedSession = {
641
+ authenticated: false
642
+ };
560
643
  this.updateSessionData(unAuthenticatedSession);
561
644
  return unAuthenticatedSession;
562
645
  }
@@ -564,13 +647,42 @@ var AuthSessionServiceImpl = class {
564
647
  }
565
648
  };
566
649
 
650
+ // src/constants.ts
651
+ var DEFAULT_SCOPES = [
652
+ "openid",
653
+ "profile",
654
+ "email",
655
+ "forwardedTokens",
656
+ "offline_access"
657
+ ];
658
+ var IFRAME_ID = "civic-auth-iframe";
659
+
567
660
  // src/react/components/CivicAuthIframe.tsx
568
661
  var import_react5 = require("react");
662
+ var import_jsx_runtime3 = require("react/jsx-runtime");
663
+ var CivicAuthIframe = (0, import_react5.forwardRef)(
664
+ ({ authUrl, onLoad }, ref) => {
665
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
666
+ "iframe",
667
+ {
668
+ id: IFRAME_ID,
669
+ ref,
670
+ src: authUrl,
671
+ className: "h-96 w-80 border-none",
672
+ onLoad
673
+ }
674
+ );
675
+ }
676
+ );
677
+ CivicAuthIframe.displayName = "CivicAuthIframe";
678
+
679
+ // src/react/components/CivicAuthIframeModal.tsx
680
+ var import_react6 = require("react");
569
681
 
570
682
  // src/react/components/LoadingIcon.tsx
571
- var import_jsx_runtime3 = require("react/jsx-runtime");
572
- var LoadingIcon = () => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { role: "status", children: [
573
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
683
+ var import_jsx_runtime4 = require("react/jsx-runtime");
684
+ var LoadingIcon = () => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { role: "status", children: [
685
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
574
686
  "svg",
575
687
  {
576
688
  "aria-hidden": "true",
@@ -579,14 +691,14 @@ var LoadingIcon = () => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { r
579
691
  fill: "none",
580
692
  xmlns: "http://www.w3.org/2000/svg",
581
693
  children: [
582
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
694
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
583
695
  "path",
584
696
  {
585
697
  d: "M100 50.5908C100 78.2051 77.6142 100.591 50 100.591C22.3858 100.591 0 78.2051 0 50.5908C0 22.9766 22.3858 0.59082 50 0.59082C77.6142 0.59082 100 22.9766 100 50.5908ZM9.08144 50.5908C9.08144 73.1895 27.4013 91.5094 50 91.5094C72.5987 91.5094 90.9186 73.1895 90.9186 50.5908C90.9186 27.9921 72.5987 9.67226 50 9.67226C27.4013 9.67226 9.08144 27.9921 9.08144 50.5908Z",
586
698
  fill: "currentColor"
587
699
  }
588
700
  ),
589
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
701
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
590
702
  "path",
591
703
  {
592
704
  d: "M93.9676 39.0409C96.393 38.4038 97.8624 35.9116 97.0079 33.5539C95.2932 28.8227 92.871 24.3692 89.8167 20.348C85.8452 15.1192 80.8826 10.7238 75.2124 7.41289C69.5422 4.10194 63.2754 1.94025 56.7698 1.05124C51.7666 0.367541 46.6976 0.446843 41.7345 1.27873C39.2613 1.69328 37.813 4.19778 38.4501 6.62326C39.0873 9.04874 41.5694 10.4717 44.0505 10.1071C47.8511 9.54855 51.7191 9.52689 55.5402 10.0491C60.8642 10.7766 65.9928 12.5457 70.6331 15.2552C75.2735 17.9648 79.3347 21.5619 82.5849 25.841C84.9175 28.9121 86.7997 32.2913 88.1811 35.8758C89.083 38.2158 91.5421 39.6781 93.9676 39.0409Z",
@@ -596,12 +708,12 @@ var LoadingIcon = () => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { r
596
708
  ]
597
709
  }
598
710
  ),
599
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "sr-only", children: "Loading..." })
711
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "sr-only", children: "Loading..." })
600
712
  ] });
601
713
 
602
- // src/react/components/CivicAuthIframe.tsx
603
- var import_jsx_runtime4 = require("react/jsx-runtime");
604
- var CloseIcon = () => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
714
+ // src/react/components/CloseIcon.tsx
715
+ var import_jsx_runtime5 = require("react/jsx-runtime");
716
+ var CloseIcon = () => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
605
717
  "svg",
606
718
  {
607
719
  xmlns: "http://www.w3.org/2000/svg",
@@ -615,26 +727,31 @@ var CloseIcon = () => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
615
727
  strokeLinejoin: "round",
616
728
  className: "lucide lucide-x",
617
729
  children: [
618
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M18 6 6 18" }),
619
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "m6 6 12 12" })
730
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M18 6 6 18" }),
731
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "m6 6 12 12" })
620
732
  ]
621
733
  }
622
734
  );
623
- var IFRAME_ID = "civic-auth-iframe";
624
- var CivicAuthIframe = ({
735
+
736
+ // src/react/components/CivicAuthIframeModal.tsx
737
+ var import_jsx_runtime6 = require("react/jsx-runtime");
738
+ var CivicAuthIframeModal = ({
625
739
  authUrl,
626
740
  redirectUri,
627
741
  setAuthResponseUrl,
628
- onClose
742
+ onClose,
743
+ iframeRef,
744
+ redirectInProgress = false,
745
+ closeOnRedirect = true
629
746
  }) => {
630
- const iframeRef = (0, import_react5.useRef)(null);
631
- const [isLoading, setIsLoading] = (0, import_react5.useState)(true);
632
- const processIframeUrl = (0, import_react5.useCallback)(() => {
747
+ const [isLoading, setIsLoading] = (0, import_react6.useState)(true);
748
+ const processIframeUrl = (0, import_react6.useCallback)(() => {
633
749
  if (iframeRef.current && iframeRef.current.contentWindow) {
634
750
  try {
635
751
  const iframeUrl = iframeRef.current.contentWindow.location.href;
636
752
  if (iframeUrl.startsWith(redirectUri)) {
637
753
  setAuthResponseUrl(iframeUrl);
754
+ if (closeOnRedirect) onClose();
638
755
  return true;
639
756
  }
640
757
  } catch (e) {
@@ -642,14 +759,17 @@ var CivicAuthIframe = ({
642
759
  }
643
760
  }
644
761
  return false;
645
- }, [redirectUri, setAuthResponseUrl]);
646
- const intervalId = (0, import_react5.useRef)();
647
- (0, import_react5.useEffect)(() => {
648
- const handleEscape = (event) => {
762
+ }, [closeOnRedirect, iframeRef, onClose, redirectUri, setAuthResponseUrl]);
763
+ const intervalId = (0, import_react6.useRef)();
764
+ const handleEscape = (0, import_react6.useCallback)(
765
+ (event) => {
649
766
  if (event.key === "Escape") {
650
767
  onClose();
651
768
  }
652
- };
769
+ },
770
+ [onClose]
771
+ );
772
+ (0, import_react6.useEffect)(() => {
653
773
  window.addEventListener("keydown", handleEscape);
654
774
  return () => window.removeEventListener("keydown", handleEscape);
655
775
  });
@@ -660,33 +780,31 @@ var CivicAuthIframe = ({
660
780
  clearInterval(intervalId.current);
661
781
  }
662
782
  };
663
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
783
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
664
784
  "div",
665
785
  {
666
- className: "absolute left-0 top-0 z-[9999] flex h-screen w-screen items-center justify-center bg-neutral-950 bg-opacity-50",
786
+ className: "absolute left-0 top-0 z-50 flex h-screen w-screen items-center justify-center bg-neutral-950 bg-opacity-50",
667
787
  onClick: onClose,
668
- children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
788
+ children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
669
789
  "div",
670
790
  {
671
791
  className: "relative rounded-3xl bg-white p-6 shadow-lg",
672
792
  onClick: (e) => e.stopPropagation(),
673
793
  children: [
674
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
794
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
675
795
  "button",
676
796
  {
677
797
  className: "absolute right-4 top-4 flex cursor-pointer items-center justify-center border-none bg-transparent p-1 text-neutral-400",
678
798
  onClick: onClose,
679
- children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(CloseIcon, {})
799
+ children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(CloseIcon, {})
680
800
  }
681
801
  ),
682
- isLoading && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "absolute inset-0 flex items-center justify-center rounded-3xl bg-neutral-100", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(LoadingIcon, {}) }),
683
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
684
- "iframe",
802
+ (isLoading || redirectInProgress) && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "absolute inset-0 flex items-center justify-center rounded-3xl bg-neutral-100", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(LoadingIcon, {}) }),
803
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
804
+ CivicAuthIframe,
685
805
  {
686
- id: IFRAME_ID,
687
806
  ref: iframeRef,
688
- src: authUrl,
689
- className: "h-48 w-80 border-none",
807
+ authUrl,
690
808
  onLoad: handleIframeLoad
691
809
  }
692
810
  )
@@ -698,9 +816,9 @@ var CivicAuthIframe = ({
698
816
  };
699
817
 
700
818
  // src/react/components/UserButton.tsx
701
- var import_react6 = require("react");
702
- var import_jsx_runtime5 = require("react/jsx-runtime");
703
- var ChevronDown = () => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
819
+ var import_react7 = require("react");
820
+ var import_jsx_runtime7 = require("react/jsx-runtime");
821
+ var ChevronDown = () => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
704
822
  "svg",
705
823
  {
706
824
  xmlns: "http://www.w3.org/2000/svg",
@@ -713,10 +831,10 @@ var ChevronDown = () => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
713
831
  strokeLinecap: "round",
714
832
  strokeLinejoin: "round",
715
833
  className: "lucide lucide-chevron-down",
716
- children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "m6 9 6 6 6-6" })
834
+ children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("path", { d: "m6 9 6 6 6-6" })
717
835
  }
718
836
  );
719
- var ChevronUp = () => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
837
+ var ChevronUp = () => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
720
838
  "svg",
721
839
  {
722
840
  xmlns: "http://www.w3.org/2000/svg",
@@ -729,51 +847,48 @@ var ChevronUp = () => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
729
847
  strokeLinecap: "round",
730
848
  strokeLinejoin: "round",
731
849
  className: "lucide lucide-chevron-up",
732
- children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "m18 15-6-6-6 6" })
850
+ children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("path", { d: "m18 15-6-6-6 6" })
733
851
  }
734
852
  );
735
853
  var UserButton = ({
736
854
  displayMode,
737
855
  className
738
856
  }) => {
739
- const [isOpen, setIsOpen] = (0, import_react6.useState)(false);
857
+ const [isOpen, setIsOpen] = (0, import_react7.useState)(false);
740
858
  const { signIn, isAuthenticated, signOut } = useAuth();
741
859
  const { user } = useUser();
742
- (0, import_react6.useEffect)(() => {
743
- const handleEscape = (event) => {
744
- if (event.key === "Escape") {
745
- setIsOpen(false);
746
- }
747
- };
860
+ const handleClickOutside = (0, import_react7.useCallback)((event) => {
861
+ const target = event.target;
862
+ if (!target.closest("#civic-dropdown-container")) {
863
+ setIsOpen(false);
864
+ }
865
+ }, []);
866
+ const handleSignOut = (0, import_react7.useCallback)(() => __async(void 0, null, function* () {
867
+ yield signOut();
868
+ setIsOpen(false);
869
+ }), [signOut]);
870
+ const handleSignIn = (0, import_react7.useCallback)(() => __async(void 0, null, function* () {
871
+ yield signIn(displayMode);
872
+ setIsOpen(false);
873
+ }), [signIn, displayMode]);
874
+ const handleEscape = (0, import_react7.useCallback)((event) => {
875
+ if (event.key === "Escape") {
876
+ setIsOpen(false);
877
+ }
878
+ }, []);
879
+ (0, import_react7.useEffect)(() => {
748
880
  if (isOpen) {
881
+ window.addEventListener("click", handleClickOutside);
749
882
  window.addEventListener("keydown", handleEscape);
750
883
  }
751
884
  return () => {
885
+ window.removeEventListener("click", handleClickOutside);
752
886
  window.removeEventListener("keydown", handleEscape);
753
887
  };
754
- }, [isOpen]);
755
- (0, import_react6.useEffect)(() => {
756
- const handleClick = (event) => {
757
- const target = event.target;
758
- if (!target.closest("#civic-dropdown-container")) {
759
- setIsOpen(false);
760
- }
761
- };
762
- if (isOpen) {
763
- window.addEventListener("click", handleClick);
764
- }
765
- return () => {
766
- window.removeEventListener("click", handleClick);
767
- };
768
- }, [isOpen]);
769
- (0, import_react6.useEffect)(() => {
770
- if (!isAuthenticated) {
771
- setIsOpen(false);
772
- }
773
- }, [isAuthenticated]);
888
+ }, [handleClickOutside, handleEscape, isOpen]);
774
889
  if (isAuthenticated) {
775
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "relative", id: "civic-dropdown-container", children: [
776
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
890
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "relative", id: "civic-dropdown-container", children: [
891
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
777
892
  "button",
778
893
  {
779
894
  className: cn(
@@ -782,28 +897,28 @@ var UserButton = ({
782
897
  ),
783
898
  onClick: () => setIsOpen((isOpen2) => !isOpen2),
784
899
  children: [
785
- (user == null ? void 0 : user.picture) ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "relative flex h-10 w-10 shrink-0 gap-2 overflow-hidden rounded-full", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
900
+ (user == null ? void 0 : user.picture) ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "relative flex h-10 w-10 shrink-0 gap-2 overflow-hidden rounded-full", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
786
901
  "img",
787
902
  {
788
903
  className: "h-full w-full object-cover",
789
904
  src: user.picture,
790
905
  alt: (user == null ? void 0 : user.name) || (user == null ? void 0 : user.email)
791
906
  }
792
- ) }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", {}),
793
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: (user == null ? void 0 : user.name) || (user == null ? void 0 : user.email) }),
794
- isOpen ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ChevronUp, {}) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ChevronDown, {})
907
+ ) }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", {}),
908
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: (user == null ? void 0 : user.name) || (user == null ? void 0 : user.email) }),
909
+ isOpen ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ChevronUp, {}) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ChevronDown, {})
795
910
  ]
796
911
  }
797
912
  ),
798
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
913
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
799
914
  "div",
800
915
  {
801
916
  className: isOpen ? "absolute right-0 mt-2 w-full rounded-lg bg-white py-2 text-neutral-500 shadow-xl" : "hidden",
802
- children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("ul", { children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
917
+ children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("ul", { children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
803
918
  "button",
804
919
  {
805
920
  className: "block w-full px-4 py-2 transition-colors hover:bg-neutral-200 hover:bg-opacity-50",
806
- onClick: () => signOut(),
921
+ onClick: handleSignOut,
807
922
  children: "Logout"
808
923
  }
809
924
  ) }) })
@@ -811,42 +926,178 @@ var UserButton = ({
811
926
  )
812
927
  ] });
813
928
  }
814
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
929
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
815
930
  "button",
816
931
  {
817
932
  className: cn(
818
933
  "rounded-full border border-neutral-500 px-3 py-2 transition-colors hover:bg-neutral-200 hover:bg-opacity-50",
819
934
  className
820
935
  ),
821
- onClick: () => signIn(displayMode),
936
+ onClick: handleSignIn,
822
937
  children: "Sign in"
823
938
  }
824
939
  );
825
940
  };
826
941
 
827
- // src/react/providers/ParamsProvider.tsx
828
- var import_react7 = require("react");
829
- var import_jsx_runtime6 = require("react/jsx-runtime");
830
- var ParamsContext = (0, import_react7.createContext)(null);
831
- var ParamsProvider = ({
832
- children,
833
- clientId,
834
- redirectUrl,
835
- config,
836
- nonce
942
+ // src/react/components/SignInButton.tsx
943
+ var import_jsx_runtime8 = require("react/jsx-runtime");
944
+ var SignInButton = ({
945
+ displayMode,
946
+ className
837
947
  }) => {
838
- const value = {
839
- clientId,
840
- redirectUrl,
841
- config,
842
- nonce
843
- };
844
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ParamsContext.Provider, { value, children });
948
+ const { signIn } = useAuth();
949
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
950
+ "button",
951
+ {
952
+ className: cn(
953
+ "rounded-full border border-neutral-500 px-3 py-2 transition-colors hover:bg-neutral-200 hover:bg-opacity-50",
954
+ className
955
+ ),
956
+ onClick: () => signIn(displayMode),
957
+ children: "Sign In"
958
+ }
959
+ );
960
+ };
961
+
962
+ // src/react/components/SignOutButton.tsx
963
+ var import_jsx_runtime9 = require("react/jsx-runtime");
964
+ var SignOutButton = ({ className }) => {
965
+ const { signOut } = useAuth();
966
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
967
+ "button",
968
+ {
969
+ className: cn(
970
+ "rounded-full border border-neutral-500 px-3 py-2 transition-colors hover:bg-neutral-200 hover:bg-opacity-50",
971
+ className
972
+ ),
973
+ onClick: () => signOut(),
974
+ children: "Sign Out"
975
+ }
976
+ );
977
+ };
978
+
979
+ // src/lib/logger.ts
980
+ var import_debug = __toESM(require("debug"));
981
+ var PACKAGE_NAME = "@civic/auth";
982
+ var DebugLogger = class {
983
+ constructor(namespace) {
984
+ this.debugLogger = (0, import_debug.default)(`${PACKAGE_NAME}:${namespace}:debug`);
985
+ this.infoLogger = (0, import_debug.default)(`${PACKAGE_NAME}:${namespace}:info`);
986
+ this.warnLogger = (0, import_debug.default)(`${PACKAGE_NAME}:${namespace}:warn`);
987
+ this.errorLogger = (0, import_debug.default)(`${PACKAGE_NAME}:${namespace}:error`);
988
+ this.debugLogger.color = "4";
989
+ this.infoLogger.color = "2";
990
+ this.warnLogger.color = "3";
991
+ this.errorLogger.color = "1";
992
+ }
993
+ debug(message, ...args) {
994
+ this.debugLogger(message, ...args);
995
+ }
996
+ info(message, ...args) {
997
+ this.infoLogger(message, ...args);
998
+ }
999
+ warn(message, ...args) {
1000
+ this.warnLogger(message, ...args);
1001
+ }
1002
+ error(message, ...args) {
1003
+ this.errorLogger(message, ...args);
1004
+ }
1005
+ };
1006
+ var createLogger = (namespace) => new DebugLogger(namespace);
1007
+ var loggers = {
1008
+ // Next.js specific loggers
1009
+ nextjs: {
1010
+ routes: createLogger("api:routes"),
1011
+ middleware: createLogger("api:middleware"),
1012
+ handlers: {
1013
+ auth: createLogger("api:handlers:auth")
1014
+ }
1015
+ },
1016
+ // React specific loggers
1017
+ react: {
1018
+ components: createLogger("react:components"),
1019
+ hooks: createLogger("react:hooks"),
1020
+ context: createLogger("react:context")
1021
+ },
1022
+ // Shared utilities loggers
1023
+ services: {
1024
+ validation: createLogger("utils:validation"),
1025
+ network: createLogger("utils:network")
1026
+ }
1027
+ };
1028
+
1029
+ // src/nextjs/config.ts
1030
+ var logger = loggers.nextjs.handlers.auth;
1031
+ var defaultAuthConfig = {
1032
+ oauthServer: "https://auth-dev.civic.com/oauth",
1033
+ callbackUrl: "/api/auth/callback",
1034
+ challengeUrl: "/api/auth/challenge",
1035
+ logoutUrl: "/api/auth/logout",
1036
+ loginUrl: "/",
1037
+ include: ["/*"],
1038
+ exclude: [],
1039
+ cookies: {
1040
+ tokens: {
1041
+ sameSite: "strict",
1042
+ path: "/",
1043
+ maxAge: 60 * 60
1044
+ // 1 hour
1045
+ },
1046
+ user: {
1047
+ sameSite: "strict",
1048
+ path: "/",
1049
+ maxAge: 60 * 60
1050
+ // 1 hour
1051
+ }
1052
+ }
1053
+ };
1054
+ var withoutUndefined = (obj) => {
1055
+ const result = {};
1056
+ for (const key in obj) {
1057
+ if (obj[key] !== void 0) {
1058
+ result[key] = obj[key];
1059
+ }
1060
+ }
1061
+ return result;
1062
+ };
1063
+ var resolveAuthConfig = (config = {}) => {
1064
+ var _a, _b, _c, _d;
1065
+ const configFromEnv = withoutUndefined({
1066
+ clientId: process.env._civic_auth_client_id,
1067
+ oauthServer: process.env._civic_oauth_server,
1068
+ callbackUrl: process.env._civic_auth_callback_url,
1069
+ loginUrl: process.env._civic_auth_login_url,
1070
+ logoutUrl: process.env._civic_auth_logout_url,
1071
+ include: (_a = process.env._civic_auth_includes) == null ? void 0 : _a.split(","),
1072
+ exclude: (_b = process.env._civic_auth_excludes) == null ? void 0 : _b.split(","),
1073
+ cookies: process.env._civic_auth_cookie_config ? JSON.parse(process.env._civic_auth_cookie_config) : void 0
1074
+ });
1075
+ const mergedConfig = __spreadProps(__spreadValues(__spreadValues(__spreadValues({}, defaultAuthConfig), configFromEnv), config), {
1076
+ // Override with directly passed config
1077
+ cookies: {
1078
+ tokens: __spreadValues(__spreadValues({}, defaultAuthConfig.cookies.tokens), ((_c = config.cookies) == null ? void 0 : _c.tokens) || {}),
1079
+ user: __spreadValues(__spreadValues({}, defaultAuthConfig.cookies.user), ((_d = config.cookies) == null ? void 0 : _d.user) || {})
1080
+ }
1081
+ });
1082
+ logger.debug("Config from environment:", configFromEnv);
1083
+ logger.debug("Resolved config:", mergedConfig);
1084
+ if (mergedConfig.clientId === void 0) {
1085
+ throw new Error("Civic Auth client ID is required");
1086
+ }
1087
+ return mergedConfig;
1088
+ };
1089
+
1090
+ // src/react/components/NextLogOut.tsx
1091
+ var import_jsx_runtime10 = require("react/jsx-runtime");
1092
+ var NextLogOut = ({ children }) => {
1093
+ const config = resolveAuthConfig();
1094
+ const logoutUrl = `${config.logoutUrl}`;
1095
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("a", { href: logoutUrl, children });
845
1096
  };
846
1097
 
847
1098
  // src/react/providers/SessionProvider.tsx
848
1099
  var import_react8 = require("react");
849
- var import_jsx_runtime7 = require("react/jsx-runtime");
1100
+ var import_jsx_runtime11 = require("react/jsx-runtime");
850
1101
  var defaultSession = {
851
1102
  authenticated: false,
852
1103
  idToken: void 0,
@@ -854,10 +1105,7 @@ var defaultSession = {
854
1105
  displayMode: "iframe"
855
1106
  };
856
1107
  var SessionContext = (0, import_react8.createContext)(defaultSession);
857
- var SessionProvider = ({ children, session }) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SessionContext.Provider, { value: session || defaultSession, children });
858
-
859
- // src/constants.ts
860
- var DEFAULT_SCOPES = ["openid", "profile", "email", "forwardedTokens"];
1108
+ var SessionProvider = ({ children, session }) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(SessionContext.Provider, { value: session || defaultSession, children });
861
1109
 
862
1110
  // src/config.ts
863
1111
  var authConfig = {
@@ -865,8 +1113,23 @@ var authConfig = {
865
1113
  oauthServer: "https://auth-dev.civic.com/oauth/"
866
1114
  };
867
1115
 
868
- // src/react/providers/AuthProvider.tsx
869
- var import_jsx_runtime8 = require("react/jsx-runtime");
1116
+ // src/lib/windowUtil.ts
1117
+ var isWindowInIframe = (window2) => {
1118
+ var _a;
1119
+ if (typeof window2 !== "undefined") {
1120
+ try {
1121
+ if (((_a = window2 == null ? void 0 : window2.frameElement) == null ? void 0 : _a.id) === "civic-auth-iframe") {
1122
+ return true;
1123
+ }
1124
+ } catch (_e) {
1125
+ return false;
1126
+ }
1127
+ }
1128
+ return false;
1129
+ };
1130
+
1131
+ // src/shared/AuthProvider.tsx
1132
+ var import_jsx_runtime12 = require("react/jsx-runtime");
870
1133
  var AuthContext = (0, import_react9.createContext)(null);
871
1134
  var globalThisObject;
872
1135
  if (typeof window !== "undefined") {
@@ -884,28 +1147,21 @@ var AuthProvider = ({
884
1147
  config = authConfig,
885
1148
  nonce,
886
1149
  onSignIn,
887
- onSignOut
1150
+ onSignOut,
1151
+ authServiceImpl,
1152
+ serverSideTokenExchange
888
1153
  }) => {
889
1154
  const [iframeUrl, setIframeUrl] = (0, import_react9.useState)(null);
890
1155
  const [currentUrl, setCurrentUrl] = (0, import_react9.useState)(null);
891
1156
  const [isInIframe, setIsInIframe] = (0, import_react9.useState)(false);
892
1157
  const [authResponseUrl, setAuthResponseUrl] = (0, import_react9.useState)(null);
893
- const [tokenExchangeInProgress, setTokenExchangeInProgress] = (0, import_react9.useState)(false);
894
1158
  const [tokenExchangeError, setTokenExchangeError] = (0, import_react9.useState)();
895
- const queryClient2 = (0, import_react_query3.useQueryClient)();
1159
+ const queryClient3 = (0, import_react_query3.useQueryClient)();
1160
+ const iframeRef = (0, import_react9.useRef)(null);
896
1161
  (0, import_react9.useEffect)(() => {
897
- var _a, _b;
898
1162
  if (typeof globalThis.window !== "undefined") {
899
1163
  setCurrentUrl(globalThis.window.location.href);
900
- let isInIframeVal = false;
901
- try {
902
- if (((_b = (_a = globalThis.window) == null ? void 0 : _a.frameElement) == null ? void 0 : _b.id) === "civic-auth-iframe") {
903
- isInIframeVal = true;
904
- }
905
- } catch (_e) {
906
- isInIframeVal = false;
907
- }
908
- console.log("isInIframeVal", isInIframeVal);
1164
+ const isInIframeVal = isWindowInIframe(globalThis.window);
909
1165
  setIsInIframe(isInIframeVal);
910
1166
  }
911
1167
  }, []);
@@ -914,39 +1170,37 @@ var AuthProvider = ({
914
1170
  [currentUrl, inputRedirectUrl]
915
1171
  );
916
1172
  const authService = (0, import_react9.useMemo)(
917
- () => currentUrl ? new AuthSessionServiceImpl(
1173
+ () => currentUrl ? authServiceImpl || new AuthSessionServiceImpl(
918
1174
  clientId,
919
1175
  redirectUrl,
920
1176
  config == null ? void 0 : config.oauthServer,
921
1177
  config == null ? void 0 : config.endpoints
922
1178
  ) : null,
923
- [currentUrl, clientId, redirectUrl, config]
1179
+ [currentUrl, clientId, redirectUrl, config, authServiceImpl]
924
1180
  );
1181
+ const [userInfoService, setUserInfoService] = (0, import_react9.useState)();
1182
+ (0, import_react9.useEffect)(() => {
1183
+ if (!authService) return;
1184
+ authService.getUserInfoService().then(setUserInfoService);
1185
+ }, [authService]);
925
1186
  const {
926
1187
  data: session,
927
1188
  isLoading,
928
1189
  error
929
1190
  } = (0, import_react_query3.useQuery)({
930
- queryKey: ["session"],
1191
+ queryKey: ["session", authResponseUrl, iframeUrl, currentUrl, isInIframe],
931
1192
  queryFn: () => __async(void 0, null, function* () {
932
- const url = new URL(globalThis.window.location.href || "");
933
- console.log("AuthProvider useQuery", { isInIframe, url, authService });
934
1193
  if (!authService) {
935
1194
  return { authenticated: false };
936
1195
  }
937
- const existingSessionData = yield authService.validateExistingSession();
938
- if (existingSessionData.authenticated) {
939
- return existingSessionData;
940
- }
1196
+ const url = new URL(
1197
+ authResponseUrl ? authResponseUrl : globalThis.window.location.href || ""
1198
+ );
941
1199
  const code = url.searchParams.get("code");
942
- if (code && !isInIframe) {
1200
+ if (code && !isInIframe && !serverSideTokenExchange) {
943
1201
  try {
944
1202
  console.log("AuthProvider useQuery code", { isInIframe, code });
945
- setTokenExchangeInProgress(true);
946
- const newSession = yield authService.tokenExchange(
947
- globalThis.window.location.href
948
- );
949
- setTokenExchangeInProgress(false);
1203
+ const newSession = yield authService.tokenExchange(url.toString());
950
1204
  onSignIn == null ? void 0 : onSignIn();
951
1205
  return newSession;
952
1206
  } catch (error2) {
@@ -957,18 +1211,25 @@ var AuthProvider = ({
957
1211
  return { authenticated: false };
958
1212
  }
959
1213
  }
1214
+ const existingSessionData = yield authService.validateExistingSession();
1215
+ if (existingSessionData.authenticated) {
1216
+ return existingSessionData;
1217
+ }
960
1218
  return existingSessionData;
961
- }),
962
- enabled: !!authService && !!currentUrl && !isInIframe
1219
+ })
963
1220
  });
964
1221
  const signOutMutation = (0, import_react_query3.useMutation)({
965
1222
  mutationFn: () => __async(void 0, null, function* () {
966
1223
  authService == null ? void 0 : authService.updateSessionData({});
1224
+ setIframeUrl(null);
967
1225
  setAuthResponseUrl(null);
968
1226
  onSignOut == null ? void 0 : onSignOut();
969
1227
  }),
970
1228
  onSuccess: () => {
971
- queryClient2.setQueryData(["session"], null);
1229
+ queryClient3.setQueryData(
1230
+ ["session", authResponseUrl, iframeUrl, currentUrl, isInIframe],
1231
+ null
1232
+ );
972
1233
  }
973
1234
  });
974
1235
  const signIn = (0, import_react9.useCallback)(
@@ -992,126 +1253,159 @@ var AuthProvider = ({
992
1253
  () => session ? session.authenticated : false,
993
1254
  [session]
994
1255
  );
995
- (0, import_react9.useEffect)(() => {
996
- if (!authService || !authResponseUrl) return;
997
- const url = new URL(authResponseUrl);
998
- const code = url.searchParams.get("code");
999
- console.log("AuthProvider useEffect code", {
1000
- isAuthenticated,
1001
- code,
1002
- tokenExchangeInProgress,
1003
- isInIframe
1004
- });
1005
- if (code && !isAuthenticated && !tokenExchangeInProgress && !isInIframe) {
1006
- try {
1007
- setTokenExchangeInProgress(true);
1008
- authService.tokenExchange(authResponseUrl).then((newSession) => {
1009
- queryClient2.setQueryData(["session"], newSession);
1010
- setIframeUrl(null);
1011
- onSignIn == null ? void 0 : onSignIn();
1012
- }).catch((error2) => {
1013
- setTokenExchangeError(error2);
1014
- }).finally(() => {
1015
- setTokenExchangeInProgress(false);
1016
- });
1017
- } catch (error2) {
1018
- setTokenExchangeInProgress(false);
1019
- onSignIn == null ? void 0 : onSignIn(
1020
- error2 instanceof Error ? error2 : new Error("Failed to sign in")
1021
- );
1022
- }
1023
- }
1024
- }, [
1025
- authService,
1026
- onSignIn,
1027
- queryClient2,
1028
- isAuthenticated,
1029
- authResponseUrl,
1030
- tokenExchangeInProgress,
1031
- isInIframe
1032
- ]);
1033
1256
  const value = (0, import_react9.useMemo)(
1034
1257
  () => ({
1035
1258
  isLoading,
1036
1259
  error,
1037
- signOut: signOutMutation.mutate,
1260
+ signOut: () => __async(void 0, null, function* () {
1261
+ yield signOutMutation.mutateAsync();
1262
+ }),
1038
1263
  isAuthenticated,
1039
1264
  signIn
1040
1265
  }),
1041
- [isLoading, error, signOutMutation.mutate, isAuthenticated, signIn]
1042
- );
1043
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1044
- AuthContext.Provider,
1045
- {
1046
- value: __spreadProps(__spreadValues({}, value), {
1047
- signOut: () => __async(void 0, null, function* () {
1048
- yield signOutMutation.mutateAsync();
1049
- })
1050
- }),
1051
- children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1052
- ParamsProvider,
1053
- {
1054
- clientId,
1055
- redirectUrl,
1056
- config,
1057
- nonce,
1058
- children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(SessionProvider, { session, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(TokenProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(UserProvider, { children: [
1059
- !isInIframe && iframeUrl && !(session == null ? void 0 : session.authenticated) && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1060
- CivicAuthIframe,
1061
- {
1062
- authUrl: iframeUrl,
1063
- redirectUri: redirectUrl,
1064
- setAuthResponseUrl,
1065
- onClose: () => setIframeUrl(null)
1066
- }
1067
- ),
1068
- (tokenExchangeInProgress || tokenExchangeError || isLoading || isInIframe) && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "absolute left-0 top-0 z-[9999] flex h-screen w-screen items-center justify-center bg-white", children: [
1069
- " ",
1070
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "absolute inset-0 flex items-center justify-center bg-white", children: tokenExchangeError ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { children: [
1071
- "Error: ",
1072
- tokenExchangeError.message
1073
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(LoadingIcon, {}) })
1074
- ] }),
1075
- children
1076
- ] }) }) })
1077
- }
1078
- )
1079
- }
1266
+ [isLoading, error, signOutMutation, isAuthenticated, signIn]
1080
1267
  );
1268
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(AuthContext.Provider, { value, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(SessionProvider, { session, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(TokenProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(UserProvider, { userInfoService, children: [
1269
+ !isInIframe && iframeUrl && !(session == null ? void 0 : session.authenticated) && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1270
+ CivicAuthIframeModal,
1271
+ {
1272
+ iframeRef,
1273
+ authUrl: iframeUrl,
1274
+ redirectUri: redirectUrl,
1275
+ setAuthResponseUrl,
1276
+ onClose: () => setIframeUrl(null)
1277
+ }
1278
+ ),
1279
+ (tokenExchangeError || isLoading || error || isInIframe && !(tokenExchangeError || error)) && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "absolute left-0 top-0 z-50 flex h-screen w-screen items-center justify-center bg-white", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "absolute inset-0 flex items-center justify-center bg-white", children: tokenExchangeError || error ? /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { children: [
1280
+ "Error:",
1281
+ " ",
1282
+ (tokenExchangeError || error).message
1283
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(LoadingIcon, {}) }) }),
1284
+ children
1285
+ ] }) }) }) });
1081
1286
  };
1082
1287
 
1083
- // src/react/providers/CivicProvider.tsx
1288
+ // src/shared/CivicAuthProvider.tsx
1084
1289
  var import_react_query4 = require("@tanstack/react-query");
1085
- var import_jsx_runtime9 = require("react/jsx-runtime");
1290
+ var import_styles = require("@civic/auth/styles.css");
1291
+ var import_jsx_runtime13 = require("react/jsx-runtime");
1086
1292
  var queryClient = new import_react_query4.QueryClient();
1087
- var CivicProvider = (_a) => {
1293
+ var CivicAuthProvider = (_a) => {
1088
1294
  var _b = _a, { children } = _b, props = __objRest(_b, ["children"]);
1089
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_query4.QueryClientProvider, { client: queryClient, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(AuthProvider, __spreadProps(__spreadValues({}, props), { children })) });
1295
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_react_query4.QueryClientProvider, { client: queryClient, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(AuthProvider, __spreadProps(__spreadValues({}, props), { children })) });
1090
1296
  };
1091
1297
 
1092
- // src/react/hooks/useUser.tsx
1093
- var useUser = () => {
1094
- const context = (0, import_react10.useContext)(UserContext);
1095
- if (!context) {
1096
- throw new Error("useUser must be used within a UserProvider");
1298
+ // src/react/providers/NextAuthProvider.tsx
1299
+ var import_react11 = require("react");
1300
+
1301
+ // src/react/hooks/useUserCookie.ts
1302
+ var import_react10 = require("react");
1303
+ var import_navigation = require("next/navigation.js");
1304
+ var import_react_query5 = require("@tanstack/react-query");
1305
+
1306
+ // src/lib/cookies.ts
1307
+ var getCookieValue = (key, window2) => {
1308
+ const cookie = window2.document.cookie;
1309
+ if (!cookie) return null;
1310
+ const cookies = cookie.split(";");
1311
+ for (const c of cookies) {
1312
+ const [name, value] = c.trim().split("=");
1313
+ if (name === key) {
1314
+ try {
1315
+ return JSON.parse(decodeURIComponent(value));
1316
+ } catch (e) {
1317
+ console.log("Error parsing cookie value", e);
1318
+ return value;
1319
+ }
1320
+ }
1097
1321
  }
1098
- return context;
1322
+ return null;
1099
1323
  };
1100
1324
 
1101
- // src/react/hooks/useParams.tsx
1102
- var import_react11 = require("react");
1103
- var useParams = () => {
1104
- const context = (0, import_react11.useContext)(ParamsContext);
1325
+ // src/react/hooks/useUserCookie.ts
1326
+ var getUserFromCookie = () => {
1327
+ const userCookie = getCookieValue("user", globalThis.window);
1328
+ return userCookie;
1329
+ };
1330
+ var useUserCookie = () => {
1331
+ const hasRunRef = (0, import_react10.useRef)(false);
1332
+ const router = (0, import_navigation.useRouter)();
1333
+ const { data: user } = (0, import_react_query5.useQuery)({
1334
+ queryKey: ["user"],
1335
+ queryFn: () => getUserFromCookie(),
1336
+ refetchInterval: 2e3,
1337
+ refetchIntervalInBackground: true,
1338
+ enabled: !hasRunRef.current,
1339
+ refetchOnWindowFocus: true
1340
+ });
1341
+ (0, import_react10.useEffect)(() => {
1342
+ if (user) {
1343
+ if (!hasRunRef.current) {
1344
+ hasRunRef.current = true;
1345
+ router.refresh();
1346
+ }
1347
+ } else {
1348
+ hasRunRef.current = false;
1349
+ }
1350
+ }, [user, router]);
1351
+ return user;
1352
+ };
1353
+
1354
+ // src/react/providers/NextAuthProvider.tsx
1355
+ var import_react_query6 = require("@tanstack/react-query");
1356
+ var import_jsx_runtime14 = require("react/jsx-runtime");
1357
+ var queryClient2 = new import_react_query6.QueryClient();
1358
+ var defaultUserContext = { user: null };
1359
+ var UserContext2 = (0, import_react11.createContext)(defaultUserContext);
1360
+ var CivicNextAuthProvider = (_a) => {
1361
+ var _b = _a, {
1362
+ children
1363
+ } = _b, props = __objRest(_b, [
1364
+ "children"
1365
+ ]);
1366
+ const user = useUserCookie();
1367
+ const [redirectUrl, setRedirectUrl] = (0, import_react11.useState)("");
1368
+ const { clientId, oauthServer, callbackUrl, challengeUrl } = resolveAuthConfig();
1369
+ (0, import_react11.useEffect)(() => {
1370
+ if (typeof globalThis.window !== "undefined") {
1371
+ const currentUrl = globalThis.window.location.href;
1372
+ setRedirectUrl(new URL(callbackUrl, currentUrl).toString());
1373
+ }
1374
+ }, [callbackUrl]);
1375
+ const authService = (0, import_react11.useMemo)(() => {
1376
+ if (redirectUrl && clientId && oauthServer) {
1377
+ return new AuthSessionServiceImpl(clientId, redirectUrl, oauthServer, {
1378
+ challenge: challengeUrl
1379
+ });
1380
+ }
1381
+ return void 0;
1382
+ }, [redirectUrl, clientId, oauthServer, challengeUrl]);
1383
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_react_query6.QueryClientProvider, { client: queryClient2, children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1384
+ AuthProvider,
1385
+ __spreadProps(__spreadValues({}, props), {
1386
+ config: { oauthServer },
1387
+ clientId,
1388
+ authServiceImpl: authService,
1389
+ serverSideTokenExchange: true,
1390
+ children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(UserContext2.Provider, { value: user, children })
1391
+ })
1392
+ ) });
1393
+ };
1394
+ var useNextUser = () => (0, import_react11.useContext)(UserContext2);
1395
+
1396
+ // src/react/hooks/useUser.tsx
1397
+ var useUser = () => {
1398
+ const context = (0, import_react12.useContext)(UserContext);
1105
1399
  if (!context) {
1106
- throw new Error("useParams must be used within an ParamsProvider");
1400
+ throw new Error("useUser must be used within a UserProvider");
1107
1401
  }
1108
1402
  return context;
1109
1403
  };
1110
1404
 
1111
1405
  // src/react/hooks/useSession.tsx
1112
- var import_react12 = require("react");
1406
+ var import_react13 = require("react");
1113
1407
  var useSession = () => {
1114
- const context = (0, import_react12.useContext)(SessionContext);
1408
+ const context = (0, import_react13.useContext)(SessionContext);
1115
1409
  if (!context) {
1116
1410
  throw new Error("useSession must be used within an SessionProvider");
1117
1411
  }
@@ -1119,12 +1413,17 @@ var useSession = () => {
1119
1413
  };
1120
1414
  // Annotate the CommonJS export names for ESM import in node:
1121
1415
  0 && (module.exports = {
1122
- CivicProvider,
1416
+ CivicAuthProvider,
1417
+ CivicNextAuthProvider,
1418
+ NextLogOut,
1419
+ SignInButton,
1420
+ SignOutButton,
1123
1421
  UserButton,
1124
1422
  useAuth,
1125
- useParams,
1423
+ useNextUser,
1126
1424
  useSession,
1127
1425
  useToken,
1128
- useUser
1426
+ useUser,
1427
+ useUserCookie
1129
1428
  });
1130
1429
  //# sourceMappingURL=react.js.map