@civic/auth 0.0.1-beta.1 → 0.0.1-beta.10

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 (45) hide show
  1. package/README.md +26 -0
  2. package/dist/chunk-CRTRMMJ7.js +59 -0
  3. package/dist/chunk-CRTRMMJ7.js.map +1 -0
  4. package/dist/chunk-EAANLFR5.mjs +148 -0
  5. package/dist/chunk-EAANLFR5.mjs.map +1 -0
  6. package/dist/chunk-EGFTMH5S.mjs +214 -0
  7. package/dist/chunk-EGFTMH5S.mjs.map +1 -0
  8. package/dist/chunk-KCSGIIPA.js +214 -0
  9. package/dist/chunk-KCSGIIPA.js.map +1 -0
  10. package/dist/chunk-MVO4UZ2A.js +148 -0
  11. package/dist/chunk-MVO4UZ2A.js.map +1 -0
  12. package/dist/chunk-PMDIR5XE.mjs +502 -0
  13. package/dist/chunk-PMDIR5XE.mjs.map +1 -0
  14. package/dist/chunk-RGHW4PYM.mjs +59 -0
  15. package/dist/chunk-RGHW4PYM.mjs.map +1 -0
  16. package/dist/chunk-YNLXRD5L.js +502 -0
  17. package/dist/chunk-YNLXRD5L.js.map +1 -0
  18. package/dist/{index-DFVNodC9.d.mts → index-Bfi0hVMZ.d.mts} +5 -13
  19. package/dist/{index-DFVNodC9.d.ts → index-Bfi0hVMZ.d.ts} +5 -13
  20. package/dist/index.css +63 -63
  21. package/dist/index.css.map +1 -1
  22. package/dist/index.d.mts +1 -1
  23. package/dist/index.d.ts +1 -1
  24. package/dist/index.js +1 -19
  25. package/dist/index.js.map +1 -1
  26. package/dist/index.mjs +1 -1
  27. package/dist/nextjs.d.mts +22 -37
  28. package/dist/nextjs.d.ts +22 -37
  29. package/dist/nextjs.js +166 -848
  30. package/dist/nextjs.js.map +1 -1
  31. package/dist/nextjs.mjs +162 -805
  32. package/dist/nextjs.mjs.map +1 -1
  33. package/dist/react.d.mts +42 -58
  34. package/dist/react.d.ts +42 -58
  35. package/dist/react.js +668 -1103
  36. package/dist/react.js.map +1 -1
  37. package/dist/react.mjs +608 -1005
  38. package/dist/react.mjs.map +1 -1
  39. package/dist/server.d.mts +56 -0
  40. package/dist/server.d.ts +56 -0
  41. package/dist/server.js +20 -0
  42. package/dist/server.js.map +1 -0
  43. package/dist/server.mjs +20 -0
  44. package/dist/server.mjs.map +1 -0
  45. package/package.json +28 -18
