@civic/auth 0.0.1-beta.19 → 0.0.1-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. package/README.md +0 -26
  2. package/dist/chunk-5NUJ7LFF.mjs +17 -0
  3. package/dist/chunk-5NUJ7LFF.mjs.map +1 -0
  4. package/dist/chunk-CRTRMMJ7.js.map +1 -1
  5. package/dist/chunk-KS7ERXGZ.js +481 -0
  6. package/dist/chunk-KS7ERXGZ.js.map +1 -0
  7. package/dist/chunk-NINRO7GS.js +209 -0
  8. package/dist/chunk-NINRO7GS.js.map +1 -0
  9. package/dist/chunk-NXBKSUKI.mjs +481 -0
  10. package/dist/chunk-NXBKSUKI.mjs.map +1 -0
  11. package/dist/chunk-T7HUHQ3J.mjs +209 -0
  12. package/dist/chunk-T7HUHQ3J.mjs.map +1 -0
  13. package/dist/chunk-WZLC5B4C.js +17 -0
  14. package/dist/chunk-WZLC5B4C.js.map +1 -0
  15. package/dist/index-DoDoIY_K.d.mts +79 -0
  16. package/dist/index-DoDoIY_K.d.ts +79 -0
  17. package/dist/index.css +70 -63
  18. package/dist/index.css.map +1 -1
  19. package/dist/index.d.mts +1 -3
  20. package/dist/index.d.ts +1 -3
  21. package/dist/index.js +1 -2
  22. package/dist/index.js.map +1 -1
  23. package/dist/index.mjs +0 -1
  24. package/dist/nextjs.d.mts +15 -42
  25. package/dist/nextjs.d.ts +15 -42
  26. package/dist/nextjs.js +180 -156
  27. package/dist/nextjs.js.map +1 -1
  28. package/dist/nextjs.mjs +177 -153
  29. package/dist/nextjs.mjs.map +1 -1
  30. package/dist/react.d.mts +81 -31
  31. package/dist/react.d.ts +81 -31
  32. package/dist/react.js +634 -35
  33. package/dist/react.js.map +1 -1
  34. package/dist/react.mjs +664 -65
  35. package/dist/react.mjs.map +1 -1
  36. package/dist/server.d.mts +34 -14
  37. package/dist/server.d.ts +34 -14
  38. package/dist/server.js +185 -4
  39. package/dist/server.js.map +1 -1
  40. package/dist/server.mjs +191 -10
  41. package/dist/server.mjs.map +1 -1
  42. package/package.json +17 -26
  43. package/dist/AuthProvider-Bj_Prt1x.d.ts +0 -21
  44. package/dist/AuthProvider-DUAoX4G9.d.mts +0 -21
  45. package/dist/UserProvider-CMLaYOUD.d.ts +0 -16
  46. package/dist/UserProvider-Cbm8MZkJ.d.mts +0 -16
  47. package/dist/chunk-5UQQYXCX.js +0 -1
  48. package/dist/chunk-5UQQYXCX.js.map +0 -1
  49. package/dist/chunk-BFESCRFK.mjs +0 -118
  50. package/dist/chunk-BFESCRFK.mjs.map +0 -1
  51. package/dist/chunk-CBQ3HKRV.mjs +0 -599
  52. package/dist/chunk-CBQ3HKRV.mjs.map +0 -1
  53. package/dist/chunk-CZ3AVCKD.js +0 -171
  54. package/dist/chunk-CZ3AVCKD.js.map +0 -1
  55. package/dist/chunk-DJFTZS4P.js +0 -118
  56. package/dist/chunk-DJFTZS4P.js.map +0 -1
  57. package/dist/chunk-HTTTZ2BP.mjs +0 -223
  58. package/dist/chunk-HTTTZ2BP.mjs.map +0 -1
  59. package/dist/chunk-O2SODTR3.js +0 -599
  60. package/dist/chunk-O2SODTR3.js.map +0 -1
  61. package/dist/chunk-O6DPCPRH.js +0 -223
  62. package/dist/chunk-O6DPCPRH.js.map +0 -1
  63. package/dist/chunk-PMJAV4JJ.mjs +0 -1
  64. package/dist/chunk-PMJAV4JJ.mjs.map +0 -1
  65. package/dist/chunk-UADVRCHY.mjs +0 -710
  66. package/dist/chunk-UADVRCHY.mjs.map +0 -1
  67. package/dist/chunk-VJVRFKDH.js +0 -710
  68. package/dist/chunk-VJVRFKDH.js.map +0 -1
  69. package/dist/chunk-X3FQBE22.mjs +0 -171
  70. package/dist/chunk-X3FQBE22.mjs.map +0 -1
  71. package/dist/nextjs/client.css +0 -335
  72. package/dist/nextjs/client.css.map +0 -1
  73. package/dist/nextjs/client.d.mts +0 -12
  74. package/dist/nextjs/client.d.ts +0 -12
  75. package/dist/nextjs/client.js +0 -179
  76. package/dist/nextjs/client.js.map +0 -1
  77. package/dist/nextjs/client.mjs +0 -179
  78. package/dist/nextjs/client.mjs.map +0 -1
  79. package/dist/storage-B2eAQNdv.d.ts +0 -25
  80. package/dist/storage-BJPUpxhm.d.mts +0 -25
  81. package/dist/types-Bqm9OCZN.d.mts +0 -22
  82. package/dist/types-Bqm9OCZN.d.ts +0 -22
  83. package/dist/types-HdCjGldB.d.mts +0 -58
  84. package/dist/types-HdCjGldB.d.ts +0 -58
