@civic/auth 0.0.1-beta.4 → 0.0.1-beta.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/README.md +26 -0
  2. package/dist/{chunk-NQPMNXBL.mjs → chunk-EAANLFR5.mjs} +4 -10
  3. package/dist/chunk-EAANLFR5.mjs.map +1 -0
  4. package/dist/{chunk-3UIVD6NR.mjs → chunk-EGFTMH5S.mjs} +11 -65
  5. package/dist/chunk-EGFTMH5S.mjs.map +1 -0
  6. package/dist/{chunk-T47HULF6.js → chunk-KCSGIIPA.js} +21 -75
  7. package/dist/chunk-KCSGIIPA.js.map +1 -0
  8. package/dist/{chunk-WPISYQG3.js → chunk-MVO4UZ2A.js} +5 -11
  9. package/dist/chunk-MVO4UZ2A.js.map +1 -0
  10. package/dist/chunk-PMDIR5XE.mjs +502 -0
  11. package/dist/chunk-PMDIR5XE.mjs.map +1 -0
  12. package/dist/chunk-YNLXRD5L.js +502 -0
  13. package/dist/chunk-YNLXRD5L.js.map +1 -0
  14. package/dist/{index-DoDoIY_K.d.mts → index-Bfi0hVMZ.d.mts} +5 -26
  15. package/dist/{index-DoDoIY_K.d.ts → index-Bfi0hVMZ.d.ts} +5 -26
  16. package/dist/index.d.mts +1 -2
  17. package/dist/index.d.ts +1 -2
  18. package/dist/nextjs.d.mts +2 -3
  19. package/dist/nextjs.d.ts +2 -3
  20. package/dist/nextjs.js +22 -36
  21. package/dist/nextjs.js.map +1 -1
  22. package/dist/nextjs.mjs +8 -22
  23. package/dist/nextjs.mjs.map +1 -1
  24. package/dist/react.d.mts +29 -47
  25. package/dist/react.d.ts +29 -47
  26. package/dist/react.js +278 -487
  27. package/dist/react.js.map +1 -1
  28. package/dist/react.mjs +300 -509
  29. package/dist/react.mjs.map +1 -1
  30. package/dist/server.d.mts +2 -7
  31. package/dist/server.d.ts +2 -7
  32. package/dist/server.js +4 -3
  33. package/dist/server.js.map +1 -1
  34. package/dist/server.mjs +4 -3
  35. package/package.json +1 -1
  36. package/dist/chunk-3UIVD6NR.mjs.map +0 -1
  37. package/dist/chunk-KBDRDCE5.mjs +0 -239
  38. package/dist/chunk-KBDRDCE5.mjs.map +0 -1
  39. package/dist/chunk-NQPMNXBL.mjs.map +0 -1
  40. package/dist/chunk-OLT5HB3G.js +0 -239
  41. package/dist/chunk-OLT5HB3G.js.map +0 -1
  42. package/dist/chunk-T47HULF6.js.map +0 -1
  43. package/dist/chunk-WPISYQG3.js.map +0 -1