package/dist/nextjs.mjs CHANGED
@@ -1,824 +1,75 @@
1
- "use server";
2
- var __defProp = Object.defineProperty;
3
- var __defProps = Object.defineProperties;
4
- var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
5
- var __getOwnPropSymbols = Object.getOwnPropertySymbols;
6
- var __hasOwnProp = Object.prototype.hasOwnProperty;
7
- var __propIsEnum = Object.prototype.propertyIsEnumerable;
8
- var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
9
- var __spreadValues = (a, b) => {
10
- for (var prop in b || (b = {}))
11
- if (__hasOwnProp.call(b, prop))
12
- __defNormalProp(a, prop, b[prop]);
13
- if (__getOwnPropSymbols)
14
- for (var prop of __getOwnPropSymbols(b)) {
15
- if (__propIsEnum.call(b, prop))
16
- __defNormalProp(a, prop, b[prop]);
17
- }
18
- return a;
19
- };
20
- var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
21
- var __async = (__this, __arguments, generator) => {
22
- return new Promise((resolve, reject) => {
23
- var fulfilled = (value) => {
24
- try {
25
- step(generator.next(value));
26
- } catch (e) {
27
- reject(e);
28
- }
29
- };
30
- var rejected = (value) => {
31
- try {
32
- step(generator.throw(value));
33
- } catch (e) {
34
- reject(e);
35
- }
36
- };
37
- var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
38
- step((generator = generator.apply(__this, __arguments)).next());
39
- });
40
- };
41
-
42
- // src/lib/logger.ts
43
- import debug from "debug";
44
- var PACKAGE_NAME = "@civic/auth";
45
- var DebugLogger = class {
46
- constructor(namespace) {
47
- this.debugLogger = debug(`${PACKAGE_NAME}:${namespace}:debug`);
48
- this.infoLogger = debug(`${PACKAGE_NAME}:${namespace}:info`);
49
- this.warnLogger = debug(`${PACKAGE_NAME}:${namespace}:warn`);
50
- this.errorLogger = debug(`${PACKAGE_NAME}:${namespace}:error`);
51
- this.debugLogger.color = "4";
52
- this.infoLogger.color = "2";
53
- this.warnLogger.color = "3";
54
- this.errorLogger.color = "1";
55
- }
56
- debug(message, ...args) {
57
- this.debugLogger(message, ...args);
58
- }
59
- info(message, ...args) {
60
- this.infoLogger(message, ...args);
61
- }
62
- warn(message, ...args) {
63
- this.warnLogger(message, ...args);
64
- }
65
- error(message, ...args) {
66
- this.errorLogger(message, ...args);
67
- }
68
- };
69
- var createLogger = (namespace) => new DebugLogger(namespace);
70
- var loggers = {
71
- // Next.js specific loggers
72
- nextjs: {
73
- routes: createLogger("api:routes"),
74
- middleware: createLogger("api:middleware"),
75
- handlers: {
76
- auth: createLogger("api:handlers:auth")
77
- }
78
- },
79
- // React specific loggers
80
- react: {
81
- components: createLogger("react:components"),
82
- hooks: createLogger("react:hooks"),
83
- context: createLogger("react:context")
84
- },
85
- // Shared utilities loggers
86
- services: {
87
- validation: createLogger("utils:validation"),
88
- network: createLogger("utils:network")
89
- }
90
- };
91
-
92
- // src/nextjs/config.ts
93
- var logger = loggers.nextjs.handlers.auth;
94
- var defaultAuthConfig = {
95
- oauthServer: "https://auth-dev.civic.com/oauth",
96
- callbackUrl: "/api/auth/callback",
97
- challengeUrl: "/api/auth/challenge",
98
- logoutUrl: "/api/auth/logout",
99
- loginUrl: "/",
100
- include: ["/*"],
101
- exclude: [],
102
- cookies: {
103
- tokens: {
104
- sameSite: "strict",
105
- path: "/",
106
- maxAge: 60 * 60
107
- // 1 hour
108
- },
109
- user: {
110
- sameSite: "strict",
111
- path: "/",
112
- maxAge: 60 * 60
113
- // 1 hour
114
- }
115
- }
116
- };
117
- var withoutUndefined = (obj) => {
118
- const result = {};
119
- for (const key in obj) {
120
- if (obj[key] !== void 0) {
121
- result[key] = obj[key];
122
- }
123
- }
124
- return result;
125
- };
126
- var resolveAuthConfig = (config = {}) => {
127
- var _a, _b, _c, _d;
128
- const configFromEnv = withoutUndefined({
129
- clientId: process.env._civic_auth_client_id,
130
- oauthServer: process.env._civic_oauth_server,
131
- callbackUrl: process.env._civic_auth_callback_url,
132
- loginUrl: process.env._civic_auth_login_url,
133
- logoutUrl: process.env._civic_auth_logout_url,
134
- include: (_a = process.env._civic_auth_includes) == null ? void 0 : _a.split(","),
135
- exclude: (_b = process.env._civic_auth_excludes) == null ? void 0 : _b.split(","),
136
- cookies: process.env._civic_auth_cookie_config ? JSON.parse(process.env._civic_auth_cookie_config) : void 0
137
- });
138
- const mergedConfig = __spreadProps(__spreadValues(__spreadValues(__spreadValues({}, defaultAuthConfig), configFromEnv), config), {
139
- // Override with directly passed config
140
- cookies: {
141
- tokens: __spreadValues(__spreadValues({}, defaultAuthConfig.cookies.tokens), ((_c = config.cookies) == null ? void 0 : _c.tokens) || {}),
142
- user: __spreadValues(__spreadValues({}, defaultAuthConfig.cookies.user), ((_d = config.cookies) == null ? void 0 : _d.user) || {})
143
- }
144
- });
145
- logger.debug("Config from environment:", configFromEnv);
146
- logger.debug("Resolved config:", mergedConfig);
147
- if (mergedConfig.clientId === void 0) {
148
- throw new Error("Civic Auth client ID is required");
149
- }
150
- return mergedConfig;
151
- };
152
- var createCivicAuthPlugin = (clientId, authConfig = {}) => {
153
- return (nextConfig) => {
154
- const resolvedConfig = resolveAuthConfig(__spreadProps(__spreadValues({}, authConfig), { clientId }));
155
- return __spreadProps(__spreadValues({}, nextConfig), {
156
- env: __spreadProps(__spreadValues({}, nextConfig == null ? void 0 : nextConfig.env), {
157
- // Internal environment variables - do not set these manually
158
- _civic_auth_client_id: clientId,
159
- _civic_oauth_server: resolvedConfig.oauthServer,
160
- _civic_auth_callback_url: resolvedConfig.callbackUrl,
161
- _civic_auth_login_url: resolvedConfig.loginUrl,
162
- _civic_auth_logout_url: resolvedConfig.logoutUrl,
163
- _civic_auth_includes: resolvedConfig.include.join(","),
164
- _civic_auth_excludes: resolvedConfig.exclude.join(","),
165
- _civic_auth_cookie_config: JSON.stringify(resolvedConfig.cookies)
166
- })
167
- });
168
- };
169
- };
170
-
171
- // src/nextjs/routeHandler.ts
172
- import { NextResponse } from "next/server.js";
173
- import { revalidatePath } from "next/cache.js";
1
+ import {
2
+ createCivicAuthPlugin,
3
+ defaultAuthConfig,
4
+ loggers,
5
+ resolveAuthConfig,
6
+ resolveCallbackUrl
7
+ } from "./chunk-EAANLFR5.mjs";
8
+ import {
9
+ CookieStorage,
10
+ resolveOAuthAccessCode
11
+ } from "./chunk-EGFTMH5S.mjs";
12
+ import {
13
+ GenericPublicClientPKCEProducer,
14
+ GenericUserSession,
15
+ clearTokens,
16
+ getUser
17
+ } from "./chunk-PMDIR5XE.mjs";
18
+ import {
19
+ __async,
20
+ __spreadProps,
21
+ __spreadValues
22
+ } from "./chunk-RGHW4PYM.mjs";
174
23
 