@@ -0,0 +1,481 @@
1
+ import {
2
+ buildOauth2Client,
3
+ displayModeFromState,
4
+ generateState,
5
+ getOauthEndpoints,
6
+ isPopupBlocked,
7
+ validateOauth2Tokens,
8
+ withoutUndefined
9
+ } from "./chunk-T7HUHQ3J.mjs";
10
+ import {
11
+ __async,
12
+ __spreadProps,
13
+ __spreadValues
14
+ } from "./chunk-RGHW4PYM.mjs";
15
+
16
+ // src/lib/logger.ts
17
+ import debug from "debug";
18
+ var PACKAGE_NAME = "@civic/auth";
19
+ var DebugLogger = class {
20
+ constructor(namespace) {
21
+ this.debugLogger = debug(`${PACKAGE_NAME}:${namespace}:debug`);
22
+ this.infoLogger = debug(`${PACKAGE_NAME}:${namespace}:info`);
23
+ this.warnLogger = debug(`${PACKAGE_NAME}:${namespace}:warn`);
24
+ this.errorLogger = debug(`${PACKAGE_NAME}:${namespace}:error`);
25
+ this.debugLogger.color = "4";
26
+ this.infoLogger.color = "2";
27
+ this.warnLogger.color = "3";
28
+ this.errorLogger.color = "1";
29
+ }
30
+ debug(message, ...args) {
31
+ this.debugLogger(message, ...args);
32
+ }
33
+ info(message, ...args) {
34
+ this.infoLogger(message, ...args);
35
+ }
36
+ warn(message, ...args) {
37
+ this.warnLogger(message, ...args);
38
+ }
39
+ error(message, ...args) {
40
+ this.errorLogger(message, ...args);
41
+ }
42
+ };
43
+ var createLogger = (namespace) => new DebugLogger(namespace);
44
+ var loggers = {
45
+ // Next.js specific loggers
46
+ nextjs: {
47
+ routes: createLogger("api:routes"),
48
+ middleware: createLogger("api:middleware"),
49
+ handlers: {
50
+ auth: createLogger("api:handlers:auth")
51
+ }
52
+ },
53
+ // React specific loggers
54
+ react: {
55
+ components: createLogger("react:components"),
56
+ hooks: createLogger("react:hooks"),
57
+ context: createLogger("react:context")
58
+ },
59
+ // Shared utilities loggers
60
+ services: {
61
+ validation: createLogger("utils:validation"),
62
+ network: createLogger("utils:network")
63
+ }
64
+ };
65
+
66
+ // src/nextjs/config.ts
67
+ var logger = loggers.nextjs.handlers.auth;
68
+ var defaultAuthConfig = {
69
+ oauthServer: "https://auth-dev.civic.com/oauth",
70
+ callbackUrl: "/api/auth/callback",
71
+ challengeUrl: "/api/auth/challenge",
72
+ logoutUrl: "/api/auth/logout",
73
+ loginUrl: "/",
74
+ include: ["/*"],
75
+ exclude: [],
76
+ cookies: {
77
+ tokens: {
78
+ sameSite: "strict",
79
+ path: "/",
80
+ maxAge: 60 * 60
81
+ // 1 hour
82
+ },
83
+ user: {
84
+ sameSite: "strict",
85
+ path: "/",
86
+ maxAge: 60 * 60
87
+ // 1 hour
88
+ }
89
+ }
90
+ };
91
+ var resolveAuthConfig = (config = {}) => {
92
+ var _a, _b, _c, _d;
93
+ const configFromEnv = withoutUndefined({
94
+ clientId: process.env._civic_auth_client_id,
95
+ oauthServer: process.env._civic_oauth_server,
96
+ callbackUrl: process.env._civic_auth_callback_url,
97
+ challengeUrl: process.env._civic_auth_challenge_url,
98
+ loginUrl: process.env._civic_auth_login_url,
99
+ logoutUrl: process.env._civic_auth_logout_url,
100
+ include: (_a = process.env._civic_auth_includes) == null ? void 0 : _a.split(","),
101
+ exclude: (_b = process.env._civic_auth_excludes) == null ? void 0 : _b.split(","),
102
+ cookies: process.env._civic_auth_cookie_config ? JSON.parse(process.env._civic_auth_cookie_config) : void 0
103
+ });
104
+ const mergedConfig = __spreadProps(__spreadValues(__spreadValues(__spreadValues({}, defaultAuthConfig), configFromEnv), config), {
105
+ // Override with directly passed config
106
+ cookies: {
107
+ tokens: __spreadValues(__spreadValues({}, defaultAuthConfig.cookies.tokens), ((_c = config.cookies) == null ? void 0 : _c.tokens) || {}),
108
+ user: __spreadValues(__spreadValues({}, defaultAuthConfig.cookies.user), ((_d = config.cookies) == null ? void 0 : _d.user) || {})
109
+ }
110
+ });
111
+ logger.debug("Config from environment:", configFromEnv);
112
+ logger.debug("Resolved config:", mergedConfig);
113
+ if (mergedConfig.clientId === void 0) {
114
+ throw new Error("Civic Auth client ID is required");
115
+ }
116
+ return mergedConfig;
117
+ };
118
+ var createCivicAuthPlugin = (clientId, authConfig = {}) => {
119
+ return (nextConfig) => {
120
+ const resolvedConfig = resolveAuthConfig(__spreadProps(__spreadValues({}, authConfig), { clientId }));
121
+ return __spreadProps(__spreadValues({}, nextConfig), {
122
+ env: __spreadProps(__spreadValues({}, nextConfig == null ? void 0 : nextConfig.env), {
123
+ // Internal environment variables - do not set these manually
124
+ _civic_auth_client_id: clientId,
125
+ _civic_oauth_server: resolvedConfig.oauthServer,
126
+ _civic_auth_callback_url: resolvedConfig.callbackUrl,
127
+ _civic_auth_challenge_url: resolvedConfig.challengeUrl,
128
+ _civic_auth_login_url: resolvedConfig.loginUrl,
129
+ _civic_auth_logout_url: resolvedConfig.logoutUrl,
130
+ _civic_auth_includes: resolvedConfig.include.join(","),
131
+ _civic_auth_excludes: resolvedConfig.exclude.join(","),
132
+ _civic_auth_cookie_config: JSON.stringify(resolvedConfig.cookies)
133
+ })
134
+ });
135
+ };
136
+ };
137
+
138
+ // src/services/UserInfoService.ts
139
+ import { parseJWT } from "oslo/jwt";
140
+ var UserInfoServiceImpl = class {
141
+ constructor(endpoints) {
142
+ this.endpoints = endpoints;
143
+ }
144
+ extractUserFromIdToken(idToken) {
145
+ const parsedJWT = parseJWT(idToken);
146
+ if (!parsedJWT) {
147
+ return null;
148
+ }
149
+ return parsedJWT.payload;
150
+ }
151
+ getUserInfo(accessToken, idToken) {
152
+ return __async(this, null, function* () {
153
+ if (idToken) {
154
+ return this.extractUserFromIdToken(idToken);
155
+ }
156
+ const userInfo = yield fetch(this.endpoints.userinfo, {
157
+ headers: { Authorization: `Bearer ${accessToken}` }
158
+ });
159
+ return userInfo.json();
160
+ });
161
+ }
162
+ };
163
+
164
+ // src/services/SessionService.ts
165
+ import { generateCodeVerifier } from "oslo/oauth2";
166
+ var AuthSessionServiceImpl = class {
167
+ constructor(clientId, redirectUrl, oauthServer, inputEndpoints) {
168
+ this.clientId = clientId;
169
+ this.redirectUrl = redirectUrl;
170
+ this.oauthServer = oauthServer;
171
+ this.inputEndpoints = inputEndpoints;
172
+ this.codeVerifier = void 0;
173
+ this.refreshTokenTimeout = null;
174
+ this.codeVerifier = this.getCodeVerifier();
175
+ this.endpoints = inputEndpoints;
176
+ }
177
+ getCodeVerifier() {
178
+ return generateCodeVerifier();
179
+ }
180
+ getUserInfoService() {
181
+ return __async(this, null, function* () {
182
+ if (this.userInfoService) {
183
+ return this.userInfoService;
184
+ }
185
+ const endpoints = yield this.getEndpoints();
186
+ this.userInfoService = new UserInfoServiceImpl(endpoints);
187
+ return this.userInfoService;
188
+ });
189
+ }
190
+ getEndpoints() {
191
+ return __async(this, null, function* () {
192
+ var _a;
193
+ if ((_a = this.endpoints) == null ? void 0 : _a.auth) {
194
+ return this.endpoints;
195
+ }
196
+ const jwksEndpoints = yield getOauthEndpoints(this.oauthServer);
197
+ return this.endpoints ? __spreadValues(__spreadValues({}, this.endpoints), jwksEndpoints) : jwksEndpoints;
198
+ });
199
+ }
200
+ getOauth2Client() {
201
+ return __async(this, null, function* () {
202
+ if (this.oauth2Client) {
203
+ return this.oauth2Client;
204
+ }
205
+ const endpoints = yield this.getEndpoints();
206
+ this.oauth2Client = buildOauth2Client(
207
+ this.clientId,
208
+ this.redirectUrl,
209
+ endpoints
210
+ );
211
+ return this.oauth2Client;
212
+ });
213
+ }
214
+ getSessionData() {
215
+ console.log("getSessionData", this.clientId);
216
+ const storedItem = localStorage.getItem(`civic-auth:${this.clientId}`) || "{}";
217
+ console.log("stored item", storedItem);
218
+ return JSON.parse(storedItem);
219
+ }
220
+ updateSessionData(data) {
221
+ localStorage.setItem(
222
+ `civic-auth:${this.clientId}`,
223
+ JSON.stringify(__spreadValues({}, data))
224
+ );
225
+ }
226
+ getUser() {
227
+ return JSON.parse(
228
+ localStorage.getItem(`civic-auth:${this.clientId}:user`) || "{}"
229
+ );
230
+ }
231
+ setUser(data) {
232
+ localStorage.setItem(
233
+ `civic-auth:${this.clientId}:user`,
234
+ JSON.stringify(data === null ? {} : data)
235
+ );
236
+ }
237
+ clearSessionData() {
238
+ localStorage.setItem(`civic-auth:${this.clientId}`, JSON.stringify({}));
239
+ }
240
+ getAuthorizationUrlWithChallenge(state, scopes) {
241
+ return __async(this, null, function* () {
242
+ var _a;
243
+ const oauth2Client = yield this.getOauth2Client();
244
+ if ((_a = this.endpoints) == null ? void 0 : _a.challenge) {
245
+ const challenge = yield fetch(this.endpoints.challenge).then(
246
+ (res) => res.json().then((data) => data.challenge)
247
+ );
248
+ const oAuthUrl = yield oauth2Client.createAuthorizationURL({
249
+ state,
250
+ scopes
251
+ });
252
+ oAuthUrl.searchParams.append("code_challenge", challenge);
253
+ oAuthUrl.searchParams.append("code_challenge_method", "S256");
254
+ return oAuthUrl;
255
+ }
256
+ return oauth2Client.createAuthorizationURL({
257
+ state,
258
+ codeVerifier: this.codeVerifier,
259
+ codeChallengeMethod: "S256",
260
+ scopes
261
+ });
262
+ });
263
+ }
264
+ getAuthorizationUrl(scopes, displayMode, nonce) {
265
+ return __async(this, null, function* () {
266
+ const state = generateState(displayMode);
267
+ const existingSessionData = this.getSessionData();
268
+ this.updateSessionData(__spreadProps(__spreadValues({}, existingSessionData), {
269
+ codeVerifier: this.codeVerifier,
270
+ displayMode
271
+ }));
272
+ const oAuthUrl = yield this.getAuthorizationUrlWithChallenge(state, scopes);
273
+ if (nonce) {
274
+ oAuthUrl.searchParams.append("nonce", nonce);
275
+ }
276
+ oAuthUrl.searchParams.append("prompt", "consent");
277
+ return oAuthUrl.toString();
278
+ });
279
+ }
280
+ // TODO fix the Window reference
281
+ loadAuthorizationUrl(authorizationURL, displayMode) {
282
+ switch (displayMode) {
283
+ case "iframe":
284
+ break;
285
+ case "redirect":
286
+ window.location.href = authorizationURL;
287
+ break;
288
+ case "new_tab":
289
+ window.open(authorizationURL, "_blank");
290
+ break;
291
+ case "custom_tab":
292
+ break;
293
+ }
294
+ }
295
+ init() {
296
+ return __async(this, null, function* () {
297
+ yield this.getOauth2Client();
298
+ return this;
299
+ });
300
+ }
301
+ logout() {
302
+ return __async(this, null, function* () {
303
+ this.updateSessionData({ authenticated: false });
304
+ });
305
+ }
306
+ determineDisplayMode(displayMode) {
307
+ if (isPopupBlocked() && displayMode === "iframe") {
308
+ displayMode = "redirect";
309
+ }
310
+ return displayMode;
311
+ }
312
+ signIn(displayMode, scopes, nonce) {
313
+ return __async(this, null, function* () {
314
+ const authorizationURL = yield this.getAuthorizationUrl(
315
+ scopes,
316
+ displayMode,
317
+ nonce
318
+ );
319
+ this.loadAuthorizationUrl(authorizationURL, displayMode);
320
+ });
321
+ }
322
+ tokenExchange(responseUrl) {
323
+ return __async(this, null, function* () {
324
+ let session = this.getSessionData();
325
+ if (!session.authenticated) {
326
+ const url = new URL(responseUrl);
327
+ const authorizationCode = url.searchParams.get("code");
328
+ const returnedState = url.searchParams.get("state");
329
+ if (!authorizationCode || !returnedState) {
330
+ throw new Error("Invalid authorization response");
331
+ }
332
+ const codeVerifier = session.codeVerifier;
333
+ const oauth2Client = yield this.getOauth2Client();
334
+ const tokens = yield oauth2Client.validateAuthorizationCode(
335
+ authorizationCode,
336
+ {
337
+ codeVerifier
338
+ }
339
+ );
340
+ try {
341
+ yield this.validateTokens(tokens);
342
+ } catch (error) {
343
+ console.error("tokenExchange tokens", { error, tokens });
344
+ throw new Error(
345
+ `OIDC tokens validation failed: ${error.message}`
346
+ );
347
+ }
348
+ const parsedDisplayMode = displayModeFromState(
349
+ returnedState,
350
+ session.displayMode
351
+ );
352
+ session = __spreadProps(__spreadValues({}, session), {
353
+ displayMode: parsedDisplayMode,
354
+ idToken: tokens.id_token,
355
+ authenticated: true,
356
+ state: returnedState,
357
+ accessToken: tokens.access_token,
358
+ refreshToken: tokens.refresh_token,
359
+ timestamp: Date.now(),
360
+ expiresIn: tokens.expires_in
361
+ });
362
+ this.updateSessionData(session);
363
+ const user = yield (yield this.getUserInfoService()).getUserInfo(tokens.access_token, tokens.id_token || null);
364
+ this.setUser(user);
365
+ }
366
+ this.setupTokenRefresh(session);
367
+ if (session.displayMode === "new_tab") {
368
+ window.close();
369
+ } else if (session.displayMode === "redirect") {
370
+ }
371
+ return session;
372
+ });
373
+ }
374
+ setupTokenRefresh(session) {
375
+ if (this.refreshTokenTimeout) {
376
+ clearTimeout(this.refreshTokenTimeout);
377
+ }
378
+ if (session.expiresIn) {
379
+ const elapsedTime = Date.now() - (session.timestamp || 0);
380
+ const remainingTime = session.expiresIn * 1e3 - elapsedTime;
381
+ const refreshTime = Math.max(0, remainingTime - 6e4);
382
+ this.refreshTokenTimeout = setTimeout(() => {
383
+ this.refreshToken().then((newSession) => {
384
+ console.log("Token refreshed successfully", newSession);
385
+ }).catch((error) => {
386
+ console.error("Failed to refresh token:", error);
387
+ this.updateSessionData({});
388
+ });
389
+ }, refreshTime);
390
+ }
391
+ }
392
+ refreshToken() {
393
+ return __async(this, null, function* () {
394
+ const sessionData = this.getSessionData();
395
+ if (!sessionData.refreshToken) {
396
+ throw new Error("No refresh token available");
397
+ }
398
+ const oauth2Client = yield this.getOauth2Client();
399
+ const tokens = yield oauth2Client.refreshAccessToken(
400
+ sessionData.refreshToken
401
+ );
402
+ const session = __spreadProps(__spreadValues({}, sessionData), {
403
+ idToken: tokens.id_token,
404
+ authenticated: true,
405
+ accessToken: tokens.access_token,
406
+ refreshToken: tokens.refresh_token,
407
+ timestamp: Date.now(),
408
+ expiresIn: tokens.expires_in
409
+ });
410
+ this.updateSessionData(session);
411
+ this.setupTokenRefresh(session);
412
+ return session;
413
+ });
414
+ }
415
+ getUserInfo() {
416
+ return __async(this, null, function* () {
417
+ const sessionData = this.getSessionData();
418
+ if (!sessionData.accessToken) {
419
+ throw new Error("No access token available");
420
+ }
421
+ const userInfoService = yield this.getUserInfoService();
422
+ return userInfoService.getUserInfo(
423
+ sessionData.accessToken,
424
+ sessionData.idToken || null
425
+ );
426
+ });
427
+ }
428
+ /**
429
+ * Uses the jose library to validate a JWT token using the OAuth JWKS endpoint
430
+ * @returns {Promise<jose.JWTPayload>}
431
+ * @throws {Error} if the token is invalid
432
+ * @param tokens
433
+ */
434
+ validateTokens(tokens) {
435
+ return __async(this, null, function* () {
436
+ const endpoints = yield this.getEndpoints();
437
+ if (!this.oauth2Client) yield this.init();
438
+ return validateOauth2Tokens(
439
+ tokens,
440
+ endpoints,
441
+ this.oauth2Client,
442
+ this.oauthServer
443
+ );
444
+ });
445
+ }
446
+ validateExistingSession() {
447
+ return __async(this, null, function* () {
448
+ const sessionData = this.getSessionData();
449
+ try {
450
+ if (!sessionData.idToken || !sessionData.accessToken) {
451
+ const unAuthenticatedSession = __spreadProps(__spreadValues({}, sessionData), { authenticated: false });
452
+ this.updateSessionData(unAuthenticatedSession);
453
+ return unAuthenticatedSession;
454
+ }
455
+ yield this.validateTokens({
456
+ id_token: sessionData.idToken,
457
+ access_token: sessionData.accessToken,
458
+ refresh_token: sessionData.refreshToken
459
+ });
460
+ sessionData.authenticated = true;
461
+ return sessionData;
462
+ } catch (error) {
463
+ console.warn("Failed to validate existing tokens", error);
464
+ const unAuthenticatedSession = {
465
+ authenticated: false
466
+ };
467
+ this.updateSessionData(unAuthenticatedSession);
468
+ return unAuthenticatedSession;
469
+ }
470
+ });
471
+ }
472
+ };
473
+
474
+ export {
475
+ AuthSessionServiceImpl,
476
+ loggers,
477
+ defaultAuthConfig,
478
+ resolveAuthConfig,
479
+ createCivicAuthPlugin
480
+ };
481
+ //# sourceMappingURL=chunk-NXBKSUKI.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/lib/logger.ts","../src/nextjs/config.ts","../src/services/UserInfoService.ts","../src/services/SessionService.ts"],"sourcesContent":["import debug from \"debug\";\n\nconst PACKAGE_NAME = \"@civic/auth\";\n\nexport interface Logger {\n debug(message: string, ...args: unknown[]): void;\n info(message: string, ...args: unknown[]): void;\n warn(message: string, ...args: unknown[]): void;\n error(message: string, ...args: unknown[]): void;\n}\n\nclass DebugLogger implements Logger {\n private debugLogger: debug.Debugger;\n private infoLogger: debug.Debugger;\n private warnLogger: debug.Debugger;\n private errorLogger: debug.Debugger;\n\n constructor(namespace: string) {\n // Format: @org/package:library:component:level\n this.debugLogger = debug(`${PACKAGE_NAME}:${namespace}:debug`);\n this.infoLogger = debug(`${PACKAGE_NAME}:${namespace}:info`);\n this.warnLogger = debug(`${PACKAGE_NAME}:${namespace}:warn`);\n this.errorLogger = debug(`${PACKAGE_NAME}:${namespace}:error`);\n\n this.debugLogger.color = \"4\";\n this.infoLogger.color = \"2\";\n this.warnLogger.color = \"3\";\n this.errorLogger.color = \"1\";\n }\n\n debug(message: string, ...args: unknown[]): void {\n this.debugLogger(message, ...args);\n }\n\n info(message: string, ...args: unknown[]): void {\n this.infoLogger(message, ...args);\n }\n\n warn(message: string, ...args: unknown[]): void {\n this.warnLogger(message, ...args);\n }\n\n error(message: string, ...args: unknown[]): void {\n this.errorLogger(message, ...args);\n }\n}\n\nexport const createLogger = (namespace: string): Logger =>\n new DebugLogger(namespace);\n\n// Pre-configured loggers for different parts of your package\nexport const loggers = {\n // Next.js specific loggers\n nextjs: {\n routes: createLogger(\"api:routes\"),\n middleware: createLogger(\"api:middleware\"),\n handlers: {\n auth: createLogger(\"api:handlers:auth\"),\n },\n },\n // React specific loggers\n react: {\n components: createLogger(\"react:components\"),\n hooks: createLogger(\"react:hooks\"),\n context: createLogger(\"react:context\"),\n },\n // Shared utilities loggers\n services: {\n validation: createLogger(\"utils:validation\"),\n network: createLogger(\"utils:network\"),\n },\n} as const;\n","/* eslint-disable turbo/no-undeclared-env-vars */\nimport { NextConfig } from \"next\";\nimport { loggers } from \"@/lib/logger\";\nimport { withoutUndefined } from \"@/utils.js\";\n\nconst logger = loggers.nextjs.handlers.auth;\n\nexport interface CookieConfig {\n secure?: boolean;\n sameSite?: \"strict\" | \"lax\" | \"none\";\n domain?: string;\n path?: string;\n maxAge?: number;\n}\n\nexport type AuthConfigWithDefaults = {\n clientId: string;\n oauthServer: string;\n callbackUrl: string;\n loginUrl: string;\n logoutUrl: string;\n challengeUrl: string;\n include: string[];\n exclude: string[];\n cookies: {\n tokens: CookieConfig;\n user: CookieConfig;\n };\n};\n\nexport type AuthConfig = Partial<AuthConfigWithDefaults>;\n\nexport type DefinedAuthConfig = AuthConfigWithDefaults;\n\n/**\n * Default configuration values that will be used if not overridden\n */\nexport const defaultAuthConfig: Omit<AuthConfigWithDefaults, \"clientId\"> = {\n oauthServer: \"https://auth-dev.civic.com/oauth\",\n callbackUrl: \"/api/auth/callback\",\n challengeUrl: \"/api/auth/challenge\",\n logoutUrl: \"/api/auth/logout\",\n loginUrl: \"/\",\n include: [\"/*\"],\n exclude: [],\n cookies: {\n tokens: {\n sameSite: \"strict\",\n path: \"/\",\n maxAge: 60 * 60, // 1 hour\n },\n user: {\n sameSite: \"strict\",\n path: \"/\",\n maxAge: 60 * 60, // 1 hour\n },\n },\n};\n\n/**\n * Resolves the authentication configuration by combining:\n * 1. Default values\n * 2. Environment variables (set internally by the plugin)\n * 3. Explicitly passed configuration\n *\n * Note: Developers should not set _civic_auth_* environment variables directly.\n * Instead, pass configuration to the createCivicAuthPlugin in next.config.js:\n *\n * @example\n * ```js\n * // next.config.js\n * export default createCivicAuthPlugin({\n * callbackUrl: '/custom/callback',\n * })\n * ```\n */\nexport const resolveAuthConfig = (\n config: AuthConfig = {},\n): AuthConfigWithDefaults & { clientId: string } => {\n // Read configuration that was set by the plugin via environment variables\n const configFromEnv = withoutUndefined({\n clientId: process.env._civic_auth_client_id,\n oauthServer: process.env._civic_oauth_server,\n callbackUrl: process.env._civic_auth_callback_url,\n challengeUrl: process.env._civic_auth_challenge_url,\n loginUrl: process.env._civic_auth_login_url,\n logoutUrl: process.env._civic_auth_logout_url,\n include: process.env._civic_auth_includes?.split(\",\"),\n exclude: process.env._civic_auth_excludes?.split(\",\"),\n cookies: process.env._civic_auth_cookie_config\n ? JSON.parse(process.env._civic_auth_cookie_config)\n : undefined,\n });\n\n const mergedConfig = {\n ...defaultAuthConfig,\n ...configFromEnv, // Apply plugin-set config\n ...config, // Override with directly passed config\n cookies: {\n tokens: {\n ...defaultAuthConfig.cookies.tokens,\n ...(config.cookies?.tokens || {}),\n },\n user: {\n ...defaultAuthConfig.cookies.user,\n ...(config.cookies?.user || {}),\n },\n },\n };\n\n logger.debug(\"Config from environment:\", configFromEnv);\n logger.debug(\"Resolved config:\", mergedConfig);\n if (mergedConfig.clientId === undefined) {\n throw new Error(\"Civic Auth client ID is required\");\n }\n return mergedConfig as AuthConfigWithDefaults & { clientId: string };\n};\n\n/**\n * Creates a Next.js plugin that handles auth configuration.\n *\n * This is the main configuration point for the auth system.\n * Do not set _civic_auth_* environment variables directly - instead,\n * pass your configuration here:\n *\n * @example\n * ```js\n * // next.config.js\n * export default createCivicAuthPlugin({\n * clientId: 'my-client-id',\n * callbackUrl: '/custom/callback',\n * loginUrl: '/custom/login',\n * logoutUrl: '/custom/logout',\n * include: ['/protected/*'],\n * exclude: ['/public/*']\n * })\n * ```\n *\n * The plugin sets internal environment variables that are used by\n * the auth system. These variables should not be set manually.\n */\nexport const createCivicAuthPlugin = (\n clientId: string,\n authConfig: AuthConfig = {},\n) => {\n return (nextConfig?: NextConfig) => {\n const resolvedConfig = resolveAuthConfig({ ...authConfig, clientId });\n return {\n ...nextConfig,\n env: {\n ...nextConfig?.env,\n // Internal environment variables - do not set these manually\n _civic_auth_client_id: clientId,\n _civic_oauth_server: resolvedConfig.oauthServer,\n _civic_auth_callback_url: resolvedConfig.callbackUrl,\n _civic_auth_challenge_url: resolvedConfig.challengeUrl,\n _civic_auth_login_url: resolvedConfig.loginUrl,\n _civic_auth_logout_url: resolvedConfig.logoutUrl,\n _civic_auth_includes: resolvedConfig.include.join(\",\"),\n _civic_auth_excludes: resolvedConfig.exclude.join(\",\"),\n _civic_auth_cookie_config: JSON.stringify(resolvedConfig.cookies),\n },\n };\n };\n};\n","import { UserInfoService, Endpoints } from \"@/types\";\nimport { parseJWT } from \"oslo/jwt\";\n\nexport class UserInfoServiceImpl implements UserInfoService {\n constructor(private endpoints: Endpoints) {}\n\n extractUserFromIdToken<T>(idToken: string): T | null {\n const parsedJWT = parseJWT(idToken);\n if (!parsedJWT) {\n return null;\n }\n return parsedJWT.payload as T;\n }\n\n async getUserInfo<T>(\n accessToken: string,\n idToken: string | null,\n ): Promise<T | null> {\n if (idToken) {\n return this.extractUserFromIdToken<T>(idToken);\n }\n\n const userInfo = await fetch(this.endpoints.userinfo, {\n headers: { Authorization: `Bearer ${accessToken}` },\n });\n return userInfo.json() as T;\n }\n}\n","import {\n AuthSessionService,\n DisplayMode,\n Endpoints,\n OIDCTokenResponseBody,\n ParsedTokens,\n SessionData,\n UnknownObject,\n User,\n UserInfoService,\n} from \"../types\";\nimport { UserInfoServiceImpl } from \"./UserInfoService\";\nimport { generateCodeVerifier, OAuth2Client } from \"oslo/oauth2\";\nimport {\n displayModeFromState,\n generateState,\n getOauthEndpoints,\n} from \"@/lib/oauth\";\nimport { isPopupBlocked } from \"@/utils\";\nimport { buildOauth2Client, validateOauth2Tokens } from \"@/shared/util.js\";\n\nexport type StorageInterface = {\n get(): SessionData;\n getUser(): User<UnknownObject> | null;\n set(data: Partial<SessionData>): void;\n setUser(data: User<UnknownObject> | null): void;\n clear(): void;\n};\n\nexport class AuthSessionServiceImpl implements AuthSessionService {\n private endpoints: Endpoints | undefined;\n private oauth2Client: OAuth2Client | undefined;\n private userInfoService: UserInfoService | undefined;\n private codeVerifier: string | undefined = undefined;\n private refreshTokenTimeout: NodeJS.Timeout | null = null;\n\n constructor(\n readonly clientId: string,\n readonly redirectUrl: string,\n readonly oauthServer: string,\n readonly inputEndpoints?: Partial<Endpoints> | undefined,\n ) {\n this.codeVerifier = this.getCodeVerifier();\n this.endpoints = inputEndpoints as Endpoints;\n }\n\n protected getCodeVerifier(): string {\n return generateCodeVerifier();\n }\n\n public async getUserInfoService(): Promise<UserInfoService> {\n if (this.userInfoService) {\n return this.userInfoService;\n }\n const endpoints = await this.getEndpoints();\n\n this.userInfoService = new UserInfoServiceImpl(endpoints);\n return this.userInfoService;\n }\n\n protected async getEndpoints(): Promise<Endpoints> {\n if (this.endpoints?.auth) {\n return this.endpoints;\n }\n const jwksEndpoints = await getOauthEndpoints(this.oauthServer);\n return this.endpoints\n ? { ...this.endpoints, ...jwksEndpoints }\n : jwksEndpoints;\n }\n\n protected async getOauth2Client() {\n if (this.oauth2Client) {\n return this.oauth2Client;\n }\n const endpoints = await this.getEndpoints();\n this.oauth2Client = buildOauth2Client(\n this.clientId,\n this.redirectUrl,\n endpoints,\n );\n return this.oauth2Client;\n }\n\n getSessionData(): SessionData {\n console.log(\"getSessionData\", this.clientId);\n const storedItem =\n localStorage.getItem(`civic-auth:${this.clientId}`) || \"{}\";\n console.log(\"stored item\", storedItem);\n return JSON.parse(storedItem) as SessionData;\n }\n\n updateSessionData(data: Partial<SessionData>): void {\n localStorage.setItem(\n `civic-auth:${this.clientId}`,\n JSON.stringify({ ...data }),\n );\n }\n\n getUser(): User<UnknownObject> | null {\n return JSON.parse(\n localStorage.getItem(`civic-auth:${this.clientId}:user`) || \"{}\",\n ) as User<UnknownObject>;\n }\n\n setUser(data: User<UnknownObject> | null): void {\n localStorage.setItem(\n `civic-auth:${this.clientId}:user`,\n JSON.stringify(data === null ? {} : data),\n );\n }\n\n clearSessionData(): void {\n localStorage.setItem(`civic-auth:${this.clientId}`, JSON.stringify({}));\n }\n\n async getAuthorizationUrlWithChallenge(\n state: string,\n scopes: string[],\n ): Promise<URL> {\n const oauth2Client = await this.getOauth2Client();\n if (this.endpoints?.challenge) {\n const challenge = await fetch(this.endpoints.challenge).then((res) =>\n res.json().then((data) => data.challenge),\n );\n const oAuthUrl = await oauth2Client.createAuthorizationURL({\n state,\n scopes,\n });\n oAuthUrl.searchParams.append(\"code_challenge\", challenge);\n oAuthUrl.searchParams.append(\"code_challenge_method\", \"S256\");\n return oAuthUrl;\n }\n return oauth2Client.createAuthorizationURL({\n state,\n codeVerifier: this.codeVerifier,\n codeChallengeMethod: \"S256\",\n scopes,\n });\n }\n\n async getAuthorizationUrl(\n scopes: string[],\n displayMode: DisplayMode,\n nonce?: string,\n ): Promise<string> {\n const state = generateState(displayMode);\n const existingSessionData = this.getSessionData();\n // TODO DK NOTES: Getter should not update state. This would be confusing to others. Should probably be part of signIn()\n this.updateSessionData({\n ...existingSessionData,\n codeVerifier: this.codeVerifier,\n displayMode,\n });\n const oAuthUrl = await this.getAuthorizationUrlWithChallenge(state, scopes);\n if (nonce) {\n // nonce isn't supported by oslo, so we add it manually\n oAuthUrl.searchParams.append(\"nonce\", nonce);\n }\n oAuthUrl.searchParams.append(\"prompt\", \"consent\");\n return oAuthUrl.toString();\n }\n\n // TODO fix the Window reference\n loadAuthorizationUrl(authorizationURL: string, displayMode: DisplayMode) {\n switch (displayMode) {\n case \"iframe\":\n // Implement iframe logic\n break;\n case \"redirect\":\n window.location.href = authorizationURL;\n break;\n case \"new_tab\":\n window.open(authorizationURL, \"_blank\");\n break;\n case \"custom_tab\":\n // Implement custom tab logic (might require native app integration)\n break;\n }\n }\n\n async init(): Promise<this> {\n await this.getOauth2Client();\n return this;\n }\n\n async logout(): Promise<void> {\n this.updateSessionData({ authenticated: false });\n }\n\n determineDisplayMode(displayMode: DisplayMode): DisplayMode {\n // If popups are blocked and we're in iframe mode, we need to override the display mode to redirect\n if (isPopupBlocked() && displayMode === \"iframe\") {\n displayMode = \"redirect\";\n }\n // TODO: Add additional checks to determine the display mode for new_mode if new tabs are blocked.\n return displayMode;\n }\n\n async signIn(\n displayMode: DisplayMode,\n scopes: string[],\n nonce: string,\n ): Promise<void> {\n const authorizationURL = await this.getAuthorizationUrl(\n scopes,\n displayMode,\n nonce,\n );\n\n this.loadAuthorizationUrl(authorizationURL, displayMode);\n }\n\n async tokenExchange(responseUrl: string): Promise<SessionData> {\n let session = this.getSessionData();\n\n if (!session.authenticated) {\n const url = new URL(responseUrl);\n const authorizationCode = url.searchParams.get(\"code\");\n const returnedState = url.searchParams.get(\"state\");\n if (!authorizationCode || !returnedState) {\n throw new Error(\"Invalid authorization response\");\n }\n const codeVerifier = session.codeVerifier;\n const oauth2Client = await this.getOauth2Client();\n const tokens =\n await oauth2Client.validateAuthorizationCode<OIDCTokenResponseBody>(\n authorizationCode,\n {\n codeVerifier,\n },\n );\n\n // Validate relevant tokens\n try {\n await this.validateTokens(tokens);\n } catch (error) {\n console.error(\"tokenExchange tokens\", { error, tokens });\n throw new Error(\n `OIDC tokens validation failed: ${(error as Error).message}`,\n );\n }\n const parsedDisplayMode = displayModeFromState(\n returnedState,\n session.displayMode,\n );\n // Update session with authentication result\n session = {\n ...session,\n displayMode: parsedDisplayMode,\n idToken: tokens.id_token,\n authenticated: true,\n state: returnedState,\n accessToken: tokens.access_token,\n refreshToken: tokens.refresh_token,\n timestamp: Date.now(),\n expiresIn: tokens.expires_in,\n };\n this.updateSessionData(session);\n const user = await (\n await this.getUserInfoService()\n ).getUserInfo(tokens.access_token, tokens.id_token || null);\n this.setUser(user);\n }\n\n // Set up automatic token refresh\n this.setupTokenRefresh(session);\n\n if (session.displayMode === \"new_tab\") {\n // Close the popup window\n window.close();\n } else if (session.displayMode === \"redirect\") {\n // TODO: Determine if there is anything additional to do here\n }\n return session;\n }\n\n private setupTokenRefresh(session: SessionData): void {\n if (this.refreshTokenTimeout) {\n clearTimeout(this.refreshTokenTimeout);\n }\n\n if (session.expiresIn) {\n // Calculate remaining time by subtracting elapsed time from total expiration time\n const elapsedTime = Date.now() - (session.timestamp || 0);\n const remainingTime = session.expiresIn * 1000 - elapsedTime;\n // Refresh the token 1 minute before it expires\n const refreshTime = Math.max(0, remainingTime - 60000);\n\n this.refreshTokenTimeout = setTimeout(() => {\n this.refreshToken()\n .then((newSession) => {\n console.log(\"Token refreshed successfully\", newSession);\n })\n .catch((error) => {\n console.error(\"Failed to refresh token:\", error);\n // Handle the error (e.g., log out the user or retry)\n // TODO this should be replaced by the real logout once it is available\n this.updateSessionData({});\n });\n }, refreshTime);\n }\n }\n\n async refreshToken(): Promise<SessionData> {\n const sessionData = this.getSessionData();\n if (!sessionData.refreshToken) {\n throw new Error(\"No refresh token available\");\n }\n const oauth2Client = await this.getOauth2Client();\n const tokens = await oauth2Client.refreshAccessToken<OIDCTokenResponseBody>(\n sessionData.refreshToken,\n );\n\n // Update session data\n const session = {\n ...sessionData,\n idToken: tokens.id_token,\n authenticated: true,\n accessToken: tokens.access_token,\n refreshToken: tokens.refresh_token,\n timestamp: Date.now(),\n expiresIn: tokens.expires_in,\n };\n this.updateSessionData(session);\n\n // Schedule next automatic refresh\n this.setupTokenRefresh(session);\n\n return session;\n }\n\n async getUserInfo<T extends UnknownObject>(): Promise<User<T> | null> {\n const sessionData = this.getSessionData();\n if (!sessionData.accessToken) {\n throw new Error(\"No access token available\");\n }\n const userInfoService = await this.getUserInfoService();\n return userInfoService.getUserInfo<T>(\n sessionData.accessToken,\n sessionData.idToken || null,\n );\n }\n\n /**\n * Uses the jose library to validate a JWT token using the OAuth JWKS endpoint\n * @returns {Promise<jose.JWTPayload>}\n * @throws {Error} if the token is invalid\n * @param tokens\n */\n async validateTokens(tokens: OIDCTokenResponseBody): Promise<ParsedTokens> {\n const endpoints = await this.getEndpoints();\n\n if (!this.oauth2Client) await this.init();\n\n return validateOauth2Tokens(\n tokens,\n endpoints,\n this.oauth2Client!,\n this.oauthServer,\n );\n }\n\n async validateExistingSession(): Promise<SessionData> {\n const sessionData = this.getSessionData();\n try {\n if (!sessionData.idToken || !sessionData.accessToken) {\n const unAuthenticatedSession = { ...sessionData, authenticated: false };\n this.updateSessionData(unAuthenticatedSession);\n return unAuthenticatedSession;\n }\n await this.validateTokens({\n id_token: sessionData.idToken as string,\n access_token: sessionData.accessToken as string,\n refresh_token: sessionData.refreshToken as string,\n });\n sessionData.authenticated = true;\n return sessionData;\n } catch (error) {\n console.warn(\"Failed to validate existing tokens\", error);\n const unAuthenticatedSession = {\n authenticated: false,\n };\n this.updateSessionData(unAuthenticatedSession);\n return unAuthenticatedSession;\n }\n }\n}\n"],"mappings":"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","names":[]}