package/dist/react.mjs CHANGED
@@ -1,18 +1,21 @@
1
1
  import {
2
2
  resolveAuthConfig,
3
3
  resolveCallbackUrl
4
- } from "./chunk-NQPMNXBL.mjs";
4
+ } from "./chunk-EAANLFR5.mjs";
5
5
  import {
6
+ BrowserAuthenticationInitiator,
7
+ BrowserAuthenticationService,
8
+ BrowserPublicClientPKCEProducer,
9
+ ConfidentialClientPKCEConsumer,
6
10
  DEFAULT_SCOPES,
11
+ GenericUserSession,
7
12
  IFRAME_ID,
8
- buildOauth2Client,
13
+ LocalStorageAdapter,
9
14
  cn,
10
- displayModeFromState,
11
15
  generateState,
12
- getOauthEndpoints,
13
- isPopupBlocked,
14
- validateOauth2Tokens
15
- } from "./chunk-KBDRDCE5.mjs";
16
+ getUser,
17
+ isWindowInIframe
18
+ } from "./chunk-PMDIR5XE.mjs";
16
19
  import {
17
20
  __async,
18
21
  __objRest,
@@ -54,16 +57,32 @@ import { useMutation, useQueryClient } from "@tanstack/react-query";
54
57
  import { useContext as useContext2 } from "react";
55
58
 
56
59
  // src/react/providers/SessionProvider.tsx
57
- import { createContext as createContext2 } from "react";
60
+ import {
61
+ createContext as createContext2
62
+ } from "react";
58
63
  import { jsx } from "react/jsx-runtime";
59
64
  var defaultSession = {
60
65
  authenticated: false,
61
66
  idToken: void 0,
62
67
  accessToken: void 0,
63
- displayMode: "iframe"
68
+ displayMode: "iframe",
69
+ iframeRef: null,
70
+ setAuthResponseUrl: () => {
71
+ }
64
72
  };
65
73
  var SessionContext = createContext2(defaultSession);
66
- var SessionProvider = ({ children, session }) => /* @__PURE__ */ jsx(SessionContext.Provider, { value: session || defaultSession, children });
74
+ var SessionProvider = ({
75
+ children,
76
+ session,
77
+ iframeRef,
78
+ setAuthResponseUrl
79
+ }) => /* @__PURE__ */ jsx(
80
+ SessionContext.Provider,
81
+ {
82
+ value: __spreadProps(__spreadValues({}, session || defaultSession), { iframeRef, setAuthResponseUrl }),
83
+ children
84
+ }
85
+ );
67
86
 
68
87
  // src/react/hooks/useSession.tsx
69
88
  var useSession = () => {
@@ -147,26 +166,18 @@ import { jsx as jsx3 } from "react/jsx-runtime";
147
166
  var UserContext = createContext4(null);
148
167
  var UserProvider = ({
149
168
  children,
150
- userInfoService
169
+ storage
151
170
  }) => {
152
171
  const { isLoading: authLoading, error: authError } = useAuth();
153
172
  const session = useSession();
154
- const { forwardedTokens, idToken, accessToken, refreshToken } = useToken();
173
+ const { accessToken } = useToken();
155
174
  const { signIn, signOut } = useAuth();
156
175
  const fetchUser = () => __async(void 0, null, function* () {
157
- if (!accessToken || !userInfoService) {
158
- return null;
159
- }
160
- const user2 = yield userInfoService == null ? void 0 : userInfoService.getUserInfo(accessToken, idToken);
161
- if (!user2) {
176
+ if (!accessToken) {
162
177
  return null;
163
178
  }
164
- return __spreadProps(__spreadValues({}, user2), {
165
- forwardedTokens,
166
- idToken,
167
- accessToken,
168
- refreshToken
169
- });
179
+ const userSession = new GenericUserSession(storage);
180
+ return userSession.get();
170
181
  });
171
182
  const {
172
183
  data: user,
@@ -205,344 +216,7 @@ import {
205
216
  } from "react";
206
217
  import { useMutation as useMutation2, useQuery as useQuery2, useQueryClient as useQueryClient2 } from "@tanstack/react-query";
207
218
 
208
- // src/services/UserInfoService.ts
209
- import { parseJWT as parseJWT2 } from "oslo/jwt";
210
- var UserInfoServiceImpl = class {
211
- constructor(endpoints) {
212
- this.endpoints = endpoints;
213
- }
214
- extractUserFromIdToken(idToken) {
215
- const parsedJWT = parseJWT2(idToken);
216
- if (!parsedJWT) {
217
- return null;
218
- }
219
- return parsedJWT.payload;
220
- }
221
- getUserInfo(accessToken, idToken) {
222
- return __async(this, null, function* () {
223
- if (idToken) {
224
- return this.extractUserFromIdToken(idToken);
225
- }
226
- const userInfo = yield fetch(this.endpoints.userinfo, {
227
- headers: { Authorization: `Bearer ${accessToken}` }
228
- });
229
- return userInfo.json();
230
- });
231
- }
232
- };
233
-
234
- // src/services/SessionService.ts
235
- import { generateCodeVerifier } from "oslo/oauth2";
236
- var AuthSessionServiceImpl = class {
237
- constructor(clientId, redirectUrl, oauthServer, inputEndpoints) {
238
- this.clientId = clientId;
239
- this.redirectUrl = redirectUrl;
240
- this.oauthServer = oauthServer;
241
- this.inputEndpoints = inputEndpoints;
242
- this.codeVerifier = void 0;
243
- this.refreshTokenTimeout = null;
244
- this.codeVerifier = this.getCodeVerifier();
245
- this.endpoints = inputEndpoints;
246
- this.redirectUrl = redirectUrl;
247
- }
248
- getCodeVerifier() {
249
- return generateCodeVerifier();
250
- }
251
- getUserInfoService() {
252
- return __async(this, null, function* () {
253
- if (this.userInfoService) {
254
- return this.userInfoService;
255
- }
256
- const endpoints = yield this.getEndpoints();
257
- this.userInfoService = new UserInfoServiceImpl(endpoints);
258
- return this.userInfoService;
259
- });
260
- }
261
- getEndpoints() {
262
- return __async(this, null, function* () {
263
- var _a;
264
- if ((_a = this.endpoints) == null ? void 0 : _a.auth) {
265
- return this.endpoints;
266
- }
267
- const jwksEndpoints = yield getOauthEndpoints(this.oauthServer);
268
- return this.endpoints ? __spreadValues(__spreadValues({}, this.endpoints), jwksEndpoints) : jwksEndpoints;
269
- });
270
- }
271
- getOauth2Client() {
272
- return __async(this, null, function* () {
273
- if (this.oauth2Client) {
274
- return this.oauth2Client;
275
- }
276
- const endpoints = yield this.getEndpoints();
277
- this.oauth2Client = buildOauth2Client(
278
- this.clientId,
279
- this.redirectUrl,
280
- endpoints
281
- );
282
- return this.oauth2Client;
283
- });
284
- }
285
- getSessionData() {
286
- console.log("getSessionData", this.clientId);
287
- const storedItem = localStorage.getItem(`civic-auth:${this.clientId}`) || "{}";
288
- console.log("stored item", storedItem);
289
- return JSON.parse(storedItem);
290
- }
291
- updateSessionData(data) {
292
- localStorage.setItem(
293
- `civic-auth:${this.clientId}`,
294
- JSON.stringify(__spreadValues({}, data))
295
- );
296
- }
297
- getUser() {
298
- return JSON.parse(
299
- localStorage.getItem(`civic-auth:${this.clientId}:user`) || "{}"
300
- );
301
- }
302
- setUser(data) {
303
- localStorage.setItem(
304
- `civic-auth:${this.clientId}:user`,
305
- JSON.stringify(data === null ? {} : data)
306
- );
307
- }
308
- clearSessionData() {
309
- localStorage.setItem(`civic-auth:${this.clientId}`, JSON.stringify({}));
310
- }
311
- getAuthorizationUrlWithChallenge(state, scopes) {
312
- return __async(this, null, function* () {
313
- var _a;
314
- const oauth2Client = yield this.getOauth2Client();
315
- if ((_a = this.endpoints) == null ? void 0 : _a.challenge) {
316
- const challenge = yield fetch(this.endpoints.challenge).then(
317
- (res) => res.json().then((data) => data.challenge)
318
- );
319
- const oAuthUrl = yield oauth2Client.createAuthorizationURL({
320
- state,
321
- scopes
322
- });
323
- oAuthUrl.searchParams.append("code_challenge", challenge);
324
- oAuthUrl.searchParams.append("code_challenge_method", "S256");
325
- return oAuthUrl;
326
- }
327
- return oauth2Client.createAuthorizationURL({
328
- state,
329
- codeVerifier: this.codeVerifier,
330
- codeChallengeMethod: "S256",
331
- scopes
332
- });
333
- });
334
- }
335
- getAuthorizationUrl(scopes, displayMode, nonce) {
336
- return __async(this, null, function* () {
337
- const state = generateState(displayMode);
338
- const existingSessionData = this.getSessionData();
339
- this.updateSessionData(__spreadProps(__spreadValues({}, existingSessionData), {
340
- codeVerifier: this.codeVerifier,
341
- displayMode
342
- }));
343
- const oAuthUrl = yield this.getAuthorizationUrlWithChallenge(state, scopes);
344
- if (nonce) {
345
- oAuthUrl.searchParams.append("nonce", nonce);
346
- }
347
- oAuthUrl.searchParams.append("prompt", "consent");
348
- return oAuthUrl.toString();
349
- });
350
- }
351
- // TODO fix the Window reference
352
- loadAuthorizationUrl(authorizationURL, displayMode) {
353
- switch (displayMode) {
354
- case "iframe":
355
- break;
356
- case "redirect":
357
- window.location.href = authorizationURL;
358
- break;
359
- case "new_tab":
360
- window.open(authorizationURL, "_blank");
361
- break;
362
- case "custom_tab":
363
- break;
364
- }
365
- }
366
- init() {
367
- return __async(this, null, function* () {
368
- yield this.getOauth2Client();
369
- return this;
370
- });
371
- }
372
- logout() {
373
- return __async(this, null, function* () {
374
- this.updateSessionData({ authenticated: false });
375
- });
376
- }
377
- determineDisplayMode(displayMode) {
378
- if (isPopupBlocked() && displayMode === "iframe") {
379
- displayMode = "redirect";
380
- }
381
- return displayMode;
382
- }
383
- signIn(displayMode, scopes, nonce) {
384
- return __async(this, null, function* () {
385
- const authorizationURL = yield this.getAuthorizationUrl(
386
- scopes,
387
- displayMode,
388
- nonce
389
- );
390
- this.loadAuthorizationUrl(authorizationURL, displayMode);
391
- });
392
- }
393
- tokenExchange(responseUrl) {
394
- return __async(this, null, function* () {
395
- let session = this.getSessionData();
396
- if (!session.authenticated) {
397
- const url = new URL(responseUrl);
398
- const authorizationCode = url.searchParams.get("code");
399
- const returnedState = url.searchParams.get("state");
400
- if (!authorizationCode || !returnedState) {
401
- throw new Error("Invalid authorization response");
402
- }
403
- const codeVerifier = session.codeVerifier;
404
- const oauth2Client = yield this.getOauth2Client();
405
- const tokens = yield oauth2Client.validateAuthorizationCode(
406
- authorizationCode,
407
- {
408
- codeVerifier
409
- }
410
- );
411
- try {
412
- yield this.validateTokens(tokens);
413
- } catch (error) {
414
- console.error("tokenExchange tokens", { error, tokens });
415
- throw new Error(
416
- `OIDC tokens validation failed: ${error.message}`
417
- );
418
- }
419
- const parsedDisplayMode = displayModeFromState(
420
- returnedState,
421
- session.displayMode
422
- );
423
- session = __spreadProps(__spreadValues({}, session), {
424
- displayMode: parsedDisplayMode,
425
- idToken: tokens.id_token,
426
- authenticated: true,
427
- state: returnedState,
428
- accessToken: tokens.access_token,
429
- refreshToken: tokens.refresh_token,
430
- timestamp: Date.now(),
431
- expiresIn: tokens.expires_in
432
- });
433
- this.updateSessionData(session);
434
- const user = yield (yield this.getUserInfoService()).getUserInfo(tokens.access_token, tokens.id_token || null);
435
- this.setUser(user);
436
- }
437
- this.setupTokenRefresh(session);
438
- if (session.displayMode === "new_tab") {
439
- window.close();
440
- } else if (session.displayMode === "redirect") {
441
- }
442
- return session;
443
- });
444
- }
445
- setupTokenRefresh(session) {
446
- if (this.refreshTokenTimeout) {
447
- clearTimeout(this.refreshTokenTimeout);
448
- }
449
- if (session.expiresIn) {
450
- const elapsedTime = Date.now() - (session.timestamp || 0);
451
- const remainingTime = session.expiresIn * 1e3 - elapsedTime;
452
- const refreshTime = Math.max(0, remainingTime - 6e4);
453
- this.refreshTokenTimeout = setTimeout(() => {
454
- this.refreshToken().then((newSession) => {
455
- console.log("Token refreshed successfully", newSession);
456
- }).catch((error) => {
457
- console.error("Failed to refresh token:", error);
458
- this.updateSessionData({});
459
- });
460
- }, refreshTime);
461
- }
462
- }
463
- refreshToken() {
464
- return __async(this, null, function* () {
465
- const sessionData = this.getSessionData();
466
- if (!sessionData.refreshToken) {
467
- throw new Error("No refresh token available");
468
- }
469
- const oauth2Client = yield this.getOauth2Client();
470
- const tokens = yield oauth2Client.refreshAccessToken(
471
- sessionData.refreshToken
472
- );
473
- const session = __spreadProps(__spreadValues({}, sessionData), {
474
- idToken: tokens.id_token,
475
- authenticated: true,
476
- accessToken: tokens.access_token,
477
- refreshToken: tokens.refresh_token,
478
- timestamp: Date.now(),
479
- expiresIn: tokens.expires_in
480
- });
481
- this.updateSessionData(session);
482
- this.setupTokenRefresh(session);
483
- return session;
484
- });
485
- }
486
- getUserInfo() {
487
- return __async(this, null, function* () {
488
- const sessionData = this.getSessionData();
489
- if (!sessionData.accessToken) {
490
- throw new Error("No access token available");
491
- }
492
- const userInfoService = yield this.getUserInfoService();
493
- return userInfoService.getUserInfo(
494
- sessionData.accessToken,
495
- sessionData.idToken || null
496
- );
497
- });
498
- }
499
- /**
500
- * Uses the jose library to validate a JWT token using the OAuth JWKS endpoint
501
- * @returns {Promise<jose.JWTPayload>}
502
- * @throws {Error} if the token is invalid
503
- * @param tokens
504
- */
505
- validateTokens(tokens) {
506
- return __async(this, null, function* () {
507
- const endpoints = yield this.getEndpoints();
508
- if (!this.oauth2Client) yield this.init();
509
- return validateOauth2Tokens(
510
- tokens,
511
- endpoints,
512
- this.oauth2Client,
513
- this.oauthServer
514
- );
515
- });
516
- }
517
- validateExistingSession() {
518
- return __async(this, null, function* () {
519
- const sessionData = this.getSessionData();
520
- try {
521
- if (!sessionData.idToken || !sessionData.accessToken) {
522
- const unAuthenticatedSession = __spreadProps(__spreadValues({}, sessionData), { authenticated: false });
523
- this.updateSessionData(unAuthenticatedSession);
524
- return unAuthenticatedSession;
525
- }
526
- yield this.validateTokens({
527
- id_token: sessionData.idToken,
528
- access_token: sessionData.accessToken,
529
- refresh_token: sessionData.refreshToken
530
- });
531
- sessionData.authenticated = true;
532
- return sessionData;
533
- } catch (error) {
534
- console.warn("Failed to validate existing tokens", error);
535
- const unAuthenticatedSession = {
536
- authenticated: false
537
- };
538
- this.updateSessionData(unAuthenticatedSession);
539
- return unAuthenticatedSession;
540
- }
541
- });
542
- }
543
- };
544
-
545
- // src/react/components/CivicAuthIframeModal.tsx
219
+ // src/react/components/CivicAuthIframeContainer.tsx
546
220
  import { useCallback, useEffect, useRef, useState } from "react";
547
221
 
548
222
  // src/react/components/LoadingIcon.tsx
@@ -603,13 +277,12 @@ var CloseIcon = () => /* @__PURE__ */ jsxs2(
603
277
  import { forwardRef } from "react";
604
278
  import { jsx as jsx6 } from "react/jsx-runtime";
605
279
  var CivicAuthIframe = forwardRef(
606
- ({ authUrl, onLoad }, ref) => {
280
+ ({ onLoad }, ref) => {
607
281
  return /* @__PURE__ */ jsx6(
608
282
  "iframe",
609
283
  {
610
284
  id: IFRAME_ID,
611
285
  ref,
612
- src: authUrl,
613
286
  className: "cac-h-96 cac-w-80 cac-border-none",
614
287
  onLoad
615
288
  }
@@ -618,25 +291,57 @@ var CivicAuthIframe = forwardRef(
618
291
  );
619
292
  CivicAuthIframe.displayName = "CivicAuthIframe";
620
293
 
621
- // src/react/components/CivicAuthIframeModal.tsx
622
- import { jsx as jsx7, jsxs as jsxs3 } from "react/jsx-runtime";
623
- var CivicAuthIframeModal = ({
624
- authUrl,
625
- redirectUri,
626
- setAuthResponseUrl,
294
+ // src/react/components/CivicAuthIframeContainer.tsx
295
+ import { Fragment, jsx as jsx7, jsxs as jsxs3 } from "react/jsx-runtime";
296
+ function NoChrome({
297
+ children
298
+ }) {
299
+ return /* @__PURE__ */ jsx7(Fragment, { children });
300
+ }
301
+ function IframeChrome({
302
+ children,
303
+ onClose
304
+ }) {
305
+ return /* @__PURE__ */ jsx7(
306
+ "div",
307
+ {
308
+ className: "cac-absolute cac-left-0 cac-top-0 cac-z-50 cac-flex cac-h-screen cac-w-screen cac-items-center cac-justify-center cac-bg-neutral-950 cac-bg-opacity-50",
309
+ onClick: onClose,
310
+ children: /* @__PURE__ */ jsxs3(
311
+ "div",
312
+ {
313
+ className: "cac-relative cac-rounded-3xl cac-bg-white cac-p-6 cac-shadow-lg",
314
+ onClick: (e) => e.stopPropagation(),
315
+ children: [
316
+ /* @__PURE__ */ jsx7(
317
+ "button",
318
+ {
319
+ className: "cac-absolute cac-right-4 cac-top-4 cac-flex cac-cursor-pointer cac-items-center cac-justify-center cac-border-none cac-bg-transparent cac-p-1 cac-text-neutral-400",
320
+ onClick: onClose,
321
+ children: /* @__PURE__ */ jsx7(CloseIcon, {})
322
+ }
323
+ ),
324
+ children
325
+ ]
326
+ }
327
+ )
328
+ }
329
+ );
330
+ }
331
+ var CivicAuthIframeContainer = ({
627
332
  onClose,
628
- iframeRef,
629
- redirectInProgress = false,
630
333
  closeOnRedirect = true
631
334
  }) => {
632
335
  const [isLoading, setIsLoading] = useState(true);
336
+ const config = useConfig();
337
+ const { setAuthResponseUrl, iframeRef } = useSession();
633
338
  const processIframeUrl = useCallback(() => {
634
- if (iframeRef.current && iframeRef.current.contentWindow) {
339
+ if (iframeRef && iframeRef.current && iframeRef.current.contentWindow) {
635
340
  try {
636
341
  const iframeUrl = iframeRef.current.contentWindow.location.href;
637
- if (iframeUrl.startsWith(redirectUri)) {
342
+ if (iframeUrl.startsWith(config.redirectUrl)) {
638
343
  setAuthResponseUrl(iframeUrl);
639
- if (closeOnRedirect) onClose();
344
+ if (closeOnRedirect) onClose == null ? void 0 : onClose();
640
345
  return true;
641
346
  }
642
347
  } catch (e) {
@@ -644,12 +349,18 @@ var CivicAuthIframeModal = ({
644
349
  }
645
350
  }
646
351
  return false;
647
- }, [closeOnRedirect, iframeRef, onClose, redirectUri, setAuthResponseUrl]);
352
+ }, [
353
+ closeOnRedirect,
354
+ config.redirectUrl,
355
+ iframeRef,
356
+ onClose,
357
+ setAuthResponseUrl
358
+ ]);
648
359
  const intervalId = useRef();
649
360
  const handleEscape = useCallback(
650
361
  (event) => {
651
362
  if (event.key === "Escape") {
652
- onClose();
363
+ onClose == null ? void 0 : onClose();
653
364
  }
654
365
  },
655
366
  [onClose]
@@ -665,39 +376,11 @@ var CivicAuthIframeModal = ({
665
376
  clearInterval(intervalId.current);
666
377
  }
667
378
  };
668
- return /* @__PURE__ */ jsx7(
669
- "div",
670
- {
671
- className: "cac-absolute cac-left-0 cac-top-0 cac-z-50 cac-flex cac-h-screen cac-w-screen cac-items-center cac-justify-center cac-bg-neutral-950 cac-bg-opacity-50",
672
- onClick: onClose,
673
- children: /* @__PURE__ */ jsxs3(
674
- "div",
675
- {
676
- className: "cac-relative cac-rounded-3xl cac-bg-white cac-p-6 cac-shadow-lg",
677
- onClick: (e) => e.stopPropagation(),
678
- children: [
679
- /* @__PURE__ */ jsx7(
680
- "button",
681
- {
682
- className: "cac-absolute cac-right-4 cac-top-4 cac-flex cac-cursor-pointer cac-items-center cac-justify-center cac-border-none cac-bg-transparent cac-p-1 cac-text-neutral-400",
683
- onClick: onClose,
684
- children: /* @__PURE__ */ jsx7(CloseIcon, {})
685
- }
686
- ),
687
- (isLoading || redirectInProgress) && /* @__PURE__ */ jsx7("div", { className: "cac-absolute cac-inset-0 cac-flex cac-items-center cac-justify-center cac-rounded-3xl cac-bg-neutral-100", children: /* @__PURE__ */ jsx7(LoadingIcon, {}) }),
688
- /* @__PURE__ */ jsx7(
689
- CivicAuthIframe,
690
- {
691
- ref: iframeRef,
692
- authUrl,
693
- onLoad: handleIframeLoad
694
- }
695
- )
696
- ]
697
- }
698
- )
699
- }
700
- );
379
+ const WrapperComponent = config.modalIframe ? IframeChrome : NoChrome;
380
+ return /* @__PURE__ */ jsxs3(WrapperComponent, { onClose, children: [
381
+ isLoading && /* @__PURE__ */ jsx7("div", { className: "cac-absolute cac-inset-0 cac-flex cac-items-center cac-justify-center cac-rounded-3xl cac-bg-neutral-100", children: /* @__PURE__ */ jsx7(LoadingIcon, {}) }),
382
+ /* @__PURE__ */ jsx7(CivicAuthIframe, { ref: iframeRef, onLoad: handleIframeLoad })
383
+ ] });
701
384
  };
702
385
 
703
386
  // src/config.ts
@@ -706,23 +389,30 @@ var authConfig = {
706
389
  oauthServer: "https://auth-dev.civic.com/oauth/"
707
390
  };
708
391
 
709
- // src/lib/windowUtil.ts
710
- var isWindowInIframe = (window2) => {
711
- var _a;
712
- if (typeof window2 !== "undefined") {
713
- try {
714
- if (((_a = window2 == null ? void 0 : window2.frameElement) == null ? void 0 : _a.id) === "civic-auth-iframe") {
715
- return true;
716
- }
717
- } catch (_e) {
718
- return false;
719
- }
720
- }
721
- return false;
392
+ // src/react/providers/ConfigProvider.tsx
393
+ import { createContext as createContext5 } from "react";
394
+ import { jsx as jsx8 } from "react/jsx-runtime";
395
+ var defaultConfig = {
396
+ config: authConfig,
397
+ redirectUrl: "",
398
+ modalIframe: true
722
399
  };
400
+ var ConfigContext = createContext5(defaultConfig);
401
+ var ConfigProvider = ({
402
+ children,
403
+ config,
404
+ redirectUrl,
405
+ modalIframe
406
+ }) => /* @__PURE__ */ jsx8(
407
+ ConfigContext.Provider,
408
+ {
409
+ value: { config, redirectUrl, modalIframe: !!modalIframe },
410
+ children
411
+ }
412
+ );
723
413
 
724
414
  // src/shared/AuthProvider.tsx
725
- import { jsx as jsx8, jsxs as jsxs4 } from "react/jsx-runtime";
415
+ import { jsx as jsx9, jsxs as jsxs4 } from "react/jsx-runtime";
726
416
  var globalThisObject;
727
417
  if (typeof window !== "undefined") {
728
418
  globalThisObject = window;
@@ -732,24 +422,32 @@ if (typeof window !== "undefined") {
732
422
  globalThisObject = Function("return this")();
733
423
  }
734
424
  globalThisObject.globalThis = globalThisObject;
425
+ function BlockDisplay({ children }) {
426
+ return /* @__PURE__ */ jsx9("div", { className: "cac-absolute cac-left-0 cac-top-0 cac-z-50 cac-flex cac-h-screen cac-w-screen cac-items-center cac-justify-center cac-bg-white", children: /* @__PURE__ */ jsx9("div", { className: "cac-absolute cac-inset-0 cac-flex cac-items-center cac-justify-center cac-bg-white", children }) });
427
+ }
735
428
  var AuthProvider = ({
736
429
  children,
737
430
  clientId,
738
431
  redirectUrl: inputRedirectUrl,
739
432
  config = authConfig,
740
- nonce,
741
433
  onSignIn,
742
434
  onSignOut,
743
- authServiceImpl,
744
- serverSideTokenExchange
435
+ pkceConsumer,
436
+ nonce,
437
+ modalIframe = true
745
438
  }) => {
746
439
  const [iframeUrl, setIframeUrl] = useState2(null);
747
440
  const [currentUrl, setCurrentUrl] = useState2(null);
748
441
  const [isInIframe, setIsInIframe] = useState2(false);
749
442
  const [authResponseUrl, setAuthResponseUrl] = useState2(null);
750
443
  const [tokenExchangeError, setTokenExchangeError] = useState2();
444
+ const [displayMode, setDisplayMode] = useState2("iframe");
445
+ const [browserAuthenticationInitiator, setBrowserAuthenticationInitiator] = useState2();
446
+ const [showIFrame, setShowIFrame] = useState2(false);
447
+ const [isRedirecting, setIsRedirecting] = useState2(false);
751
448
  const queryClient3 = useQueryClient2();
752
449
  const iframeRef = useRef2(null);
450
+ const serverBasedPKCE = pkceConsumer instanceof ConfidentialClientPKCEConsumer;
753
451
  useEffect2(() => {
754
452
  if (typeof globalThis.window !== "undefined") {
755
453
  setCurrentUrl(globalThis.window.location.href);
@@ -761,26 +459,30 @@ var AuthProvider = ({
761
459
  () => (inputRedirectUrl || currentUrl || "").split("?")[0],
762
460
  [currentUrl, inputRedirectUrl]
763
461
  );
764
- const authService = useMemo2(
765
- () => currentUrl ? authServiceImpl || new AuthSessionServiceImpl(
462
+ const [authService, setAuthService] = useState2();
463
+ useEffect2(() => {
464
+ if (!currentUrl) return;
465
+ BrowserAuthenticationService.build({
766
466
  clientId,
767
467
  redirectUrl,
768
- config == null ? void 0 : config.oauthServer,
769
- config == null ? void 0 : config.endpoints
770
- ) : null,
771
- [currentUrl, clientId, redirectUrl, config, authServiceImpl]
772
- );
773
- const [userInfoService, setUserInfoService] = useState2();
774
- useEffect2(() => {
775
- if (!authService) return;
776
- authService.getUserInfoService().then(setUserInfoService);
777
- }, [authService]);
468
+ oauthServer: config.oauthServer,
469
+ scopes: DEFAULT_SCOPES,
470
+ displayMode
471
+ }).then(setAuthService);
472
+ }, [currentUrl, clientId, redirectUrl, config, displayMode]);
778
473
  const {
779
474
  data: session,
780
475
  isLoading,
781
476
  error
782
477
  } = useQuery2({
783
- queryKey: ["session", authResponseUrl, iframeUrl, currentUrl, isInIframe],
478
+ queryKey: [
479
+ "session",
480
+ authResponseUrl,
481
+ iframeUrl,
482
+ currentUrl,
483
+ isInIframe,
484
+ authService
485
+ ],
784
486
  queryFn: () => __async(void 0, null, function* () {
785
487
  if (!authService) {
786
488
  return { authenticated: false };
@@ -789,12 +491,24 @@ var AuthProvider = ({
789
491
  authResponseUrl ? authResponseUrl : globalThis.window.location.href || ""
790
492
  );
791
493
  const code = url.searchParams.get("code");
792
- if (code && !isInIframe && !serverSideTokenExchange) {
494
+ const state = url.searchParams.get("state");
495
+ if (!serverBasedPKCE && code && state && !isInIframe) {
793
496
  try {
794
- console.log("AuthProvider useQuery code", { isInIframe, code });
795
- const newSession = yield authService.tokenExchange(url.toString());
497
+ console.log("AuthProvider useQuery code", {
498
+ isInIframe,
499
+ code,
500
+ state
501
+ });
502
+ yield authService.tokenExchange(code, state);
503
+ const clientStorage = new LocalStorageAdapter();
504
+ const user = yield getUser(clientStorage);
505
+ if (!user) {
506
+ throw new Error("Failed to get user info");
507
+ }
508
+ const userSession = new GenericUserSession(clientStorage);
509
+ userSession.set(user);
796
510
  onSignIn == null ? void 0 : onSignIn();
797
- return newSession;
511
+ return authService.getSessionData();
798
512
  } catch (error2) {
799
513
  setTokenExchangeError(error2);
800
514
  onSignIn == null ? void 0 : onSignIn(
@@ -812,39 +526,90 @@ var AuthProvider = ({
812
526
  });
813
527
  const signOutMutation = useMutation2({
814
528
  mutationFn: () => __async(void 0, null, function* () {
815
- authService == null ? void 0 : authService.updateSessionData({});
529
+ const authInitiator = getAuthInitiator();
530
+ authInitiator == null ? void 0 : authInitiator.signOut();
816
531
  setIframeUrl(null);
532
+ setShowIFrame(false);
817
533
  setAuthResponseUrl(null);
818
534
  onSignOut == null ? void 0 : onSignOut();
819
535
  }),
820
536
  onSuccess: () => {
821
537
  queryClient3.setQueryData(
822
- ["session", authResponseUrl, iframeUrl, currentUrl, isInIframe],
538
+ [
539
+ "session",
540
+ authResponseUrl,
541
+ iframeUrl,
542
+ currentUrl,
543
+ isInIframe,
544
+ authService
545
+ ],
823
546
  null
824
547
  );
825
548
  }
826
549
  });
550
+ const getAuthInitiator = useCallback2(
551
+ (overrideDisplayMode) => {
552
+ const useDisplayMode = overrideDisplayMode || displayMode;
553
+ if (!pkceConsumer) {
554
+ return null;
555
+ }
556
+ return browserAuthenticationInitiator || new BrowserAuthenticationInitiator({
557
+ pkceConsumer,
558
+ // generate and retrieve the challenge client-side
559
+ clientId,
560
+ redirectUrl,
561
+ state: generateState(useDisplayMode),
562
+ scopes: DEFAULT_SCOPES,
563
+ displayMode: useDisplayMode,
564
+ oauthServer: config.oauthServer,
565
+ // the endpoints to use for the login (if not obtained from the auth server
566
+ endpointOverrides: config.endpoints,
567
+ nonce
568
+ });
569
+ },
570
+ [
571
+ displayMode,
572
+ browserAuthenticationInitiator,
573
+ clientId,
574
+ redirectUrl,
575
+ config.oauthServer,
576
+ config.endpoints,
577
+ pkceConsumer,
578
+ nonce
579
+ ]
580
+ );
827
581
  const signIn = useCallback2(
828
582
  (overrideDisplayMode = "iframe") => __async(void 0, null, function* () {
829
- if (!authService) return;
830
- const url = yield authService.getAuthorizationUrl(
831
- // This is the default scope. We will eventually pull this from the partner dashboard
832
- DEFAULT_SCOPES,
833
- overrideDisplayMode,
834
- nonce
835
- );
583
+ setDisplayMode(overrideDisplayMode);
584
+ const authInitiator = getAuthInitiator(overrideDisplayMode);
585
+ setBrowserAuthenticationInitiator(authInitiator);
836
586
  if (overrideDisplayMode === "iframe") {
837
- setIframeUrl(url);
838
- return;
587
+ setShowIFrame(true);
588
+ } else if (overrideDisplayMode === "redirect") {
589
+ setIsRedirecting(true);
839
590
  }
840
- authService.loadAuthorizationUrl(url, overrideDisplayMode);
591
+ authInitiator == null ? void 0 : authInitiator.signIn(iframeRef.current);
841
592
  }),
842
- [authService, nonce]
593
+ [getAuthInitiator]
843
594
  );
844
595
  const isAuthenticated = useMemo2(
845
596
  () => session ? session.authenticated : false,
846
597
  [session]
847
598
  );
599
+ const {
600
+ data: autoSignIn,
601
+ isLoading: autoSignInLoading,
602
+ error: autoSignInError
603
+ } = useQuery2({
604
+ queryKey: ["autoSignIn", modalIframe, redirectUrl, isAuthenticated],
605
+ queryFn: () => __async(void 0, null, function* () {
606
+ if (!modalIframe && redirectUrl && !isAuthenticated && iframeRef.current) {
607
+ signIn("iframe");
608
+ }
609
+ return true;
610
+ }),
611
+ refetchOnWindowFocus: false
612
+ });
848
613
  const value = useMemo2(
849
614
  () => ({
850
615
  isLoading,
@@ -857,37 +622,57 @@ var AuthProvider = ({
857
622
  }),
858
623
  [isLoading, error, signOutMutation, isAuthenticated, signIn]
859
624
  );
860
- return /* @__PURE__ */ jsx8(AuthContext.Provider, { value, children: /* @__PURE__ */ jsx8(SessionProvider, { session, children: /* @__PURE__ */ jsx8(TokenProvider, { children: /* @__PURE__ */ jsxs4(UserProvider, { userInfoService, children: [
861
- !isInIframe && iframeUrl && !(session == null ? void 0 : session.authenticated) && /* @__PURE__ */ jsx8(
862
- CivicAuthIframeModal,
863
- {
864
- iframeRef,
865
- authUrl: iframeUrl,
866
- redirectUri: redirectUrl,
867
- setAuthResponseUrl,
868
- onClose: () => setIframeUrl(null)
869
- }
870
- ),
871
- (tokenExchangeError || isLoading || error || isInIframe && !(tokenExchangeError || error)) && /* @__PURE__ */ jsx8("div", { className: "cac-absolute cac-left-0 cac-top-0 cac-z-50 cac-flex cac-h-screen cac-w-screen cac-items-center cac-justify-center cac-bg-white", children: /* @__PURE__ */ jsx8("div", { className: "cac-absolute cac-inset-0 cac-flex cac-items-center cac-justify-center cac-bg-white", children: tokenExchangeError || error ? /* @__PURE__ */ jsxs4("div", { children: [
872
- "Error: ",
873
- (tokenExchangeError || error).message
874
- ] }) : /* @__PURE__ */ jsx8(LoadingIcon, {}) }) }),
875
- children
876
- ] }) }) }) });
625
+ return /* @__PURE__ */ jsx9(AuthContext.Provider, { value, children: /* @__PURE__ */ jsx9(
626
+ ConfigProvider,
627
+ {
628
+ config,
629
+ redirectUrl,
630
+ modalIframe,
631
+ children: /* @__PURE__ */ jsx9(
632
+ SessionProvider,
633
+ {
634
+ session,
635
+ setAuthResponseUrl,
636
+ iframeRef,
637
+ children: /* @__PURE__ */ jsx9(TokenProvider, { children: /* @__PURE__ */ jsxs4(UserProvider, { storage: new LocalStorageAdapter(), children: [
638
+ modalIframe && !isInIframe && !(session == null ? void 0 : session.authenticated) && /* @__PURE__ */ jsx9(
639
+ "div",
640
+ {
641
+ style: showIFrame ? { display: "block" } : { display: "none" },
642
+ children: /* @__PURE__ */ jsx9(CivicAuthIframeContainer, { onClose: () => setShowIFrame(false) })
643
+ }
644
+ ),
645
+ modalIframe && (isInIframe || isRedirecting || isLoading) && /* @__PURE__ */ jsx9(BlockDisplay, { children: /* @__PURE__ */ jsx9(LoadingIcon, {}) }),
646
+ (tokenExchangeError || error) && /* @__PURE__ */ jsx9(BlockDisplay, { children: /* @__PURE__ */ jsxs4("div", { children: [
647
+ "Error: ",
648
+ (tokenExchangeError || error).message
649
+ ] }) }),
650
+ children
651
+ ] }) })
652
+ }
653
+ )
654
+ }
655
+ ) });
877
656
  };
878
657
 
879
658
  // src/shared/CivicAuthProvider.tsx
880
659
  import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
881
660
  import "@civic/auth/styles.css";
882
- import { jsx as jsx9 } from "react/jsx-runtime";
661
+ import { jsx as jsx10 } from "react/jsx-runtime";
883
662
  var queryClient = new QueryClient();
884
663
  var CivicAuthProvider = (_a) => {
885
664
  var _b = _a, { children } = _b, props = __objRest(_b, ["children"]);
886
- return /* @__PURE__ */ jsx9(QueryClientProvider, { client: queryClient, children: /* @__PURE__ */ jsx9(AuthProvider, __spreadProps(__spreadValues({}, props), { children })) });
665
+ return /* @__PURE__ */ jsx10(QueryClientProvider, { client: queryClient, children: /* @__PURE__ */ jsx10(
666
+ AuthProvider,
667
+ __spreadProps(__spreadValues({}, props), {
668
+ pkceConsumer: new BrowserPublicClientPKCEProducer(),
669
+ children
670
+ })
671
+ ) });
887
672
  };
888
673
 
889
674
  // src/react/providers/NextAuthProvider.tsx
890
- import { createContext as createContext5, useContext as useContext4, useEffect as useEffect4, useMemo as useMemo3, useState as useState3 } from "react";
675
+ import { createContext as createContext6, useContext as useContext4, useEffect as useEffect4, useState as useState3 } from "react";
891
676
 
892
677
  // src/react/hooks/useUserCookie.ts
893
678
  import { useEffect as useEffect3, useRef as useRef3 } from "react";
@@ -901,7 +686,7 @@ var getCookieValue = (key, window2) => {
901
686
  const cookies = cookie.split(";");
902
687
  for (const c of cookies) {
903
688
  const [name, value] = c.trim().split("=");
904
- if (name === key) {
689
+ if (value && name === key) {
905
690
  try {
906
691
  return JSON.parse(decodeURIComponent(value));
907
692
  } catch (e) {
@@ -945,10 +730,10 @@ var useUserCookie = () => {
945
730
  // src/react/providers/NextAuthProvider.tsx
946
731
  import { QueryClient as QueryClient2, QueryClientProvider as QueryClientProvider2 } from "@tanstack/react-query";
947
732
  import "@civic/auth/styles.css";
948
- import { jsx as jsx10 } from "react/jsx-runtime";
733
+ import { jsx as jsx11 } from "react/jsx-runtime";
949
734
  var queryClient2 = new QueryClient2();
950
735
  var defaultUserContext = { user: null };
951
- var UserContext2 = createContext5(defaultUserContext);
736
+ var UserContext2 = createContext6(defaultUserContext);
952
737
  var CivicNextAuthProvider = (_a) => {
953
738
  var _b = _a, {
954
739
  children
@@ -964,22 +749,14 @@ var CivicNextAuthProvider = (_a) => {
964
749
  setRedirectUrl(resolveCallbackUrl(resolveAuthConfig(), currentUrl));
965
750
  }
966
751
  }, [callbackUrl]);
967
- const authService = useMemo3(() => {
968
- if (redirectUrl && clientId && oauthServer) {
969
- return new AuthSessionServiceImpl(clientId, redirectUrl, oauthServer, {
970
- challenge: challengeUrl
971
- });
972
- }
973
- return void 0;
974
- }, [redirectUrl, clientId, oauthServer, challengeUrl]);
975
- return /* @__PURE__ */ jsx10(QueryClientProvider2, { client: queryClient2, children: /* @__PURE__ */ jsx10(
752
+ return /* @__PURE__ */ jsx11(QueryClientProvider2, { client: queryClient2, children: /* @__PURE__ */ jsx11(
976
753
  AuthProvider,
977
754
  __spreadProps(__spreadValues({}, props), {
755
+ redirectUrl,
978
756
  config: { oauthServer },
979
757
  clientId,
980
- authServiceImpl: authService,
981
- serverSideTokenExchange: true,
982
- children: /* @__PURE__ */ jsx10(UserContext2.Provider, { value: user, children })
758
+ pkceConsumer: new ConfidentialClientPKCEConsumer(challengeUrl),
759
+ children: /* @__PURE__ */ jsx11(UserContext2.Provider, { value: user, children })
983
760
  })
984
761
  ) });
985
762
  };
@@ -994,10 +771,20 @@ var useUser = () => {
994
771
  return context;
995
772
  };
996
773
 
774
+ // src/react/hooks/useConfig.tsx
775
+ import { useContext as useContext6 } from "react";
776
+ var useConfig = () => {
777
+ const context = useContext6(ConfigContext);
778
+ if (!context) {
779
+ throw new Error("useConfig must be used within an ConfigProvider");
780
+ }
781
+ return context;
782
+ };
783
+
997
784
  // src/react/components/UserButton.tsx
998
785
  import { useCallback as useCallback3, useEffect as useEffect5, useState as useState4 } from "react";
999
- import { jsx as jsx11, jsxs as jsxs5 } from "react/jsx-runtime";
1000
- var ChevronDown = () => /* @__PURE__ */ jsx11(
786
+ import { jsx as jsx12, jsxs as jsxs5 } from "react/jsx-runtime";
787
+ var ChevronDown = () => /* @__PURE__ */ jsx12(
1001
788
  "svg",
1002
789
  {
1003
790
  xmlns: "http://www.w3.org/2000/svg",
@@ -1010,10 +797,10 @@ var ChevronDown = () => /* @__PURE__ */ jsx11(
1010
797
  strokeLinecap: "round",
1011
798
  strokeLinejoin: "round",
1012
799
  className: "lucide lucide-chevron-down",
1013
- children: /* @__PURE__ */ jsx11("path", { d: "m6 9 6 6 6-6" })
800
+ children: /* @__PURE__ */ jsx12("path", { d: "m6 9 6 6 6-6" })
1014
801
  }
1015
802
  );
1016
- var ChevronUp = () => /* @__PURE__ */ jsx11(
803
+ var ChevronUp = () => /* @__PURE__ */ jsx12(
1017
804
  "svg",
1018
805
  {
1019
806
  xmlns: "http://www.w3.org/2000/svg",
@@ -1026,7 +813,7 @@ var ChevronUp = () => /* @__PURE__ */ jsx11(
1026
813
  strokeLinecap: "round",
1027
814
  strokeLinejoin: "round",
1028
815
  className: "lucide lucide-chevron-up",
1029
- children: /* @__PURE__ */ jsx11("path", { d: "m18 15-6-6-6 6" })
816
+ children: /* @__PURE__ */ jsx12("path", { d: "m18 15-6-6-6 6" })
1030
817
  }
1031
818
  );
1032
819
  var UserButton = ({
@@ -1076,24 +863,24 @@ var UserButton = ({
1076
863
  ),
1077
864
  onClick: () => setIsOpen((isOpen2) => !isOpen2),
1078
865
  children: [
1079
- (user == null ? void 0 : user.picture) ? /* @__PURE__ */ jsx11("span", { className: "cac-relative cac-flex cac-h-10 cac-w-10 cac-shrink-0 cac-gap-2 cac-overflow-hidden cac-rounded-full", children: /* @__PURE__ */ jsx11(
866
+ (user == null ? void 0 : user.picture) ? /* @__PURE__ */ jsx12("span", { className: "cac-relative cac-flex cac-h-10 cac-w-10 cac-shrink-0 cac-gap-2 cac-overflow-hidden cac-rounded-full", children: /* @__PURE__ */ jsx12(
1080
867
  "img",
1081
868
  {
1082
869
  className: "cac-h-full cac-w-full cac-object-cover",
1083
870
  src: user.picture,
1084
871
  alt: (user == null ? void 0 : user.name) || (user == null ? void 0 : user.email)
1085
872
  }
1086
- ) }) : /* @__PURE__ */ jsx11("div", {}),
1087
- /* @__PURE__ */ jsx11("span", { children: (user == null ? void 0 : user.name) || (user == null ? void 0 : user.email) }),
1088
- isOpen ? /* @__PURE__ */ jsx11(ChevronUp, {}) : /* @__PURE__ */ jsx11(ChevronDown, {})
873
+ ) }) : /* @__PURE__ */ jsx12("div", {}),
874
+ /* @__PURE__ */ jsx12("span", { children: (user == null ? void 0 : user.name) || (user == null ? void 0 : user.email) }),
875
+ isOpen ? /* @__PURE__ */ jsx12(ChevronUp, {}) : /* @__PURE__ */ jsx12(ChevronDown, {})
1089
876
  ]
1090
877
  }
1091
878
  ),
1092
- /* @__PURE__ */ jsx11(
879
+ /* @__PURE__ */ jsx12(
1093
880
  "div",
1094
881
  {
1095
882
  className: isOpen ? "cac-absolute cac-right-0 cac-mt-2 cac-w-full cac-rounded-lg cac-bg-white cac-py-2 cac-text-neutral-500 cac-shadow-xl" : "cac-hidden",
1096
- children: /* @__PURE__ */ jsx11("ul", { children: /* @__PURE__ */ jsx11("li", { children: /* @__PURE__ */ jsx11(
883
+ children: /* @__PURE__ */ jsx12("ul", { children: /* @__PURE__ */ jsx12("li", { children: /* @__PURE__ */ jsx12(
1097
884
  "button",
1098
885
  {
1099
886
  className: "cac-block cac-w-full cac-px-4 cac-py-2 cac-transition-colors hover:cac-bg-neutral-200 hover:cac-bg-opacity-50",
@@ -1105,9 +892,10 @@ var UserButton = ({
1105
892
  )
1106
893
  ] });
1107
894
  }
1108
- return /* @__PURE__ */ jsx11(
895
+ return /* @__PURE__ */ jsx12(
1109
896
  "button",
1110
897
  {
898
+ "data-testid": "sign-in-button",
1111
899
  className: cn(
1112
900
  "cac-rounded-full cac-border cac-border-neutral-500 cac-px-3 cac-py-2 cac-transition-colors hover:cac-bg-neutral-200 hover:cac-bg-opacity-50",
1113
901
  className
@@ -1119,15 +907,16 @@ var UserButton = ({
1119
907
  };
1120
908
 
1121
909
  // src/react/components/SignInButton.tsx
1122
- import { jsx as jsx12 } from "react/jsx-runtime";
910
+ import { jsx as jsx13 } from "react/jsx-runtime";
1123
911
  var SignInButton = ({
1124
912
  displayMode,
1125
913
  className
1126
914
  }) => {
1127
915
  const { signIn } = useAuth();
1128
- return /* @__PURE__ */ jsx12(
916
+ return /* @__PURE__ */ jsx13(
1129
917
  "button",
1130
918
  {
919
+ "data-testid": "sign-in-button",
1131
920
  className: cn(
1132
921
  "cac-rounded-full cac-border cac-border-neutral-500 cac-px-3 cac-py-2 cac-transition-colors hover:cac-bg-neutral-200 hover:cac-bg-opacity-50",
1133
922
  className
@@ -1139,10 +928,10 @@ var SignInButton = ({
1139
928
  };
1140
929
 
1141
930
  // src/react/components/SignOutButton.tsx
1142
- import { jsx as jsx13 } from "react/jsx-runtime";
931
+ import { jsx as jsx14 } from "react/jsx-runtime";
1143
932
  var SignOutButton = ({ className }) => {
1144
933
  const { signOut } = useAuth();
1145
- return /* @__PURE__ */ jsx13(
934
+ return /* @__PURE__ */ jsx14(
1146
935
  "button",
1147
936
  {
1148
937
  className: cn(
@@ -1156,13 +945,14 @@ var SignOutButton = ({ className }) => {
1156
945
  };
1157
946
 
1158
947
  // src/react/components/NextLogOut.tsx
1159
- import { jsx as jsx14 } from "react/jsx-runtime";
948
+ import { jsx as jsx15 } from "react/jsx-runtime";
1160
949
  var NextLogOut = ({ children }) => {
1161
950
  const config = resolveAuthConfig();
1162
951
  const logoutUrl = `${config.logoutUrl}`;
1163
- return /* @__PURE__ */ jsx14("a", { href: logoutUrl, children });
952
+ return /* @__PURE__ */ jsx15("a", { href: logoutUrl, children });
1164
953
  };
1165
954
  export {
955
+ CivicAuthIframeContainer,
1166
956
  CivicAuthProvider,
1167
957
  CivicNextAuthProvider,
1168
958
  NextLogOut,
@@ -1170,6 +960,7 @@ export {
1170
960
  SignOutButton,
1171
961
  UserButton,
1172
962
  useAuth,
963
+ useConfig,
1173
964
  useNextUser,
1174
965
  useSession,
1175
966
  useToken,