175
- // src/nextjs/NextJSSessionService.ts
24
+ // src/nextjs/cookies.ts
176
25
  import { cookies } from "next/headers.js";
177
-
178
- // src/services/UserInfoService.ts
179
- import { parseJWT } from "oslo/jwt";
180
- var UserInfoServiceImpl = class {
181
- constructor(endpoints) {
182
- this.endpoints = endpoints;
183
- }
184
- extractUserFromIdToken(idToken) {
185
- const parsedJWT = parseJWT(idToken);
186
- if (!parsedJWT) {
187
- return null;
188
- }
189
- return parsedJWT.payload;
190
- }
191
- getUserInfo(accessToken, idToken) {
192
- return __async(this, null, function* () {
193
- if (idToken) {
194
- return this.extractUserFromIdToken(idToken);
195
- }
196
- const userInfo = yield fetch(this.endpoints.userinfo, {
197
- headers: { Authorization: `Bearer ${accessToken}` }
198
- });
199
- return userInfo.json();
200
- });
201
- }
202
- };
203
-
204
- // src/services/SessionService.ts
205
- import { OAuth2Client, generateCodeVerifier } from "oslo/oauth2";
206
- import * as jose from "jose";
207
-
208
- // src/lib/oauth.ts
209
- import { v4 as uuid } from "uuid";
210
- var getIssuerVariations = (issuer) => {
211
- const issuerWithoutSlash = issuer.endsWith("/") ? issuer.slice(0, issuer.length - 1) : issuer;
212
- const issuerWithSlash = `${issuerWithoutSlash}/`;
213
- return [issuerWithoutSlash, issuerWithSlash];
214
- };
215
- var addSlashIfNeeded = (url) => url.endsWith("/") ? url : `${url}/`;
216
- var getOauthEndpoints = (oauthServer) => __async(void 0, null, function* () {
217
- const openIdConfigResponse = yield fetch(
218
- `${addSlashIfNeeded(oauthServer)}.well-known/openid-configuration`
219
- );
220
- const openIdConfig = yield openIdConfigResponse.json();
221
- return {
222
- jwks: openIdConfig.jwks_uri,
223
- auth: openIdConfig.authorization_endpoint,
224
- token: openIdConfig.token_endpoint,
225
- userinfo: openIdConfig.userinfo_endpoint
226
- };
26
+ var clearAuthCookies = () => __async(void 0, null, function* () {
27
+ const cookieStorage = new NextjsCookieStorage();
28
+ clearTokens(cookieStorage);
29
+ const clientStorage = new NextjsClientStorage();
30
+ const userSession = new GenericUserSession(clientStorage);
31
+ userSession.set(null);
227
32
  });
228
- var generateState = (displayMode) => {
229
- const jsonString = JSON.stringify({
230
- uuid: uuid(),
231
- displayMode
232
- });
233
- return btoa(jsonString);
234
- };
235
- var displayModeFromState = (state, sessionDisplayMode) => {
236
- try {
237
- const jsonString = btoa(state);
238
- return JSON.parse(jsonString).displayMode;
239
- } catch (e) {
240
- console.error("Failed to parse displayMode from state:", e);
241
- return sessionDisplayMode;
242
- }
243
- };
244
-
245
- // src/utils.ts
246
- import { clsx } from "clsx";
247
- import { twMerge } from "tailwind-merge";
248
- var isPopupBlocked = () => {
249
- const popup = window.open("", "", "width=1,height=1");
250
- if (!popup) {
251
- return true;
252
- }
253
- try {
254
- if (typeof popup.closed === "undefined") {
255
- throw new Error("Popup is blocked");
256
- }
257
- } catch (e) {
258
- return true;
259
- }
260
- popup.close();
261
- return false;
262
- };
263
-
264
- // src/services/SessionService.ts
265
- var AuthSessionServiceImpl = class {
266
- constructor(clientId, redirectUrl, oauthServer, inputEndpoints) {
267
- this.clientId = clientId;
268
- this.redirectUrl = redirectUrl;
269
- this.oauthServer = oauthServer;
270
- this.inputEndpoints = inputEndpoints;
271
- this.codeVerifier = void 0;
272
- this.refreshTokenTimeout = null;
273
- this.codeVerifier = this.getCodeVerifier();
274
- this.endpoints = inputEndpoints;
275
- }
276
- getCodeVerifier() {
277
- return generateCodeVerifier();
278
- }
279
- getUserInfoService() {
280
- return __async(this, null, function* () {
281
- if (this.userInfoService) {
282
- return this.userInfoService;
283
- }
284
- const endpoints = yield this.getEndpoints();
285
- this.userInfoService = new UserInfoServiceImpl(endpoints);
286
- return this.userInfoService;
287
- });
288
- }
289
- getEndpoints() {
290
- return __async(this, null, function* () {
291
- var _a;
292
- if ((_a = this.endpoints) == null ? void 0 : _a.auth) {
293
- return this.endpoints;
294
- }
295
- const jwksEndpoints = yield getOauthEndpoints(this.oauthServer);
296
- return this.endpoints ? __spreadValues(__spreadValues({}, this.endpoints), jwksEndpoints) : jwksEndpoints;
297
- });
298
- }
299
- getOauth2Client() {
300
- return __async(this, null, function* () {
301
- if (this.oauth2Client) {
302
- return this.oauth2Client;
303
- }
304
- const endpoints = yield this.getEndpoints();
305
- this.oauth2Client = new OAuth2Client(
306
- this.clientId,
307
- endpoints.auth,
308
- endpoints.token,
309
- // this
310
- { redirectURI: this.redirectUrl }
311
- );
312
- return this.oauth2Client;
313
- });
314
- }
315
- getSessionData() {
316
- return JSON.parse(
317
- localStorage.getItem(`civic-auth:${this.clientId}`) || "{}"
318
- );
319
- }
320
- updateSessionData(data) {
321
- localStorage.setItem(
322
- `civic-auth:${this.clientId}`,
323
- JSON.stringify(__spreadValues({}, data))
324
- );
325
- }
326
- getUser() {
327
- return JSON.parse(
328
- localStorage.getItem(`civic-auth:${this.clientId}:user`) || "{}"
329
- );
330
- }
331
- setUser(data) {
332
- localStorage.setItem(
333
- `civic-auth:${this.clientId}:user`,
334
- JSON.stringify(data === null ? {} : data)
335
- );
336
- }
337
- clearSessionData() {
338
- localStorage.setItem(`civic-auth:${this.clientId}`, JSON.stringify({}));
339
- }
340
- getAuthorizationUrlWithChallenge(state, scopes) {
341
- return __async(this, null, function* () {
342
- var _a;
343
- const oauth2Client = yield this.getOauth2Client();
344
- if ((_a = this.endpoints) == null ? void 0 : _a.challenge) {
345
- const challenge = yield fetch(this.endpoints.challenge).then(
346
- (res) => res.json().then((data) => data.challenge)
347
- );
348
- const oAuthUrl2 = yield oauth2Client.createAuthorizationURL({
349
- state,
350
- scopes
351
- });
352
- oAuthUrl2.searchParams.append("code_challenge", challenge);
353
- oAuthUrl2.searchParams.append("code_challenge_method", "S256");
354
- return oAuthUrl2;
355
- }
356
- const oAuthUrl = yield oauth2Client.createAuthorizationURL({
357
- state,
358
- codeVerifier: this.codeVerifier,
359
- codeChallengeMethod: "S256",
360
- scopes
361
- });
362
- return oAuthUrl;
363
- });
364
- }
365
- getAuthorizationUrl(scopes, displayMode, nonce) {
366
- return __async(this, null, function* () {
367
- const state = generateState(displayMode);
368
- const existingSessionData = this.getSessionData();
369
- this.updateSessionData(__spreadProps(__spreadValues({}, existingSessionData), {
370
- codeVerifier: this.codeVerifier,
371
- displayMode
372
- }));
373
- const oAuthUrl = yield this.getAuthorizationUrlWithChallenge(state, scopes);
374
- if (nonce) {
375
- oAuthUrl.searchParams.append("nonce", nonce);
376
- }
377
- oAuthUrl.searchParams.append("prompt", "consent");
378
- return oAuthUrl.toString();
379
- });
380
- }
381
- // TODO fix the Window reference
382
- loadAuthorizationUrl(authorizationURL, displayMode) {
383
- switch (displayMode) {
384
- case "iframe":
385
- break;
386
- case "redirect":
387
- window.location.href = authorizationURL;
388
- break;
389
- case "new_tab":
390
- window.open(authorizationURL, "_blank");
391
- break;
392
- case "custom_tab":
393
- break;
394
- }
395
- }
396
- init() {
397
- return __async(this, null, function* () {
398
- this.updateSessionData({ authenticated: false });
399
- });
400
- }
401
- determineDisplayMode(displayMode) {
402
- if (isPopupBlocked() && displayMode === "iframe") {
403
- displayMode = "redirect";
404
- }
405
- return displayMode;
406
- }
407
- signIn(displayMode, scopes, nonce) {
408
- return __async(this, null, function* () {
409
- const authorizationURL = yield this.getAuthorizationUrl(
410
- scopes,
411
- displayMode,
412
- nonce
413
- );
414
- this.loadAuthorizationUrl(authorizationURL, displayMode);
415
- });
416
- }
417
- tokenExchange(responseUrl) {
418
- return __async(this, null, function* () {
419
- let session = this.getSessionData();
420
- if (!session.authenticated) {
421
- const url = new URL(responseUrl);
422
- const authorizationCode = url.searchParams.get("code");
423
- const returnedState = url.searchParams.get("state");
424
- if (!authorizationCode || !returnedState) {
425
- throw new Error("Invalid authorization response");
426
- }
427
- const codeVerifier = session.codeVerifier;
428
- const oauth2Client = yield this.getOauth2Client();
429
- const tokens = yield oauth2Client.validateAuthorizationCode(
430
- authorizationCode,
431
- {
432
- codeVerifier
433
- }
434
- );
435
- try {
436
- yield this.validateTokens(tokens);
437
- } catch (error) {
438
- console.error("tokenExchange tokens", { error, tokens });
439
- throw new Error(
440
- `OIDC tokens validation failed: ${error.message}`
441
- );
442
- }
443
- const parsedDisplayMode = displayModeFromState(
444
- returnedState,
445
- session.displayMode
446
- );
447
- session = __spreadProps(__spreadValues({}, session), {
448
- displayMode: parsedDisplayMode,
449
- idToken: tokens.id_token,
450
- authenticated: true,
451
- state: returnedState,
452
- accessToken: tokens.access_token,
453
- refreshToken: tokens.refresh_token,
454
- timestamp: Date.now(),
455
- expiresIn: tokens.expires_in
456
- });
457
- this.updateSessionData(session);
458
- const user = yield (yield this.getUserInfoService()).getUserInfo(tokens.access_token, tokens.id_token || null);
459
- this.setUser(user);
460
- }
461
- this.setupTokenRefresh(session);
462
- if (session.displayMode === "new_tab") {
463
- window.close();
464
- } else if (session.displayMode === "redirect") {
465
- }
466
- return session;
467
- });
468
- }
469
- setupTokenRefresh(session) {
470
- if (this.refreshTokenTimeout) {
471
- clearTimeout(this.refreshTokenTimeout);
472
- }
473
- if (session.expiresIn) {
474
- const elapsedTime = Date.now() - (session.timestamp || 0);
475
- const remainingTime = session.expiresIn * 1e3 - elapsedTime;
476
- const refreshTime = Math.max(0, remainingTime - 6e4);
477
- this.refreshTokenTimeout = setTimeout(() => {
478
- this.refreshToken().then((newSession) => {
479
- console.log("Token refreshed successfully", newSession);
480
- }).catch((error) => {
481
- console.error("Failed to refresh token:", error);
482
- this.updateSessionData({});
483
- });
484
- }, refreshTime);
485
- }
486
- }
487
- refreshToken() {
488
- return __async(this, null, function* () {
489
- const sessionData = this.getSessionData();
490
- if (!sessionData.refreshToken) {
491
- throw new Error("No refresh token available");
492
- }
493
- const oauth2Client = yield this.getOauth2Client();
494
- const tokens = yield oauth2Client.refreshAccessToken(
495
- sessionData.refreshToken
496
- );
497
- const session = __spreadProps(__spreadValues({}, sessionData), {
498
- idToken: tokens.id_token,
499
- authenticated: true,
500
- accessToken: tokens.access_token,
501
- refreshToken: tokens.refresh_token,
502
- timestamp: Date.now(),
503
- expiresIn: tokens.expires_in
504
- });
505
- this.updateSessionData(session);
506
- this.setupTokenRefresh(session);
507
- return session;
508
- });
509
- }
510
- getUserInfo() {
511
- return __async(this, null, function* () {
512
- const sessionData = this.getSessionData();
513
- if (!sessionData.accessToken) {
514
- throw new Error("No access token available");
515
- }
516
- const userInfoService = yield this.getUserInfoService();
517
- return userInfoService.getUserInfo(
518
- sessionData.accessToken,
519
- sessionData.idToken || null
520
- );
521
- });
522
- }
523
- /**
524
- * Uses the jose library to validate a JWT token using the OAuth JWKS endpoint
525
- * @param {string} token
526
- * @returns {Promise<jose.JWTPayload>}
527
- * @throws {Error} if the token is invalid
528
- */
529
- validateTokens(tokens) {
530
- return __async(this, null, function* () {
531
- const endpoints = yield this.getEndpoints();
532
- const JWKS = jose.createRemoteJWKSet(new URL(endpoints.jwks));
533
- const returnPayload = {};
534
- console.log("issuer", getIssuerVariations(this.oauthServer));
535
- const idTokenResponse = yield jose.jwtVerify(tokens.id_token, JWKS, {
536
- issuer: getIssuerVariations(this.oauthServer),
537
- audience: this.clientId
538
- });
539
- returnPayload.idToken = idTokenResponse.payload;
540
- const accessTokenResponse = yield jose.jwtVerify(
541
- tokens.access_token,
542
- JWKS,
543
- {
544
- issuer: getIssuerVariations(this.oauthServer)
545
- }
546
- );
547
- returnPayload.accessToken = accessTokenResponse.payload;
548
- if (tokens.refresh_token) {
549
- returnPayload.refreshToken = tokens.refresh_token;
550
- }
551
- return returnPayload;
552
- });
553
- }
554
- validateExistingSession() {
555
- return __async(this, null, function* () {
556
- const sessionData = this.getSessionData();
557
- try {
558
- if (!sessionData.idToken || !sessionData.accessToken) {
559
- const unAuthenticatedSession = __spreadProps(__spreadValues({}, sessionData), { authenticated: false });
560
- this.updateSessionData(unAuthenticatedSession);
561
- return unAuthenticatedSession;
562
- }
563
- yield this.validateTokens({
564
- id_token: sessionData.idToken,
565
- access_token: sessionData.accessToken,
566
- refresh_token: sessionData.refreshToken
567
- });
568
- sessionData.authenticated = true;
569
- return sessionData;
570
- } catch (error) {
571
- console.warn("Failed to validate existing tokens", error);
572
- const unAuthenticatedSession = {
573
- authenticated: false
574
- };
575
- this.updateSessionData(unAuthenticatedSession);
576
- return unAuthenticatedSession;
577
- }
578
- });
579
- }
580
- };
581
-
582
- // src/nextjs/cookies.ts
583
- var createSecureTokenCookies = (response, sessionData, config) => {
584
- var _a, _b;
585
- const maxAge = (_a = sessionData.expiresIn) != null ? _a : 3600;
586
- const cookieOptions = __spreadProps(__spreadValues({}, (_b = config.cookies) == null ? void 0 : _b.tokens), {
587
- maxAge
588
- });
589
- if (sessionData.accessToken) {
590
- response.cookies.set("access_token", sessionData.accessToken, __spreadProps(__spreadValues({}, cookieOptions), {
33
+ var NextjsCookieStorage = class extends CookieStorage {
34
+ constructor(config = {}) {
35
+ super(__spreadProps(__spreadValues({}, config), {
36
+ secure: true,
591
37
  httpOnly: true
592
38
  }));
593
39
  }
594
- if (sessionData.idToken) {
595
- response.cookies.set("id_token", sessionData.idToken, __spreadProps(__spreadValues({}, cookieOptions), {
596
- httpOnly: true
597
- }));
40
+ get(key) {
41
+ var _a;
42
+ return ((_a = cookies().get(key)) == null ? void 0 : _a.value) || null;
598
43
  }
599
- if (sessionData.refreshToken) {
600
- response.cookies.set("refresh_token", sessionData.refreshToken, __spreadProps(__spreadValues({}, cookieOptions), {
601
- httpOnly: true
602
- }));
44
+ set(key, value) {
45
+ cookies().set(key, value, this.settings);
603
46
  }
604
47
  };
605
- var createUserInfoCookie = (response, user, sessionData, config) => {
606
- var _a, _b, _c;
607
- if (!user) {
608
- response.cookies.set("user", "", __spreadProps(__spreadValues({}, (_a = config.cookies) == null ? void 0 : _a.user), {
609
- maxAge: 0
48
+ var NextjsClientStorage = class extends CookieStorage {
49
+ constructor(config = {}) {
50
+ super(__spreadProps(__spreadValues({}, config), {
51
+ secure: false,
52
+ httpOnly: false
610
53
  }));
611
- return;
612
54
  }
613
- const maxAge = (_b = sessionData.expiresIn) != null ? _b : 3600;
614
- const frontendUser = __spreadValues({}, user);
615
- response.cookies.set("user", JSON.stringify(frontendUser), __spreadProps(__spreadValues({}, (_c = config.cookies) == null ? void 0 : _c.user), {
616
- maxAge
617
- }));
618
- };
619
- var clearAuthCookies = (response, config) => {
620
- var _a, _b;
621
- const clearOptions = __spreadProps(__spreadValues({}, (_a = config.cookies) == null ? void 0 : _a.tokens), {
622
- maxAge: 0
623
- });
624
- response.cookies.set("access_token", "", clearOptions);
625
- response.cookies.set("id_token", "", clearOptions);
626
- response.cookies.set("refresh_token", "", clearOptions);
627
- response.cookies.set("codeVerifier", "", clearOptions);
628
- response.cookies.set("user", "", __spreadProps(__spreadValues({}, (_b = config.cookies) == null ? void 0 : _b.user), {
629
- maxAge: 0
630
- }));
631
- };
632
-
633
- // src/nextjs/NextJSSessionService.ts
634
- var NextJSAuthSessionServiceImpl = class extends AuthSessionServiceImpl {
635
- constructor(authConfig, request, response, inputEndpoints) {
636
- super(
637
- authConfig.clientId,
638
- authConfig.callbackUrl,
639
- authConfig.oauthServer,
640
- inputEndpoints
641
- );
642
- this.authConfig = authConfig;
643
- this.request = request;
644
- this.response = response;
645
- this.inputEndpoints = inputEndpoints;
646
- }
647
- getCodeVerifier() {
648
- const codeVerifier = cookies().get("codeVerifier");
649
- if (!codeVerifier) {
650
- throw new Error("Code verifier not found in cookies");
651
- }
652
- return codeVerifier.value;
653
- }
654
- getSessionData() {
655
- var _a, _b, _c, _d;
656
- const authenticated = cookies().get("access_token") !== void 0;
657
- return {
658
- authenticated,
659
- codeVerifier: (_a = cookies().get("codeVerifier")) == null ? void 0 : _a.value,
660
- accessToken: (_b = cookies().get("access_token")) == null ? void 0 : _b.value,
661
- idToken: (_c = cookies().get("id_token")) == null ? void 0 : _c.value,
662
- refreshToken: (_d = cookies().get("refresh_token")) == null ? void 0 : _d.value
663
- };
664
- }
665
- updateSessionData(data) {
666
- createSecureTokenCookies(
667
- this.response,
668
- data,
669
- this.authConfig
670
- );
671
- }
672
- getUser() {
673
- const userCookie = cookies().get("user");
674
- if (!userCookie) return null;
675
- return JSON.parse(userCookie.value);
676
- }
677
- setUser(user) {
678
- createUserInfoCookie(
679
- this.response,
680
- user,
681
- { authenticated: true },
682
- this.authConfig
683
- );
684
- }
685
- clearSessionData() {
686
- clearAuthCookies(this.response, this.authConfig);
687
- }
688
- // TODO fix the Window reference
689
- loadAuthorizationUrl() {
690
- throw new Error("Not implemented");
691
- }
692
- init() {
693
- return __async(this, null, function* () {
694
- this.updateSessionData({ authenticated: false });
695
- });
55
+ get(key) {
56
+ var _a;
57
+ return ((_a = cookies().get(key)) == null ? void 0 : _a.value) || null;
696
58
  }
697
- };
698
-
699
- // src/nextjs/routeHandler.ts
700
- import { generateCodeVerifier as generateCodeVerifier2 } from "oslo/oauth2";
701
- var logger2 = loggers.nextjs.handlers.auth;
702
- var AuthError = class extends Error {
703
- constructor(message, status = 401) {
704
- super(message);
705
- this.status = status;
706
- this.name = "AuthError";
59
+ set(key, value) {
60
+ cookies().set(key, value, this.settings);
707
61
  }
708
62
  };
709
- function generateCodeChallenge(codeVerifier) {
710
- return __async(this, null, function* () {
711
- const encoder = new TextEncoder();
712
- const data = encoder.encode(codeVerifier);
713
- const digest = yield crypto.subtle.digest("SHA-256", data);
714
- return btoa(String.fromCharCode(...new Uint8Array(digest))).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
715
- });
716
- }
717
- function handleChallenge() {
718
- return __async(this, null, function* () {
719
- const codeVerifier = generateCodeVerifier2();
720
- console.log("handleChallenge codeVerifier", codeVerifier);
721
- const challenge = yield generateCodeChallenge(codeVerifier);
722
- const response = NextResponse.json({ status: "success", challenge });
723
- response.cookies.set("codeVerifier", codeVerifier, {
724
- httpOnly: true,
725
- secure: true,
726
- sameSite: "strict"
727
- });
728
- return response;
729
- });
730
- }
731
- function handleCallback(request, config) {
732
- return __async(this, null, function* () {
733
- const code = request.nextUrl.searchParams.get("code");
734
- if (!code) {
735
- throw new AuthError("Missing authorization code");
736
- }
737
- try {
738
- const response = new NextResponse(`<html></html>`);
739
- response.headers.set("Content-Type", "text/html; charset=utf-8");
740
- const resolvedConfigs = resolveAuthConfig(config);
741
- const callbackUrl = new URL(
742
- resolvedConfigs == null ? void 0 : resolvedConfigs.callbackUrl,
743
- request.url
744
- ).toString();
745
- const authService = getDefaultAuthSessionService(
746
- __spreadProps(__spreadValues({}, resolvedConfigs), {
747
- callbackUrl
748
- }),
749
- request,
750
- response
751
- );
752
- console.log("handleCallback authService", authService);
753
- const tokens = yield authService.tokenExchange(request.nextUrl.toString());
754
- if (!tokens.accessToken) {
755
- throw new AuthError("Missing access token");
756
- }
757
- return response;
758
- } catch (error) {
759
- logger2.error("Token exchange failed:", error);
760
- throw new AuthError("Failed to authenticate user", 401);
761
- }
762
- });
763
- }
764
- function handleLogout(request, config) {
765
- return __async(this, null, function* () {
766
- var _a;
767
- const resolvedConfigs = resolveAuthConfig(config);
768
- const path = (_a = resolvedConfigs.loginUrl) != null ? _a : "/";
769
- const redirectTarget = new URL(path, request.url).toString();
770
- const response = NextResponse.redirect(redirectTarget);
771
- clearAuthCookies(response, resolvedConfigs);
772
- try {
773
- revalidatePath(path);
774
- } catch (error) {
775
- logger2.warn("Failed to revalidate path after logout:", error);
776
- }
777
- return response;
778
- });
779
- }
780
- var getDefaultAuthSessionService = (authConfig, request, response) => {
781
- return new NextJSAuthSessionServiceImpl(authConfig, request, response);
782
- };
783
- function handler(authConfig = {}) {
784
- return (request) => __async(this, null, function* () {
785
- const config = resolveAuthConfig(authConfig);
786
- try {
787
- const pathname = request.nextUrl.pathname;
788
- const pathSegments = pathname.split("/");
789
- const lastSegment = pathSegments[pathSegments.length - 1];
790
- switch (lastSegment) {
791
- case "challenge":
792
- return yield handleChallenge();
793
- case "callback":
794
- return yield handleCallback(request, config);
795
- case "logout":
796
- return yield handleLogout(request, config);
797
- default:
798
- throw new AuthError(`Invalid auth route: ${pathname}`, 404);
799
- }
800
- } catch (error) {
801
- logger2.error("Auth handler error:", error);
802
- const status = error instanceof AuthError ? error.status : 500;
803
- const message = error instanceof Error ? error.message : "Authentication failed";
804
- const response = NextResponse.json({ error: message }, { status });
805
- clearAuthCookies(response, config);
806
- return response;
807
- }
808
- });
809
- }
810
63
 
811
64
  // src/nextjs/GetUser.ts
812
- import { cookies as cookies2 } from "next/headers.js";
813
- var getUser = () => {
814
- var _a;
815
- const user = (_a = cookies2().get("user")) == null ? void 0 : _a.value;
816
- if (!user) return null;
817
- return JSON.parse(user);
65
+ var getUser2 = () => {
66
+ const clientStorage = new NextjsClientStorage();
67
+ const userSession = new GenericUserSession(clientStorage);
68
+ return userSession.get();
818
69
  };
819
70
 
820
71
  // src/nextjs/middleware.ts
821
- import { NextResponse as NextResponse2 } from "next/server.js";
72
+ import { NextResponse } from "next/server.js";
822
73
  import picomatch from "picomatch";
823
74
  var matchGlob = (pathname, globPattern) => {
824
75
  const matches = picomatch(globPattern);
@@ -851,7 +102,7 @@ var applyAuth = (authConfig, request) => __async(void 0, null, function* () {
851
102
  if (!isAuthenticated) {
852
103
  console.log("\u2192 No valid token found - redirecting to login");
853
104
  const loginUrl = new URL(authConfigWithDefaults.loginUrl, request.url);
854
- return NextResponse2.redirect(loginUrl);
105
+ return NextResponse.redirect(loginUrl);
855
106
  }
856
107
  console.log("\u2192 Auth check passed");
857
108
  return void 0;
@@ -859,7 +110,7 @@ var applyAuth = (authConfig, request) => __async(void 0, null, function* () {
859
110
  var authMiddleware = (authConfig = defaultAuthConfig) => (request) => __async(void 0, null, function* () {
860
111
  const response = yield applyAuth(authConfig, request);
861
112
  if (response) return response;
862
- return NextResponse2.next();
113
+ return NextResponse.next();
863
114
  });
864
115
  function withAuth(middleware) {
865
116
  return (request) => __async(this, null, function* () {
@@ -877,11 +128,117 @@ function auth(authConfig = {}) {
877
128
  });
878
129
  };
879
130
  }
131
+
132
+ // src/nextjs/routeHandler.ts
133
+ import { NextResponse as NextResponse2 } from "next/server.js";
134
+ import { revalidatePath } from "next/cache.js";
135
+ var logger = loggers.nextjs.handlers.auth;
136
+ var AuthError = class extends Error {
137
+ constructor(message, status = 401) {
138
+ super(message);
139
+ this.status = status;
140
+ this.name = "AuthError";
141
+ }
142
+ };
143
+ function handleChallenge() {
144
+ return __async(this, null, function* () {
145
+ const cookieStorage = new NextjsCookieStorage();
146
+ const pkceProducer = new GenericPublicClientPKCEProducer(cookieStorage);
147
+ const challenge = yield pkceProducer.getCodeChallenge();
148
+ return NextResponse2.json({ status: "success", challenge });
149
+ });
150
+ }
151
+ function handleCallback(request, config) {
152
+ return __async(this, null, function* () {
153
+ const tokenExchange = request.nextUrl.searchParams.get("tokenExchange");
154
+ if (!tokenExchange) {
155
+ const response2 = new NextResponse2(`<html></html>`);
156
+ response2.headers.set("Content-Type", "text/html; charset=utf-8");
157
+ return response2;
158
+ }
159
+ const code = request.nextUrl.searchParams.get("code");
160
+ const state = request.nextUrl.searchParams.get("state");
161
+ if (!code || !state) throw new AuthError("Bad parameters", 400);
162
+ const cookieStorage = new NextjsCookieStorage();
163
+ const resolvedConfigs = resolveAuthConfig(config);
164
+ const callbackUrl = resolveCallbackUrl(resolvedConfigs, request.url);
165
+ try {
166
+ yield resolveOAuthAccessCode(code, state, cookieStorage, __spreadProps(__spreadValues({}, resolvedConfigs), {
167
+ redirectUrl: callbackUrl
168
+ }));
169
+ } catch (error) {
170
+ logger.error("Token exchange failed:", error);
171
+ throw new AuthError("Failed to authenticate user", 401);
172
+ }
173
+ const user = yield getUser(cookieStorage);
174
+ if (!user) {
175
+ throw new AuthError("Failed to get user info", 401);
176
+ }
177
+ const clientStorage = new NextjsClientStorage();
178
+ const userSession = new GenericUserSession(clientStorage);
179
+ userSession.set(user);
180
+ const response = new NextResponse2(`<html></html>`);
181
+ response.headers.set("Content-Type", "text/html; charset=utf-8");
182
+ return response;
183
+ });
184
+ }
185
+ var getAbsoluteRedirectPath = (redirectPath, currentBasePath) => {
186
+ if (/^(https?:\/\/|www\.).+/i.test(redirectPath)) {
187
+ return redirectPath;
188
+ }
189
+ return new URL(redirectPath, currentBasePath).href;
190
+ };
191
+ function handleLogout(request, config) {
192
+ return __async(this, null, function* () {
193
+ var _a;
194
+ const resolvedConfigs = resolveAuthConfig(config);
195
+ const defaultRedirectPath = (_a = resolvedConfigs.loginUrl) != null ? _a : "/";
196
+ const redirectTarget = new URL(request.url).searchParams.get("redirect") || defaultRedirectPath;
197
+ const isAbsoluteRedirect = /^(https?:\/\/|www\.).+/i.test(redirectTarget);
198
+ const finalRedirectUrl = getAbsoluteRedirectPath(
199
+ redirectTarget,
200
+ new URL(request.url).origin
201
+ );
202
+ const response = NextResponse2.redirect(finalRedirectUrl);
203
+ clearAuthCookies();
204
+ try {
205
+ revalidatePath(isAbsoluteRedirect ? finalRedirectUrl : redirectTarget);
206
+ } catch (error) {
207
+ logger.warn("Failed to revalidate path after logout:", error);
208
+ }
209
+ return response;
210
+ });
211
+ }
212
+ var handler = (authConfig = {}) => (request) => __async(void 0, null, function* () {
213
+ const config = resolveAuthConfig(authConfig);
214
+ try {
215
+ const pathname = request.nextUrl.pathname;
216
+ const pathSegments = pathname.split("/");
217
+ const lastSegment = pathSegments[pathSegments.length - 1];
218
+ switch (lastSegment) {
219
+ case "challenge":
220
+ return yield handleChallenge();
221
+ case "callback":
222
+ return yield handleCallback(request, config);
223
+ case "logout":
224
+ return yield handleLogout(request, config);
225
+ default:
226
+ throw new AuthError(`Invalid auth route: ${pathname}`, 404);
227
+ }
228
+ } catch (error) {
229
+ logger.error("Auth handler error:", error);
230
+ const status = error instanceof AuthError ? error.status : 500;
231
+ const message = error instanceof Error ? error.message : "Authentication failed";
232
+ const response = NextResponse2.json({ error: message }, { status });
233
+ clearAuthCookies();
234
+ return response;
235
+ }
236
+ });
880
237
  export {
881
238
  auth,
882
239
  authMiddleware,
883
240
  createCivicAuthPlugin,
884
- getUser,
241
+ getUser2 as getUser,
885
242
  handler,
886
243
  withAuth
887
244
  };