@vunexa/lixa 0.0.1-alpha.20 → 0.0.1-alpha.22

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 (40) hide show
  1. package/README.md +562 -79
  2. package/dist/dao/session-cache.d.ts +2 -2
  3. package/dist/dao/session-cache.d.ts.map +1 -1
  4. package/dist/dao/state-cache.d.ts +3 -3
  5. package/dist/dao/state-cache.d.ts.map +1 -1
  6. package/dist/dao/types.d.ts +246 -5
  7. package/dist/dao/types.d.ts.map +1 -1
  8. package/dist/export-types/index.d.ts +852 -49
  9. package/dist/index.cjs +282 -46
  10. package/dist/index.cjs.map +1 -1
  11. package/dist/index.d.cts +853 -46
  12. package/dist/index.d.ts +11 -3
  13. package/dist/index.d.ts.map +1 -1
  14. package/dist/index.js +282 -46
  15. package/dist/index.js.map +1 -1
  16. package/dist/lixa.d.ts +187 -18
  17. package/dist/lixa.d.ts.map +1 -1
  18. package/dist/models/session.d.ts +163 -7
  19. package/dist/models/session.d.ts.map +1 -1
  20. package/dist/providers/IProvider.d.ts +121 -4
  21. package/dist/providers/IProvider.d.ts.map +1 -1
  22. package/dist/providers/index.d.ts +0 -2
  23. package/dist/providers/index.d.ts.map +1 -1
  24. package/dist/types.d.ts +131 -15
  25. package/dist/types.d.ts.map +1 -1
  26. package/package.json +2 -16
  27. package/dist/IProvider-2tDwRAnH.d.cts +0 -18
  28. package/dist/IProvider-2tDwRAnH.d.ts +0 -18
  29. package/dist/export-types/providers.d.ts +0 -61
  30. package/dist/providers/github.d.ts +0 -13
  31. package/dist/providers/github.d.ts.map +0 -1
  32. package/dist/providers/google.d.ts +0 -13
  33. package/dist/providers/google.d.ts.map +0 -1
  34. package/dist/providers-entry.cjs +0 -48
  35. package/dist/providers-entry.cjs.map +0 -1
  36. package/dist/providers-entry.d.cts +0 -25
  37. package/dist/providers-entry.d.ts +0 -22
  38. package/dist/providers-entry.d.ts.map +0 -1
  39. package/dist/providers-entry.js +0 -20
  40. package/dist/providers-entry.js.map +0 -1
package/dist/index.cjs CHANGED
@@ -87,12 +87,11 @@ var DefaultSessionStrategy = class {
87
87
  * @returns A Promise that resolves to a Session object
88
88
  */
89
89
  async createSession(tokenData) {
90
- const accessToken = tokenData.access_token || tokenData.accessToken || tokenData.token || tokenData;
91
- if (!accessToken || typeof accessToken !== "string") {
90
+ if (!tokenData.access_token || typeof tokenData.access_token !== "string") {
92
91
  throw new Error("No valid access token found in OAuth response");
93
92
  }
94
93
  return {
95
- token: accessToken,
94
+ token: tokenData.access_token,
96
95
  raw: tokenData
97
96
  };
98
97
  }
@@ -100,7 +99,9 @@ var DefaultSessionStrategy = class {
100
99
 
101
100
  // src/lixa.ts
102
101
  var Lixa = class _Lixa {
102
+ static DEFAULT_PROVIDERS = /* @__PURE__ */ new Map();
103
103
  static CONFIGURED_PROVIDERS = /* @__PURE__ */ new Map();
104
+ // Legacy registry for backward compatibility
104
105
  static LOCAL_STATE_CACHE = new LocalStateCache();
105
106
  static LOCAL_SESSION_CACHE = new LocalSessionCache();
106
107
  static DEFAULT_SESSION_STRATEGY = new DefaultSessionStrategy();
@@ -111,39 +112,122 @@ var Lixa = class _Lixa {
111
112
  debug;
112
113
  /**
113
114
  * Creates a new Lixa instance with the provided configuration.
114
- *
115
+ *
116
+ * @remarks
117
+ * Providers can be passed inline in the configuration using the `provider` field.
118
+ * Provider resolution priority: inline custom provider \> default providers \> legacy registry.
119
+ *
115
120
  * @param config - The configuration object containing provider settings and optional session strategy
121
+ *
122
+ * @throws Error when provider configuration is missing required fields
123
+ * @throws Error when provider implementation is missing required properties
124
+ * @throws Error when provider is not available and no inline implementation is provided
116
125
  */
117
126
  constructor(config) {
118
- const configuredProviders = Object.keys(config.providers);
119
- const registeredProviders = _Lixa.getRegisteredProviders();
120
- for (const provider of configuredProviders) {
121
- if (!registeredProviders.includes(provider.toLowerCase())) {
122
- throw new Error(`Provider '${provider}' is not registered. Please register it first using Lixa.registerProvider()`);
123
- }
124
- }
125
127
  this.config = config;
126
128
  this.stateDao = config.stateDao || _Lixa.LOCAL_STATE_CACHE;
127
129
  this.sesionDao = config.sessionDao || _Lixa.LOCAL_SESSION_CACHE;
128
130
  this.sessionStrategy = config.sessionStrategy || _Lixa.DEFAULT_SESSION_STRATEGY;
129
131
  this.debug = config.debug || false;
132
+ this.log("INFO", "Init", "Initializing Lixa instance", {
133
+ providers: Object.keys(config.providers),
134
+ debug: this.debug
135
+ });
136
+ for (const [providerName, providerConfig] of Object.entries(config.providers)) {
137
+ const name = providerName.toLowerCase();
138
+ const typedConfig = providerConfig;
139
+ this.validateProviderConfig(providerName, typedConfig);
140
+ if (typedConfig.provider) {
141
+ this.validateProviderImplementation(providerName, typedConfig.provider);
142
+ this.log("INFO", "Init", `Registered inline provider: ${providerName}`);
143
+ } else {
144
+ if (!_Lixa.DEFAULT_PROVIDERS.has(name) && !_Lixa.CONFIGURED_PROVIDERS.has(name)) {
145
+ this.log("ERROR", "Init", `Provider '${providerName}' not available`);
146
+ throw new Error(
147
+ `Provider '${providerName}' is not available. Either import it from '@vunexa/lixa-providers' and include it in the configuration, or provide a custom implementation using the 'provider' field: { provider: new CustomProvider(), clientId: '...', ... }`
148
+ );
149
+ }
150
+ this.log("INFO", "Init", `Using registered provider: ${providerName}`);
151
+ }
152
+ }
153
+ this.log("INFO", "Init", "Lixa instance initialized successfully");
130
154
  }
131
- log(...args) {
132
- if (this.debug) {
133
- console.log("[Lixa]", ...args);
155
+ /**
156
+ * Validates that a provider configuration has all required credentials.
157
+ *
158
+ * @param name - The provider name
159
+ * @param config - The provider configuration
160
+ * @throws Error when required fields are missing or invalid
161
+ */
162
+ validateProviderConfig(name, config) {
163
+ const requiredFields = ["clientId", "clientSecret", "redirectUri", "scopes"];
164
+ const missingFields = requiredFields.filter((field) => {
165
+ const value = config[field];
166
+ return value === void 0 || value === null || typeof value === "string" && value.trim() === "";
167
+ });
168
+ if (missingFields.length > 0) {
169
+ throw new Error(
170
+ `Provider '${name}' configuration is missing required fields: ${missingFields.join(", ")}`
171
+ );
172
+ }
173
+ if (!Array.isArray(config.scopes)) {
174
+ throw new Error(
175
+ `Provider '${name}' configuration error: 'scopes' must be an array of strings`
176
+ );
177
+ }
178
+ if (config.scopes.length === 0) {
179
+ throw new Error(
180
+ `Provider '${name}' configuration error: 'scopes' array cannot be empty`
181
+ );
134
182
  }
135
183
  }
136
- logError(...args) {
137
- if (this.debug) {
138
- console.error("[Lixa]", ...args);
184
+ /**
185
+ * Validates that a provider implementation has all required properties.
186
+ *
187
+ * @param name - The provider name
188
+ * @param provider - The provider implementation
189
+ * @throws Error when required properties are missing
190
+ */
191
+ validateProviderImplementation(name, provider) {
192
+ const requiredProps = ["authorizationEndpoint", "tokenEndpoint", "userInfoEndpoint"];
193
+ const missingProps = requiredProps.filter((prop) => {
194
+ const value = provider[prop];
195
+ return !value || typeof value !== "string" || value.trim() === "";
196
+ });
197
+ if (missingProps.length > 0) {
198
+ throw new Error(
199
+ `Provider '${name}' implementation is missing required properties: ${missingProps.join(", ")}. All IProvider implementations must define: authorizationEndpoint, tokenEndpoint, and userInfoEndpoint.`
200
+ );
139
201
  }
140
202
  }
141
203
  /**
142
- * Checks if a provider is both registered and configured for this instance.
204
+ * Structured debug logging with standardized format.
205
+ *
206
+ * @param level - Log level (INFO, WARN, ERROR)
207
+ * @param context - Context of the log (Init, Auth, Token, Session, State)
208
+ * @param message - Log message
209
+ * @param data - Optional data to log
210
+ *
211
+ * @remarks
212
+ * Format: [Lixa] [timestamp] [level] [context] message
213
+ * Only logs when debug mode is enabled.
214
+ */
215
+ log(level, context, message, data) {
216
+ if (!this.debug) return;
217
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString();
218
+ const prefix = `[Lixa] [${timestamp}] [${level}] [${context}]`;
219
+ if (data !== void 0) {
220
+ console.log(`${prefix} ${message}`, data);
221
+ } else {
222
+ console.log(`${prefix} ${message}`);
223
+ }
224
+ }
225
+ /**
226
+ * Checks if a provider is configured for this instance.
143
227
  * This is a type guard that narrows the provider type for use with getAuthUrl.
144
228
  *
145
229
  * @param provider - The provider name to check (case-insensitive)
146
- * @returns True if the provider is registered and configured, false otherwise
230
+ * @returns True if the provider is configured, false otherwise
147
231
  *
148
232
  * @example
149
233
  * ```typescript
@@ -155,14 +239,55 @@ var Lixa = class _Lixa {
155
239
  */
156
240
  isProviderConfigured(provider) {
157
241
  const providerType = provider.toLowerCase();
158
- return _Lixa.CONFIGURED_PROVIDERS.has(providerType) && this.config.providers.hasOwnProperty(providerType);
242
+ return this.config.providers.hasOwnProperty(providerType);
243
+ }
244
+ /**
245
+ * Gets a provider implementation by name.
246
+ * Resolution priority: inline custom provider \> default providers \> legacy registry
247
+ *
248
+ * @param name - The provider name (case-insensitive)
249
+ * @param config - The provider configuration
250
+ * @returns The provider implementation
251
+ * @throws Error when provider is not found
252
+ */
253
+ getProvider(name, config) {
254
+ if (config.provider) {
255
+ return config.provider;
256
+ }
257
+ const lowerName = name.toLowerCase();
258
+ const defaultProvider = _Lixa.DEFAULT_PROVIDERS.get(lowerName);
259
+ if (defaultProvider) {
260
+ return defaultProvider;
261
+ }
262
+ const legacyProvider = _Lixa.CONFIGURED_PROVIDERS.get(lowerName);
263
+ if (legacyProvider) {
264
+ return legacyProvider;
265
+ }
266
+ throw new Error(
267
+ `Provider '${name}' not found. Ensure the provider is included in the configuration with a 'provider' field, or registered using Lixa.registerProvider().`
268
+ );
159
269
  }
160
270
  /**
161
271
  * Registers custom OAuth providers for use with Lixa.
272
+ *
273
+ * @deprecated This method is maintained for backward compatibility.
274
+ * The recommended approach is to pass providers inline in the configuration:
275
+ * ```typescript
276
+ * const lixa = new Lixa({
277
+ * providers: {
278
+ * custom: {
279
+ * provider: new CustomProvider(),
280
+ * clientId: '...',
281
+ * // ...
282
+ * }
283
+ * }
284
+ * });
285
+ * ```
162
286
  *
163
287
  * @param providerMap - A map of provider names to IProvider implementations
164
288
  *
165
289
  * @example
290
+ * Legacy usage (still supported):
166
291
  * ```typescript
167
292
  * class CustomProvider implements IProvider {
168
293
  * authorizationEndpoint = 'https://custom.com/oauth/authorize';
@@ -187,19 +312,29 @@ var Lixa = class _Lixa {
187
312
  return Array.from(_Lixa.CONFIGURED_PROVIDERS.keys());
188
313
  }
189
314
  /**
190
- * Creates a type-safe configuration that only allows registered providers.
315
+ * Creates a type-safe configuration.
316
+ *
317
+ * @deprecated This method is maintained for backward compatibility.
318
+ * You can now pass configuration directly to the Lixa constructor without this helper.
319
+ *
320
+ * @param config - Configuration object with provider settings
321
+ * @returns The same configuration object with type safety
191
322
  *
192
- * @param config - Configuration object with providers that must be registered
193
- * @returns The same configuration object, but with type safety for registered providers
323
+ * @example
324
+ * New approach (recommended):
325
+ * ```typescript
326
+ * const lixa = new Lixa({
327
+ * providers: {
328
+ * google: {
329
+ * provider: new GoogleProvider(),
330
+ * clientId: '...',
331
+ * // ...
332
+ * }
333
+ * }
334
+ * });
335
+ * ```
194
336
  */
195
337
  static createConfig(config) {
196
- const configuredProviders = Object.keys(config.providers);
197
- const registeredProviders = _Lixa.getRegisteredProviders();
198
- for (const provider of configuredProviders) {
199
- if (!registeredProviders.includes(provider.toLowerCase())) {
200
- throw new Error(`Provider '${provider}' is not registered. Please register it first using Lixa.registerProvider()`);
201
- }
202
- }
203
338
  return config;
204
339
  }
205
340
  /**
@@ -216,14 +351,83 @@ var Lixa = class _Lixa {
216
351
  /**
217
352
  * Generates a cryptographically secure code verifier for PKCE flows.
218
353
  *
219
- * @returns A 64-character hexadecimal string
354
+ * @returns A 64-character hexadecimal string (32 random bytes encoded as hex)
220
355
  *
221
356
  * @remarks
222
- * The code verifier is used in PKCE (Proof Key for Code Exchange) to enhance security.
357
+ * This method implements the code verifier generation as specified in RFC 7636 (PKCE).
358
+ *
359
+ * **PKCE (Proof Key for Code Exchange)** is a security extension to OAuth 2.0 that
360
+ * prevents authorization code interception attacks. It's especially important for
361
+ * public clients (mobile apps, SPAs) but is recommended for all OAuth flows.
362
+ *
363
+ * **Generation methodology:**
364
+ * 1. Generate 32 cryptographically random bytes using Node.js crypto.randomBytes()
365
+ * 2. Encode the bytes as a hexadecimal string (64 characters)
366
+ * 3. The verifier is stored securely and used later in the token exchange
367
+ *
368
+ * **RFC 7636 Requirements:**
369
+ * - Minimum length: 43 characters
370
+ * - Maximum length: 128 characters
371
+ * - Character set: [A-Z] / [a-z] / [0-9] / "-" / "." / "_" / "~"
372
+ * - This implementation produces 64 hex characters, meeting the requirements
373
+ *
374
+ * The code verifier is:
375
+ * - Generated when creating the authorization URL
376
+ * - Stored in state cache with the state parameter
377
+ * - Retrieved during callback handling
378
+ * - Sent to the token endpoint to prove the client's identity
379
+ *
380
+ * @see {@link https://datatracker.ietf.org/doc/html/rfc7636 | RFC 7636 - PKCE}
381
+ * @see buildCodeChallenge for the corresponding challenge generation
382
+ *
383
+ * @internal
223
384
  */
224
385
  static generateCodeVerifier() {
225
386
  return (0, import_crypto.randomBytes)(32).toString("hex");
226
387
  }
388
+ /**
389
+ * Generates a code challenge from a code verifier for PKCE flows.
390
+ *
391
+ * @param codeVerifier - The code verifier string (64 hex characters)
392
+ * @returns A base64url-encoded SHA-256 hash of the code verifier
393
+ *
394
+ * @remarks
395
+ * This method implements the code challenge generation as specified in RFC 7636 (PKCE)
396
+ * using the S256 (SHA-256) transformation method.
397
+ *
398
+ * **Challenge generation methodology:**
399
+ * 1. Hash the code verifier using SHA-256
400
+ * 2. Encode the hash as base64
401
+ * 3. Convert to base64url format (RFC 4648):
402
+ * - Replace '+' with '-'
403
+ * - Replace '/' with '_'
404
+ * - Remove trailing '=' padding
405
+ *
406
+ * **PKCE Flow:**
407
+ * 1. Client generates code_verifier (random string)
408
+ * 2. Client creates code_challenge = BASE64URL(SHA256(code_verifier))
409
+ * 3. Client sends code_challenge to authorization endpoint
410
+ * 4. Authorization server stores the code_challenge
411
+ * 5. Client sends code_verifier to token endpoint
412
+ * 6. Authorization server verifies: SHA256(code_verifier) == code_challenge
413
+ *
414
+ * **Security Benefits:**
415
+ * - Prevents authorization code interception attacks
416
+ * - Even if an attacker intercepts the authorization code, they cannot
417
+ * exchange it for tokens without the original code_verifier
418
+ * - The challenge is sent in the authorization request (public)
419
+ * - The verifier is sent in the token request (should be kept secret)
420
+ *
421
+ * **RFC 7636 Transformation Methods:**
422
+ * - plain: code_challenge = code_verifier (not recommended)
423
+ * - S256: code_challenge = BASE64URL(SHA256(code_verifier)) (recommended, used here)
424
+ *
425
+ * @see {@link https://datatracker.ietf.org/doc/html/rfc7636 | RFC 7636 - PKCE}
426
+ * @see {@link https://datatracker.ietf.org/doc/html/rfc4648#section-5 | RFC 4648 - Base64url Encoding}
427
+ * @see generateCodeVerifier for the verifier generation
428
+ *
429
+ * @internal
430
+ */
227
431
  static buildCodeChallenge(codeVerifier) {
228
432
  const hash = import_crypto2.default.createHash("sha256").update(codeVerifier).digest("base64");
229
433
  return hash.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
@@ -246,13 +450,16 @@ var Lixa = class _Lixa {
246
450
  */
247
451
  getAuthUrl(provider, state) {
248
452
  const providerType = String(provider).toLowerCase();
453
+ this.log("INFO", "Auth", `Generating authorization URL for provider: ${providerType}`);
249
454
  const providerConfig = this.findProviderByType(providerType);
250
- const providerImpl = _Lixa.CONFIGURED_PROVIDERS.get(providerType);
251
- if (!providerConfig || !providerImpl) {
252
- throw new Error(`Provider ${providerType} not configured`);
455
+ if (!providerConfig) {
456
+ this.log("ERROR", "Auth", `Provider '${String(provider)}' is not configured`);
457
+ throw new Error(`Provider '${String(provider)}' is not configured in this Lixa instance`);
253
458
  }
459
+ const providerImpl = this.getProvider(providerType, providerConfig);
254
460
  const codeVerifier = _Lixa.generateCodeVerifier();
255
461
  const codeChallenge = _Lixa.buildCodeChallenge(codeVerifier);
462
+ this.log("INFO", "State", `Saving state for provider: ${providerType}`, { state });
256
463
  this.stateDao.saveState(
257
464
  state,
258
465
  {
@@ -273,7 +480,12 @@ var Lixa = class _Lixa {
273
480
  code_challenge_method: "S256",
274
481
  ...providerConfig.extraConfig
275
482
  });
276
- return `${providerImpl.authorizationEndpoint}?${params.toString()}`;
483
+ const authUrl = `${providerImpl.authorizationEndpoint}?${params.toString()}`;
484
+ this.log("INFO", "Auth", `Authorization URL generated successfully`, {
485
+ provider: providerType,
486
+ endpoint: providerImpl.authorizationEndpoint
487
+ });
488
+ return authUrl;
277
489
  }
278
490
  /**
279
491
  * Handles the OAuth callback and creates a user session.
@@ -299,37 +511,50 @@ var Lixa = class _Lixa {
299
511
  code,
300
512
  state
301
513
  }) {
514
+ const providerType = String(provider).toLowerCase();
515
+ this.log("INFO", "Auth", `Handling OAuth callback for provider: ${providerType}`);
302
516
  if (!code || code.trim() === "") {
517
+ this.log("ERROR", "Auth", "Invalid or missing authorization code in callback");
303
518
  throw new Error("Invalid or missing code in callback");
304
519
  }
305
520
  if (!state || state.trim() === "") {
521
+ this.log("ERROR", "Auth", "Invalid or missing state in callback");
306
522
  throw new Error("Invalid or missing state in callback");
307
523
  }
524
+ this.log("INFO", "State", "Validating state parameter", { state });
308
525
  const cachedState = await this.stateDao.getState(state);
309
526
  if (!cachedState) {
527
+ this.log("ERROR", "State", "State validation failed: state not found or expired", { state });
310
528
  throw new Error("Invalid or expired state");
311
529
  }
530
+ this.log("INFO", "State", "State validated successfully, removing from cache");
312
531
  await this.stateDao.deleteState(state);
313
532
  const codeVerifier = cachedState.codeVerifier;
314
- const providerType = String(provider).toLowerCase();
315
533
  const providerConfig = this.findProviderByType(providerType);
316
- const providerImpl = _Lixa.CONFIGURED_PROVIDERS.get(providerType);
317
- if (!providerConfig || !providerImpl) {
318
- throw new Error(`Provider ${String(provider)} not configured`);
534
+ if (!providerConfig) {
535
+ this.log("ERROR", "Auth", `Provider '${String(provider)}' is not configured`);
536
+ throw new Error(`Provider '${String(provider)}' is not configured in this Lixa instance`);
319
537
  }
538
+ const providerImpl = this.getProvider(providerType, providerConfig);
539
+ this.log("INFO", "Token", `Exchanging authorization code for tokens`, { provider: providerType });
320
540
  const tokens = await this.exchangeCodeForToken(
321
541
  code,
322
542
  providerConfig,
323
543
  providerImpl,
324
544
  codeVerifier
325
545
  );
546
+ this.log("INFO", "Token", "Token exchange successful");
547
+ this.log("INFO", "Session", "Creating user session");
326
548
  const session = await this.sessionStrategy.createSession(tokens);
327
549
  const sessionId = (0, import_crypto.randomBytes)(32).toString("hex");
550
+ this.log("INFO", "Session", "Storing session", { sessionId });
328
551
  await this.sesionDao.saveSession(sessionId, session, 86400);
552
+ this.log("INFO", "Session", "Session created successfully", { sessionId });
329
553
  return sessionId;
330
554
  }
331
- fetchSessionInfo(sessionId) {
332
- return this.sesionDao.getSession(sessionId);
555
+ async fetchSessionInfo(sessionId) {
556
+ const sessionData = await this.sesionDao.getSession(sessionId);
557
+ return sessionData;
333
558
  }
334
559
  async exchangeCodeForToken(code, providerConfig, providerImpl, codeVerifier) {
335
560
  const body = {
@@ -343,8 +568,9 @@ var Lixa = class _Lixa {
343
568
  body.code_verifier = codeVerifier;
344
569
  }
345
570
  const params = new URLSearchParams(body);
346
- this.log("Token Exchange - Request body:", params.toString());
347
- this.log("Token Exchange - Token endpoint:", providerImpl.tokenEndpoint);
571
+ this.log("INFO", "Token", "Sending token exchange request", {
572
+ endpoint: providerImpl.tokenEndpoint
573
+ });
348
574
  const response = await fetch(providerImpl.tokenEndpoint, {
349
575
  method: "POST",
350
576
  headers: {
@@ -355,15 +581,25 @@ var Lixa = class _Lixa {
355
581
  });
356
582
  if (!response.ok) {
357
583
  const errorBody = await response.text();
358
- this.logError("Token Exchange - Error response:", errorBody);
584
+ this.log("ERROR", "Token", "Token exchange failed", {
585
+ status: response.status,
586
+ statusText: response.statusText,
587
+ error: errorBody
588
+ });
359
589
  throw new Error(
360
590
  `Token exchange failed: ${response.status} ${response.statusText} - ${errorBody}`
361
591
  );
362
592
  }
593
+ this.log("INFO", "Token", "Token exchange response received successfully");
363
594
  return response.json();
364
595
  }
365
596
  findProviderByType(providerType) {
366
- return this.config.providers[providerType];
597
+ for (const [key, value] of Object.entries(this.config.providers)) {
598
+ if (key.toLowerCase() === providerType.toLowerCase()) {
599
+ return value;
600
+ }
601
+ }
602
+ return void 0;
367
603
  }
368
604
  };
369
605
  // Annotate the CommonJS export names for ESM import in node:
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/lixa.ts","../src/dao/state-cache.ts","../src/dao/session-cache.ts","../src/models/session.ts"],"sourcesContent":["/**\n * A flexible, provider-agnostic OAuth 2.0 and OpenID Connect (OIDC) client library for backend applications.\n * \n * @remarks\n * This package simplifies multi-provider authentication flows (e.g., Google, GitHub), supports extensible session management, and enables custom provider registration.\n * \n * @packageDocumentation\n */\n\nexport { Lixa } from \"./lixa\";\nexport {\n type ProviderConfig,\n type LixaConfig,\n type SafeLixaConfig,\n} from \"./types\";\nexport { type Session, type SessionStrategy, DefaultSessionStrategy } from \"./models/session\";\nexport { type IProvider } from \"./providers\";\n","import { randomBytes } from \"crypto\";\nimport { type LixaConfig, type ProviderConfig } from \"./types\";\nimport { IProvider } from \"./providers\";\nimport { LocalStateCache } from \"./dao/state-cache\";\nimport { SessionDao, StateDao } from \"./dao/types\";\nimport crypto from \"crypto\";\nimport { LocalSessionCache } from \"./dao/session-cache\";\nimport { type Session, type SessionStrategy, DefaultSessionStrategy } from \"./models/session\";\n\n/**\n * Global registry of registered provider names\n */\ntype RegisteredProviders = string;\n\n/**\n * Type representing the keys of configured providers\n */\ntype ConfiguredProviderKey<T extends LixaConfig<any>> = keyof T['providers'];\n\n/**\n * A flexible, provider-agnostic OAuth 2.0 and OpenID Connect (OIDC) client library.\n *\n * @remarks\n * Lixa simplifies multi-provider authentication flows and supports extensible session management.\n *\n * @example\n * ```typescript\n * import { Lixa } from '@vunexa/lixa';\n * import { GoogleProvider } from '@vunexa/lixa/providers';\n * \n * // Register providers before using them\n * Lixa.registerProvider({ google: new GoogleProvider() });\n * \n * const config = Lixa.createConfig({\n * providers: {\n * google: {\n * clientId: 'your-client-id',\n * clientSecret: 'your-client-secret',\n * redirectUri: 'https://yourapp.com/auth/google/callback',\n * scopes: ['openid', 'email', 'profile']\n * }\n * }\n * });\n * \n * const lixa = new Lixa(config);\n * ```\n *\n * @public\n */\nclass Lixa<TConfig extends LixaConfig<any> = LixaConfig> {\n private static CONFIGURED_PROVIDERS: Map<string, IProvider> = new Map();\n private static LOCAL_STATE_CACHE = new LocalStateCache();\n private static LOCAL_SESSION_CACHE = new LocalSessionCache();\n private static DEFAULT_SESSION_STRATEGY = new DefaultSessionStrategy();\n private config: TConfig;\n private stateDao: StateDao;\n private sesionDao: SessionDao;\n private sessionStrategy: SessionStrategy;\n private debug: boolean;\n\n /**\n * Creates a new Lixa instance with the provided configuration.\n *\n * @param config - The configuration object containing provider settings and optional session strategy\n */\n constructor(config: TConfig) {\n // Validate that all providers in config are registered\n const configuredProviders = Object.keys(config.providers);\n const registeredProviders = Lixa.getRegisteredProviders();\n \n for (const provider of configuredProviders) {\n if (!registeredProviders.includes(provider.toLowerCase())) {\n throw new Error(`Provider '${provider}' is not registered. Please register it first using Lixa.registerProvider()`);\n }\n }\n \n this.config = config;\n this.stateDao = config.stateDao || Lixa.LOCAL_STATE_CACHE;\n this.sesionDao = config.sessionDao || Lixa.LOCAL_SESSION_CACHE;\n this.sessionStrategy = config.sessionStrategy || Lixa.DEFAULT_SESSION_STRATEGY;\n this.debug = config.debug || false;\n }\n\n private log(...args: any[]) {\n if (this.debug) {\n console.log('[Lixa]', ...args);\n }\n }\n\n private logError(...args: any[]) {\n if (this.debug) {\n console.error('[Lixa]', ...args);\n }\n }\n\n /**\n * Checks if a provider is both registered and configured for this instance.\n * This is a type guard that narrows the provider type for use with getAuthUrl.\n *\n * @param provider - The provider name to check (case-insensitive)\n * @returns True if the provider is registered and configured, false otherwise\n *\n * @example\n * ```typescript\n * if (lixa.isProviderConfigured(provider)) {\n * // TypeScript now knows provider is a valid ConfiguredProviderKey\n * const authUrl = lixa.getAuthUrl(provider, state);\n * }\n * ```\n */\n public isProviderConfigured<T extends string>(provider: T): provider is T & ConfiguredProviderKey<TConfig> {\n const providerType = provider.toLowerCase();\n return Lixa.CONFIGURED_PROVIDERS.has(providerType) &&\n this.config.providers.hasOwnProperty(providerType);\n }\n\n /**\n * Registers custom OAuth providers for use with Lixa.\n *\n * @param providerMap - A map of provider names to IProvider implementations\n *\n * @example\n * ```typescript\n * class CustomProvider implements IProvider {\n * authorizationEndpoint = 'https://custom.com/oauth/authorize';\n * tokenEndpoint = 'https://custom.com/oauth/token';\n * userInfoEndpoint = 'https://custom.com/api/user';\n * }\n *\n * Lixa.registerProvider({ custom: new CustomProvider() });\n * ```\n */\n public static registerProvider<T extends Record<string, IProvider>>(providerMap: T): void {\n Object.entries(providerMap).forEach(([key, providerImpl]) => {\n Lixa.CONFIGURED_PROVIDERS.set(key.toLowerCase(), providerImpl);\n });\n }\n\n /**\n * Gets the list of registered provider names.\n * \n * @returns Array of registered provider names\n */\n public static getRegisteredProviders(): string[] {\n return Array.from(Lixa.CONFIGURED_PROVIDERS.keys());\n }\n\n /**\n * Creates a type-safe configuration that only allows registered providers.\n * \n * @param config - Configuration object with providers that must be registered\n * @returns The same configuration object, but with type safety for registered providers\n */\n public static createConfig<T extends Record<string, ProviderConfig>>(\n config: LixaConfig<keyof T & string> & { providers: T }\n ): LixaConfig<keyof T & string> {\n // Validate that all providers in config are registered\n const configuredProviders = Object.keys(config.providers);\n const registeredProviders = Lixa.getRegisteredProviders();\n \n for (const provider of configuredProviders) {\n if (!registeredProviders.includes(provider.toLowerCase())) {\n throw new Error(`Provider '${provider}' is not registered. Please register it first using Lixa.registerProvider()`);\n }\n }\n \n return config;\n }\n\n /**\n * Generates a cryptographically secure random state parameter for OAuth flows.\n *\n * @returns A 32-character hexadecimal string\n *\n * @remarks\n * The state parameter is used to prevent CSRF attacks in OAuth flows.\n */\n public static generateRandomState(): string {\n return randomBytes(16).toString(\"hex\");\n }\n\n /**\n * Generates a cryptographically secure code verifier for PKCE flows.\n *\n * @returns A 64-character hexadecimal string\n *\n * @remarks\n * The code verifier is used in PKCE (Proof Key for Code Exchange) to enhance security.\n */\n private static generateCodeVerifier(): string {\n return randomBytes(32).toString(\"hex\");\n }\n\n private static buildCodeChallenge(codeVerifier: string): string {\n const hash = crypto\n .createHash(\"sha256\")\n .update(codeVerifier)\n .digest(\"base64\");\n\n // Convert to base64url\n return hash.replace(/\\+/g, \"-\").replace(/\\//g, \"_\").replace(/=+$/, \"\");\n }\n\n /**\n * Generates the authorization URL for the specified provider.\n *\n * @param provider - The provider name (must be a configured provider key)\n * @param state - The state parameter for CSRF protection\n * @returns The complete authorization URL to redirect users to\n *\n * @throws Error when the provider is not configured\n *\n * @example\n * ```typescript\n * const state = Lixa.generateRandomState();\n * const authUrl = lixa.getAuthUrl('google', state);\n * res.redirect(authUrl);\n * ```\n */\n public getAuthUrl(provider: ConfiguredProviderKey<TConfig> | string, state: string): string {\n const providerType = String(provider).toLowerCase();\n const providerConfig = this.findProviderByType(providerType);\n const providerImpl = Lixa.CONFIGURED_PROVIDERS.get(providerType);\n\n if (!providerConfig || !providerImpl) {\n throw new Error(`Provider ${providerType} not configured`);\n }\n\n const codeVerifier = Lixa.generateCodeVerifier();\n const codeChallenge = Lixa.buildCodeChallenge(codeVerifier);\n\n // Cache the state paramaeter with TTL of 5 minutes (300 seconds)\n // We dont care about value. we are onl interested in key existence\n this.stateDao.saveState(\n state,\n {\n createdAt: Date.now(),\n provider: providerType,\n codeVerifier,\n },\n 300 // 5 minutes in seconds\n );\n\n const params = new URLSearchParams({\n client_id: providerConfig.clientId,\n redirect_uri: providerConfig.redirectUri,\n scope: providerConfig.scopes.join(\" \"),\n state,\n response_type: \"code\",\n code_challenge: codeChallenge,\n code_challenge_method: \"S256\",\n ...providerConfig.extraConfig,\n });\n\n return `${providerImpl.authorizationEndpoint}?${params.toString()}`;\n }\n\n /**\n * Handles the OAuth callback and creates a user session.\n *\n * @param provider - The provider name (must be a configured provider key)\n * @param code - The authorization code from the provider\n * @param state - The state parameter for validation\n * @returns A Promise that resolves to the session ID\n *\n * @throws Error when code or state is missing/invalid, or provider is not configured\n *\n * @example\n * ```typescript\n * const sessionId = await lixa.handleCallback({\n * provider: 'google',\n * code: req.query.code,\n * state: req.query.state\n * });\n * ```\n */\n public async handleCallback({\n provider,\n code,\n state,\n }: {\n provider: ConfiguredProviderKey<TConfig> | string;\n code: string;\n state?: string;\n }): Promise<string> {\n if (!code || code.trim() === \"\") {\n throw new Error(\"Invalid or missing code in callback\");\n }\n\n if (!state || state.trim() === \"\") {\n throw new Error(\"Invalid or missing state in callback\");\n }\n\n //Validate state here\n const cachedState = await this.stateDao.getState(state);\n if (!cachedState) {\n throw new Error(\"Invalid or expired state\");\n }\n // State is valid, remove it from cache to prevent reuse\n await this.stateDao.deleteState(state);\n\n //Get code verifier from cached state\n const codeVerifier = cachedState.codeVerifier;\n\n const providerType = String(provider).toLowerCase();\n const providerConfig = this.findProviderByType(providerType);\n const providerImpl = Lixa.CONFIGURED_PROVIDERS.get(providerType);\n\n if (!providerConfig || !providerImpl) {\n throw new Error(`Provider ${String(provider)} not configured`);\n }\n\n // Exchange code for tokens and fetch user info here.\n const tokens = await this.exchangeCodeForToken(\n code,\n providerConfig,\n providerImpl,\n codeVerifier\n );\n\n\n const session = await this.sessionStrategy.createSession(tokens);\n\n // Generate unique session ID\n const sessionId = randomBytes(32).toString(\"hex\");\n\n // Store session with 24 hour TTL (86400 seconds)\n await this.sesionDao.saveSession(sessionId, session, 86400);\n\n return sessionId;\n }\n\n public fetchSessionInfo(sessionId: string): Promise<Session | null> {\n return this.sesionDao.getSession(sessionId);\n }\n\n private async exchangeCodeForToken(\n code: string,\n providerConfig: ProviderConfig,\n providerImpl: IProvider,\n codeVerifier: string\n ): Promise<any> {\n // Build the request body\n const body: Record<string, string> = {\n client_id: providerConfig.clientId,\n client_secret: providerConfig.clientSecret,\n code,\n redirect_uri: providerConfig.redirectUri,\n grant_type: \"authorization_code\",\n };\n\n if (codeVerifier) {\n body.code_verifier = codeVerifier;\n }\n const params = new URLSearchParams(body);\n\n this.log('Token Exchange - Request body:', params.toString());\n this.log('Token Exchange - Token endpoint:', providerImpl.tokenEndpoint);\n \n const response = await fetch(providerImpl.tokenEndpoint, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/x-www-form-urlencoded\",\n Accept: \"application/json\",\n },\n body: params.toString(),\n });\n\n if (!response.ok) {\n const errorBody = await response.text();\n this.logError('Token Exchange - Error response:', errorBody);\n throw new Error(\n `Token exchange failed: ${response.status} ${response.statusText} - ${errorBody}`\n );\n }\n\n return response.json();\n }\n\n private findProviderByType(providerType: string): ProviderConfig | undefined {\n return this.config.providers[providerType];\n }\n}\n\nexport { Lixa };\n","import NodeCache from 'node-cache';\nimport { StateDao } from \"./types\";\n\nclass LocalStateCache implements StateDao {\n private cache: NodeCache;\n\n constructor(defaultTtlSeconds: number = 600) {\n this.cache = new NodeCache({ stdTTL: defaultTtlSeconds });\n }\n\n async saveState(state: string, data: any, expiresInSeconds: number): Promise<void> {\n this.cache.set(state, data, expiresInSeconds);\n }\n\n async getState(state: string): Promise<any | null> {\n return this.cache.get(state) || null;\n }\n\n async deleteState(state: string): Promise<void> {\n this.cache.del(state);\n }\n}\n\nexport { LocalStateCache };\n","import NodeCache from 'node-cache';\nimport { SessionDao } from \"./types\";\n\nclass LocalSessionCache implements SessionDao {\n private cache: NodeCache;\n\n constructor(defaultTtlSeconds: number = 600) {\n this.cache = new NodeCache({ stdTTL: defaultTtlSeconds });\n }\n\n async saveSession(state: string, data: any, expiresInSeconds: number): Promise<void> {\n this.cache.set(state, data, expiresInSeconds);\n }\n\n async getSession(state: string): Promise<any | null> {\n return this.cache.get(state) || null;\n }\n\n async deleteSession(state: string): Promise<void> {\n this.cache.del(state);\n }\n}\n\nexport { LocalSessionCache };\n","/**\n * Represents a user session after successful OAuth authentication.\n *\n * @public\n */\nexport interface Session {\n /** The session token (typically the access token) */\n token: string;\n /** Raw token data from the OAuth provider */\n raw: any;\n}\n\n/**\n * Strategy interface for custom session creation.\n *\n * @public\n */\nexport interface SessionStrategy {\n /**\n * Creates a session from OAuth token data.\n *\n * @param userInfo - The token data received from the OAuth provider\n * @returns A Promise that resolves to a Session object\n */\n createSession(userInfo: any): Promise<Session>;\n}\n\n/**\n * Default session strategy that works with any OAuth provider.\n * Extracts common token information and creates a standardized session.\n *\n * @public\n */\nexport class DefaultSessionStrategy implements SessionStrategy {\n /**\n * Creates a session from OAuth token data.\n * Handles common OAuth token formats and extracts the access token.\n *\n * @param tokenData - The token data received from the OAuth provider\n * @returns A Promise that resolves to a Session object\n */\n async createSession(tokenData: any): Promise<Session> {\n // Extract access token from various possible formats\n const accessToken = tokenData.access_token || \n tokenData.accessToken || \n tokenData.token ||\n tokenData;\n\n if (!accessToken || typeof accessToken !== 'string') {\n throw new Error('No valid access token found in OAuth response');\n }\n\n return {\n token: accessToken,\n raw: tokenData,\n };\n }\n}"],"mappings":"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","names":["NodeCache","import_crypto","import_node_cache","NodeCache","crypto"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/lixa.ts","../src/dao/state-cache.ts","../src/dao/session-cache.ts","../src/models/session.ts"],"sourcesContent":["/**\n * A flexible, provider-agnostic OAuth 2.0 and OpenID Connect (OIDC) client library for backend applications.\n * \n * @remarks\n * This package simplifies multi-provider authentication flows (e.g., Google, GitHub), supports extensible session management, and enables custom provider registration.\n * \n * Key features:\n * - OAuth 2.0 authorization code flow with PKCE (RFC 6749, RFC 7636)\n * - OpenID Connect support\n * - Built-in providers available in \\@vunexa/lixa-providers\n * - Custom provider support via IProvider interface\n * - Extensible session management via SessionStrategy\n * - Pluggable state and session storage via StateDao and SessionDao\n * - TypeScript-first with comprehensive type safety\n * \n * @packageDocumentation\n */\n\nexport { Lixa } from \"./lixa\";\nexport {\n type ProviderConfig,\n type LixaConfig,\n type SafeLixaConfig,\n type IProvider,\n type SessionStrategy,\n type Session,\n type StateDao,\n type SessionDao,\n type StateData,\n} from \"./types\";\nexport { DefaultSessionStrategy } from \"./models/session\";\n","import { randomBytes } from \"crypto\";\nimport { type LixaConfig, type ProviderConfig } from \"./types\";\nimport { IProvider } from \"./providers\";\nimport { LocalStateCache } from \"./dao/state-cache\";\nimport { SessionDao, StateDao } from \"./dao/types\";\nimport crypto from \"crypto\";\nimport { LocalSessionCache } from \"./dao/session-cache\";\nimport { type Session, type SessionStrategy, DefaultSessionStrategy, type OAuthTokenResponse } from \"./models/session\";\n\n/**\n * Type representing the keys of configured providers\n */\ntype ConfiguredProviderKey<T extends LixaConfig<Record<string, ProviderConfig>>> = keyof T['providers'];\n\n/**\n * A flexible, provider-agnostic OAuth 2.0 and OpenID Connect (OIDC) client library.\n *\n * @remarks\n * Lixa simplifies multi-provider authentication flows and supports extensible session management.\n * Providers can be passed inline in the configuration, eliminating the need for pre-registration.\n *\n * @example\n * Using built-in providers from \\@vunexa/lixa-providers:\n * ```typescript\n * import { Lixa } from '@vunexa/lixa';\n * import { GoogleProvider } from '@vunexa/lixa-providers';\n * \n * const lixa = new Lixa({\n * providers: {\n * google: {\n * provider: new GoogleProvider(),\n * clientId: 'your-client-id',\n * clientSecret: 'your-client-secret',\n * redirectUri: 'https://yourapp.com/auth/google/callback',\n * scopes: ['openid', 'email', 'profile']\n * }\n * }\n * });\n * ```\n * \n * @example\n * Using custom inline providers:\n * ```typescript\n * import { Lixa, IProvider } from '@vunexa/lixa';\n * \n * const customProvider: IProvider = {\n * authorizationEndpoint: 'https://custom.com/oauth/authorize',\n * tokenEndpoint: 'https://custom.com/oauth/token',\n * userInfoEndpoint: 'https://custom.com/api/user'\n * };\n * \n * const lixa = new Lixa({\n * providers: {\n * custom: {\n * provider: customProvider,\n * clientId: 'your-client-id',\n * clientSecret: 'your-client-secret',\n * redirectUri: 'https://yourapp.com/auth/custom/callback',\n * scopes: ['read:user']\n * }\n * }\n * });\n * ```\n *\n * @public\n */\nclass Lixa<TConfig extends LixaConfig<Record<string, ProviderConfig>> = LixaConfig> {\n private static DEFAULT_PROVIDERS: Map<string, IProvider> = new Map();\n private static CONFIGURED_PROVIDERS: Map<string, IProvider> = new Map(); // Legacy registry for backward compatibility\n private static LOCAL_STATE_CACHE = new LocalStateCache();\n private static LOCAL_SESSION_CACHE = new LocalSessionCache();\n private static DEFAULT_SESSION_STRATEGY = new DefaultSessionStrategy();\n private config: TConfig;\n private stateDao: StateDao;\n private sesionDao: SessionDao;\n private sessionStrategy: SessionStrategy;\n private debug: boolean;\n\n /**\n * Creates a new Lixa instance with the provided configuration.\n * \n * @remarks\n * Providers can be passed inline in the configuration using the `provider` field.\n * Provider resolution priority: inline custom provider \\> default providers \\> legacy registry.\n * \n * @param config - The configuration object containing provider settings and optional session strategy\n * \n * @throws Error when provider configuration is missing required fields\n * @throws Error when provider implementation is missing required properties\n * @throws Error when provider is not available and no inline implementation is provided\n */\n constructor(config: TConfig) {\n this.config = config;\n this.stateDao = config.stateDao || Lixa.LOCAL_STATE_CACHE;\n this.sesionDao = config.sessionDao || Lixa.LOCAL_SESSION_CACHE;\n this.sessionStrategy = config.sessionStrategy || Lixa.DEFAULT_SESSION_STRATEGY;\n this.debug = config.debug || false;\n \n this.log('INFO', 'Init', 'Initializing Lixa instance', { \n providers: Object.keys(config.providers),\n debug: this.debug \n });\n \n // Validate and extract providers from configuration\n for (const [providerName, providerConfig] of Object.entries(config.providers)) {\n const name = providerName.toLowerCase();\n const typedConfig = providerConfig as ProviderConfig;\n \n // Validate provider configuration has required credentials\n this.validateProviderConfig(providerName, typedConfig);\n \n // If provider config includes a custom provider implementation, validate it\n if (typedConfig.provider) {\n this.validateProviderImplementation(providerName, typedConfig.provider);\n this.log('INFO', 'Init', `Registered inline provider: ${providerName}`);\n } else {\n // Check if it's available in default providers or legacy registry\n if (!Lixa.DEFAULT_PROVIDERS.has(name) && !Lixa.CONFIGURED_PROVIDERS.has(name)) {\n this.log('ERROR', 'Init', `Provider '${providerName}' not available`);\n throw new Error(\n `Provider '${providerName}' is not available. ` +\n `Either import it from '@vunexa/lixa-providers' and include it in the configuration, ` +\n `or provide a custom implementation using the 'provider' field: ` +\n `{ provider: new CustomProvider(), clientId: '...', ... }`\n );\n }\n this.log('INFO', 'Init', `Using registered provider: ${providerName}`);\n }\n }\n \n this.log('INFO', 'Init', 'Lixa instance initialized successfully');\n }\n \n /**\n * Validates that a provider configuration has all required credentials.\n * \n * @param name - The provider name\n * @param config - The provider configuration\n * @throws Error when required fields are missing or invalid\n */\n private validateProviderConfig(name: string, config: ProviderConfig): void {\n const requiredFields: (keyof ProviderConfig)[] = ['clientId', 'clientSecret', 'redirectUri', 'scopes'];\n const missingFields = requiredFields.filter(field => {\n const value = config[field];\n return value === undefined || value === null || (typeof value === 'string' && value.trim() === '');\n });\n \n if (missingFields.length > 0) {\n throw new Error(\n `Provider '${name}' configuration is missing required fields: ${missingFields.join(', ')}`\n );\n }\n \n // Validate scopes is an array\n if (!Array.isArray(config.scopes)) {\n throw new Error(\n `Provider '${name}' configuration error: 'scopes' must be an array of strings`\n );\n }\n \n if (config.scopes.length === 0) {\n throw new Error(\n `Provider '${name}' configuration error: 'scopes' array cannot be empty`\n );\n }\n }\n \n /**\n * Validates that a provider implementation has all required properties.\n * \n * @param name - The provider name\n * @param provider - The provider implementation\n * @throws Error when required properties are missing\n */\n private validateProviderImplementation(name: string, provider: IProvider): void {\n const requiredProps: (keyof IProvider)[] = ['authorizationEndpoint', 'tokenEndpoint', 'userInfoEndpoint'];\n const missingProps = requiredProps.filter(prop => {\n const value = provider[prop];\n return !value || typeof value !== 'string' || value.trim() === '';\n });\n \n if (missingProps.length > 0) {\n throw new Error(\n `Provider '${name}' implementation is missing required properties: ${missingProps.join(', ')}. ` +\n `All IProvider implementations must define: authorizationEndpoint, tokenEndpoint, and userInfoEndpoint.`\n );\n }\n }\n\n /**\n * Structured debug logging with standardized format.\n * \n * @param level - Log level (INFO, WARN, ERROR)\n * @param context - Context of the log (Init, Auth, Token, Session, State)\n * @param message - Log message\n * @param data - Optional data to log\n * \n * @remarks\n * Format: [Lixa] [timestamp] [level] [context] message\n * Only logs when debug mode is enabled.\n */\n private log(level: 'INFO' | 'WARN' | 'ERROR', context: 'Init' | 'Auth' | 'Token' | 'Session' | 'State', message: string, data?: Record<string, unknown>): void {\n if (!this.debug) return;\n \n const timestamp = new Date().toISOString();\n const prefix = `[Lixa] [${timestamp}] [${level}] [${context}]`;\n \n if (data !== undefined) {\n console.log(`${prefix} ${message}`, data);\n } else {\n console.log(`${prefix} ${message}`);\n }\n }\n\n /**\n * Checks if a provider is configured for this instance.\n * This is a type guard that narrows the provider type for use with getAuthUrl.\n *\n * @param provider - The provider name to check (case-insensitive)\n * @returns True if the provider is configured, false otherwise\n *\n * @example\n * ```typescript\n * if (lixa.isProviderConfigured(provider)) {\n * // TypeScript now knows provider is a valid ConfiguredProviderKey\n * const authUrl = lixa.getAuthUrl(provider, state);\n * }\n * ```\n */\n public isProviderConfigured<T extends string>(provider: T): provider is T & ConfiguredProviderKey<TConfig> {\n const providerType = provider.toLowerCase();\n return this.config.providers.hasOwnProperty(providerType);\n }\n \n /**\n * Gets a provider implementation by name.\n * Resolution priority: inline custom provider \\> default providers \\> legacy registry\n * \n * @param name - The provider name (case-insensitive)\n * @param config - The provider configuration\n * @returns The provider implementation\n * @throws Error when provider is not found\n */\n private getProvider(name: string, config: ProviderConfig): IProvider {\n // First check if provider is inline in config\n if (config.provider) {\n return config.provider;\n }\n \n // Then check default providers\n const lowerName = name.toLowerCase();\n const defaultProvider = Lixa.DEFAULT_PROVIDERS.get(lowerName);\n if (defaultProvider) {\n return defaultProvider;\n }\n \n // Finally check legacy registry for backward compatibility\n const legacyProvider = Lixa.CONFIGURED_PROVIDERS.get(lowerName);\n if (legacyProvider) {\n return legacyProvider;\n }\n \n throw new Error(\n `Provider '${name}' not found. ` +\n `Ensure the provider is included in the configuration with a 'provider' field, ` +\n `or registered using Lixa.registerProvider().`\n );\n }\n\n /**\n * Registers custom OAuth providers for use with Lixa.\n * \n * @deprecated This method is maintained for backward compatibility.\n * The recommended approach is to pass providers inline in the configuration:\n * ```typescript\n * const lixa = new Lixa({\n * providers: {\n * custom: {\n * provider: new CustomProvider(),\n * clientId: '...',\n * // ...\n * }\n * }\n * });\n * ```\n *\n * @param providerMap - A map of provider names to IProvider implementations\n *\n * @example\n * Legacy usage (still supported):\n * ```typescript\n * class CustomProvider implements IProvider {\n * authorizationEndpoint = 'https://custom.com/oauth/authorize';\n * tokenEndpoint = 'https://custom.com/oauth/token';\n * userInfoEndpoint = 'https://custom.com/api/user';\n * }\n *\n * Lixa.registerProvider({ custom: new CustomProvider() });\n * ```\n */\n public static registerProvider<T extends Record<string, IProvider>>(providerMap: T): void {\n Object.entries(providerMap).forEach(([key, providerImpl]) => {\n Lixa.CONFIGURED_PROVIDERS.set(key.toLowerCase(), providerImpl);\n });\n }\n\n /**\n * Gets the list of registered provider names.\n * \n * @returns Array of registered provider names\n */\n public static getRegisteredProviders(): string[] {\n return Array.from(Lixa.CONFIGURED_PROVIDERS.keys());\n }\n\n /**\n * Creates a type-safe configuration.\n * \n * @deprecated This method is maintained for backward compatibility.\n * You can now pass configuration directly to the Lixa constructor without this helper.\n * \n * @param config - Configuration object with provider settings\n * @returns The same configuration object with type safety\n * \n * @example\n * New approach (recommended):\n * ```typescript\n * const lixa = new Lixa({\n * providers: {\n * google: {\n * provider: new GoogleProvider(),\n * clientId: '...',\n * // ...\n * }\n * }\n * });\n * ```\n */\n public static createConfig<T extends Record<string, ProviderConfig>>(\n config: LixaConfig<T> & { providers: T }\n ): LixaConfig<T> {\n return config;\n }\n\n /**\n * Generates a cryptographically secure random state parameter for OAuth flows.\n *\n * @returns A 32-character hexadecimal string\n *\n * @remarks\n * The state parameter is used to prevent CSRF attacks in OAuth flows.\n */\n public static generateRandomState(): string {\n return randomBytes(16).toString(\"hex\");\n }\n\n /**\n * Generates a cryptographically secure code verifier for PKCE flows.\n *\n * @returns A 64-character hexadecimal string (32 random bytes encoded as hex)\n *\n * @remarks\n * This method implements the code verifier generation as specified in RFC 7636 (PKCE).\n * \n * **PKCE (Proof Key for Code Exchange)** is a security extension to OAuth 2.0 that\n * prevents authorization code interception attacks. It's especially important for\n * public clients (mobile apps, SPAs) but is recommended for all OAuth flows.\n * \n * **Generation methodology:**\n * 1. Generate 32 cryptographically random bytes using Node.js crypto.randomBytes()\n * 2. Encode the bytes as a hexadecimal string (64 characters)\n * 3. The verifier is stored securely and used later in the token exchange\n * \n * **RFC 7636 Requirements:**\n * - Minimum length: 43 characters\n * - Maximum length: 128 characters\n * - Character set: [A-Z] / [a-z] / [0-9] / \"-\" / \".\" / \"_\" / \"~\"\n * - This implementation produces 64 hex characters, meeting the requirements\n * \n * The code verifier is:\n * - Generated when creating the authorization URL\n * - Stored in state cache with the state parameter\n * - Retrieved during callback handling\n * - Sent to the token endpoint to prove the client's identity\n * \n * @see {@link https://datatracker.ietf.org/doc/html/rfc7636 | RFC 7636 - PKCE}\n * @see buildCodeChallenge for the corresponding challenge generation\n * \n * @internal\n */\n private static generateCodeVerifier(): string {\n return randomBytes(32).toString(\"hex\");\n }\n\n /**\n * Generates a code challenge from a code verifier for PKCE flows.\n *\n * @param codeVerifier - The code verifier string (64 hex characters)\n * @returns A base64url-encoded SHA-256 hash of the code verifier\n *\n * @remarks\n * This method implements the code challenge generation as specified in RFC 7636 (PKCE)\n * using the S256 (SHA-256) transformation method.\n * \n * **Challenge generation methodology:**\n * 1. Hash the code verifier using SHA-256\n * 2. Encode the hash as base64\n * 3. Convert to base64url format (RFC 4648):\n * - Replace '+' with '-'\n * - Replace '/' with '_'\n * - Remove trailing '=' padding\n * \n * **PKCE Flow:**\n * 1. Client generates code_verifier (random string)\n * 2. Client creates code_challenge = BASE64URL(SHA256(code_verifier))\n * 3. Client sends code_challenge to authorization endpoint\n * 4. Authorization server stores the code_challenge\n * 5. Client sends code_verifier to token endpoint\n * 6. Authorization server verifies: SHA256(code_verifier) == code_challenge\n * \n * **Security Benefits:**\n * - Prevents authorization code interception attacks\n * - Even if an attacker intercepts the authorization code, they cannot\n * exchange it for tokens without the original code_verifier\n * - The challenge is sent in the authorization request (public)\n * - The verifier is sent in the token request (should be kept secret)\n * \n * **RFC 7636 Transformation Methods:**\n * - plain: code_challenge = code_verifier (not recommended)\n * - S256: code_challenge = BASE64URL(SHA256(code_verifier)) (recommended, used here)\n * \n * @see {@link https://datatracker.ietf.org/doc/html/rfc7636 | RFC 7636 - PKCE}\n * @see {@link https://datatracker.ietf.org/doc/html/rfc4648#section-5 | RFC 4648 - Base64url Encoding}\n * @see generateCodeVerifier for the verifier generation\n * \n * @internal\n */\n private static buildCodeChallenge(codeVerifier: string): string {\n const hash = crypto\n .createHash(\"sha256\")\n .update(codeVerifier)\n .digest(\"base64\");\n\n // Convert to base64url (RFC 4648 Section 5)\n return hash.replace(/\\+/g, \"-\").replace(/\\//g, \"_\").replace(/=+$/, \"\");\n }\n\n /**\n * Generates the authorization URL for the specified provider.\n *\n * @param provider - The provider name (must be a configured provider key)\n * @param state - The state parameter for CSRF protection\n * @returns The complete authorization URL to redirect users to\n *\n * @throws Error when the provider is not configured\n *\n * @example\n * ```typescript\n * const state = Lixa.generateRandomState();\n * const authUrl = lixa.getAuthUrl('google', state);\n * res.redirect(authUrl);\n * ```\n */\n public getAuthUrl(provider: ConfiguredProviderKey<TConfig> | string, state: string): string {\n const providerType = String(provider).toLowerCase();\n \n this.log('INFO', 'Auth', `Generating authorization URL for provider: ${providerType}`);\n \n const providerConfig = this.findProviderByType(providerType);\n\n if (!providerConfig) {\n this.log('ERROR', 'Auth', `Provider '${String(provider)}' is not configured`);\n throw new Error(`Provider '${String(provider)}' is not configured in this Lixa instance`);\n }\n\n const providerImpl = this.getProvider(providerType, providerConfig);\n\n const codeVerifier = Lixa.generateCodeVerifier();\n const codeChallenge = Lixa.buildCodeChallenge(codeVerifier);\n\n this.log('INFO', 'State', `Saving state for provider: ${providerType}`, { state });\n\n // Cache the state paramaeter with TTL of 5 minutes (300 seconds)\n // We dont care about value. we are onl interested in key existence\n this.stateDao.saveState(\n state,\n {\n createdAt: Date.now(),\n provider: providerType,\n codeVerifier,\n },\n 300 // 5 minutes in seconds\n );\n\n const params = new URLSearchParams({\n client_id: providerConfig.clientId,\n redirect_uri: providerConfig.redirectUri,\n scope: providerConfig.scopes.join(\" \"),\n state,\n response_type: \"code\",\n code_challenge: codeChallenge,\n code_challenge_method: \"S256\",\n ...providerConfig.extraConfig,\n });\n\n const authUrl = `${providerImpl.authorizationEndpoint}?${params.toString()}`;\n this.log('INFO', 'Auth', `Authorization URL generated successfully`, { \n provider: providerType,\n endpoint: providerImpl.authorizationEndpoint \n });\n\n return authUrl;\n }\n\n /**\n * Handles the OAuth callback and creates a user session.\n *\n * @param provider - The provider name (must be a configured provider key)\n * @param code - The authorization code from the provider\n * @param state - The state parameter for validation\n * @returns A Promise that resolves to the session ID\n *\n * @throws Error when code or state is missing/invalid, or provider is not configured\n *\n * @example\n * ```typescript\n * const sessionId = await lixa.handleCallback({\n * provider: 'google',\n * code: req.query.code,\n * state: req.query.state\n * });\n * ```\n */\n public async handleCallback({\n provider,\n code,\n state,\n }: {\n provider: ConfiguredProviderKey<TConfig> | string;\n code: string;\n state?: string;\n }): Promise<string> {\n const providerType = String(provider).toLowerCase();\n this.log('INFO', 'Auth', `Handling OAuth callback for provider: ${providerType}`);\n\n if (!code || code.trim() === \"\") {\n this.log('ERROR', 'Auth', 'Invalid or missing authorization code in callback');\n throw new Error(\"Invalid or missing code in callback\");\n }\n\n if (!state || state.trim() === \"\") {\n this.log('ERROR', 'Auth', 'Invalid or missing state in callback');\n throw new Error(\"Invalid or missing state in callback\");\n }\n\n this.log('INFO', 'State', 'Validating state parameter', { state });\n\n //Validate state here\n const cachedState = await this.stateDao.getState(state);\n if (!cachedState) {\n this.log('ERROR', 'State', 'State validation failed: state not found or expired', { state });\n throw new Error(\"Invalid or expired state\");\n }\n \n this.log('INFO', 'State', 'State validated successfully, removing from cache');\n // State is valid, remove it from cache to prevent reuse\n await this.stateDao.deleteState(state);\n\n //Get code verifier from cached state\n const codeVerifier = cachedState.codeVerifier;\n\n const providerConfig = this.findProviderByType(providerType);\n\n if (!providerConfig) {\n this.log('ERROR', 'Auth', `Provider '${String(provider)}' is not configured`);\n throw new Error(`Provider '${String(provider)}' is not configured in this Lixa instance`);\n }\n\n const providerImpl = this.getProvider(providerType, providerConfig);\n\n this.log('INFO', 'Token', `Exchanging authorization code for tokens`, { provider: providerType });\n\n // Exchange code for tokens and fetch user info here.\n const tokens = await this.exchangeCodeForToken(\n code,\n providerConfig,\n providerImpl,\n codeVerifier\n );\n\n this.log('INFO', 'Token', 'Token exchange successful');\n\n this.log('INFO', 'Session', 'Creating user session');\n const session = await this.sessionStrategy.createSession(tokens);\n\n // Generate unique session ID\n const sessionId = randomBytes(32).toString(\"hex\");\n\n this.log('INFO', 'Session', 'Storing session', { sessionId });\n // Store session with 24 hour TTL (86400 seconds)\n await this.sesionDao.saveSession(sessionId, session, 86400);\n\n this.log('INFO', 'Session', 'Session created successfully', { sessionId });\n\n return sessionId;\n }\n\n public async fetchSessionInfo(sessionId: string): Promise<Session | null> {\n const sessionData = await this.sesionDao.getSession(sessionId);\n return sessionData as Session | null;\n }\n\n private async exchangeCodeForToken(\n code: string,\n providerConfig: ProviderConfig,\n providerImpl: IProvider,\n codeVerifier: string\n ): Promise<OAuthTokenResponse> {\n // Build the request body\n const body: Record<string, string> = {\n client_id: providerConfig.clientId,\n client_secret: providerConfig.clientSecret,\n code,\n redirect_uri: providerConfig.redirectUri,\n grant_type: \"authorization_code\",\n };\n\n if (codeVerifier) {\n body.code_verifier = codeVerifier;\n }\n const params = new URLSearchParams(body);\n\n this.log('INFO', 'Token', 'Sending token exchange request', { \n endpoint: providerImpl.tokenEndpoint \n });\n \n const response = await fetch(providerImpl.tokenEndpoint, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/x-www-form-urlencoded\",\n Accept: \"application/json\",\n },\n body: params.toString(),\n });\n\n if (!response.ok) {\n const errorBody = await response.text();\n this.log('ERROR', 'Token', 'Token exchange failed', { \n status: response.status, \n statusText: response.statusText,\n error: errorBody \n });\n throw new Error(\n `Token exchange failed: ${response.status} ${response.statusText} - ${errorBody}`\n );\n }\n\n this.log('INFO', 'Token', 'Token exchange response received successfully');\n return response.json();\n }\n\n private findProviderByType(providerType: string): ProviderConfig | undefined {\n // Use Object.entries to safely iterate and find the provider\n for (const [key, value] of Object.entries(this.config.providers)) {\n if (key.toLowerCase() === providerType.toLowerCase()) {\n return value as ProviderConfig;\n }\n }\n return undefined;\n }\n}\n\nexport { Lixa };\n","import NodeCache from 'node-cache';\nimport { StateDao, StateData } from \"./types\";\n\nclass LocalStateCache implements StateDao {\n private cache: NodeCache;\n\n constructor(defaultTtlSeconds: number = 600) {\n this.cache = new NodeCache({ stdTTL: defaultTtlSeconds });\n }\n\n async saveState(state: string, data: StateData, expiresInSeconds: number): Promise<void> {\n this.cache.set(state, data, expiresInSeconds);\n }\n\n async getState(state: string): Promise<StateData | null> {\n return this.cache.get<StateData>(state) || null;\n }\n\n async deleteState(state: string): Promise<void> {\n this.cache.del(state);\n }\n}\n\nexport { LocalStateCache };\n","import NodeCache from 'node-cache';\nimport { SessionDao } from \"./types\";\n\nclass LocalSessionCache implements SessionDao {\n private cache: NodeCache;\n\n constructor(defaultTtlSeconds: number = 600) {\n this.cache = new NodeCache({ stdTTL: defaultTtlSeconds });\n }\n\n async saveSession<T = unknown>(state: string, data: T, expiresInSeconds: number): Promise<void> {\n this.cache.set(state, data, expiresInSeconds);\n }\n\n async getSession<T = unknown>(state: string): Promise<T | null> {\n return this.cache.get<T>(state) || null;\n }\n\n async deleteSession(state: string): Promise<void> {\n this.cache.del(state);\n }\n}\n\nexport { LocalSessionCache };\n","/**\n * OAuth 2.0 token response structure.\n * Based on RFC 6749 Section 5.1 and OpenID Connect Core 1.0 Section 3.1.3.3\n * \n * @remarks\n * This interface represents the standard OAuth 2.0 token response with\n * optional OpenID Connect extensions. All OAuth providers should return\n * at minimum the required fields (access_token, token_type).\n * \n * @public\n */\nexport interface OAuthTokenResponse {\n /** \n * OAuth 2.0 access token (required).\n * Used to access protected resources on behalf of the user.\n */\n access_token: string;\n \n /** \n * Token type (required).\n * Typically \"Bearer\" for OAuth 2.0.\n */\n token_type: string;\n \n /** \n * Token expiration time in seconds (optional).\n * Time until the access token expires.\n */\n expires_in?: number;\n \n /** \n * OAuth 2.0 refresh token (optional).\n * Used to obtain new access tokens without re-authentication.\n */\n refresh_token?: string;\n \n /** \n * Granted OAuth scopes (optional).\n * Space-separated list of scopes that were granted.\n */\n scope?: string;\n \n /** \n * OpenID Connect ID token (optional).\n * JWT containing user identity claims (only present for OIDC providers).\n */\n id_token?: string;\n \n /**\n * Additional provider-specific fields.\n * Some providers may include extra fields like user_id, account_id, etc.\n */\n [key: string]: unknown;\n}\n\n/**\n * Represents a user session after successful OAuth authentication.\n * \n * @remarks\n * The Session object is returned by SessionStrategy.createSession() and contains\n * the session identifier and any additional data needed for your application.\n * \n * The structure is intentionally flexible to support various session management\n * approaches (JWT tokens, session IDs, etc.).\n *\n * @public\n */\nexport interface Session<TRaw = OAuthTokenResponse> {\n /** \n * The session token or identifier.\n * This could be an access token, a session ID, a JWT, or any other identifier\n * that your application uses to track authenticated users.\n */\n token: string;\n \n /** \n * Raw session data.\n * Contains the complete OAuth token response and any additional data\n * your SessionStrategy adds (user info, database IDs, etc.).\n * \n * Typical OAuth token data includes:\n * - access_token: OAuth access token\n * - refresh_token: OAuth refresh token (if requested)\n * - expires_in: Token expiration time in seconds\n * - token_type: Token type (usually \"Bearer\")\n * - id_token: OpenID Connect ID token (if using OIDC)\n * - scope: Granted scopes\n */\n raw: TRaw;\n}\n\n/**\n * Strategy interface for custom session creation.\n * \n * @remarks\n * Implement this interface to customize how OAuth tokens are converted into\n * application sessions. This is where you typically:\n * - Decode ID tokens (for OpenID Connect)\n * - Look up or create users in your database\n * - Generate session identifiers\n * - Store session data\n * - Add custom claims or metadata\n * \n * The default implementation (DefaultSessionStrategy) simply extracts the\n * access token and returns it as the session token.\n * \n * @example\n * Custom session strategy with database integration:\n * ```typescript\n * interface CustomSessionData extends OAuthTokenResponse {\n * userId: string;\n * email: string;\n * }\n * \n * class DatabaseSessionStrategy implements SessionStrategy {\n * constructor(private db: Database) {}\n * \n * async createSession(tokenData: OAuthTokenResponse): Promise<Session<CustomSessionData>> {\n * // Decode ID token for OIDC providers\n * const idToken = tokenData.id_token;\n * const payload = decodeJwt(idToken);\n * \n * // Create or update user in database\n * const user = await this.db.users.upsert({\n * email: payload.email,\n * name: payload.name,\n * picture: payload.picture\n * });\n * \n * // Generate session ID\n * const sessionId = generateSecureId();\n * \n * // Store session with tokens\n * await this.db.sessions.create({\n * id: sessionId,\n * userId: user.id,\n * accessToken: tokenData.access_token,\n * refreshToken: tokenData.refresh_token,\n * expiresAt: new Date(Date.now() + (tokenData.expires_in || 3600) * 1000)\n * });\n * \n * return {\n * token: sessionId,\n * raw: {\n * userId: user.id,\n * email: user.email,\n * ...tokenData\n * }\n * };\n * }\n * }\n * ```\n *\n * @public\n */\nexport interface SessionStrategy {\n /**\n * Creates a session from OAuth token data.\n * \n * @param tokenData - The token data received from the OAuth provider's token endpoint\n * @returns A Promise that resolves to a Session object\n * \n * @remarks\n * This method is called after successfully exchanging the authorization code\n * for tokens. The tokenData parameter contains the raw response from the\n * provider's token endpoint.\n * \n * Common token data fields:\n * - access_token: OAuth access token\n * - refresh_token: OAuth refresh token (optional)\n * - expires_in: Token expiration time in seconds\n * - token_type: Token type (usually \"Bearer\")\n * - id_token: OpenID Connect ID token (for OIDC providers)\n * - scope: Granted scopes\n * \n * @throws \\{Error\\} If session creation fails (e.g., database error, invalid token)\n * \n * @example\n * Simple implementation:\n * ```typescript\n * async createSession(tokenData: OAuthTokenResponse): Promise<Session> {\n * return {\n * token: tokenData.access_token,\n * raw: tokenData\n * };\n * }\n * ```\n */\n createSession(tokenData: OAuthTokenResponse): Promise<Session>;\n}\n\n/**\n * Default session strategy that works with any OAuth provider.\n * Extracts common token information and creates a standardized session.\n *\n * @public\n */\nexport class DefaultSessionStrategy implements SessionStrategy {\n /**\n * Creates a session from OAuth token data.\n * Handles common OAuth token formats and extracts the access token.\n *\n * @param tokenData - The token data received from the OAuth provider\n * @returns A Promise that resolves to a Session object\n */\n async createSession(tokenData: OAuthTokenResponse): Promise<Session> {\n if (!tokenData.access_token || typeof tokenData.access_token !== 'string') {\n throw new Error('No valid access token found in OAuth response');\n }\n\n return {\n token: tokenData.access_token,\n raw: tokenData,\n };\n }\n}"],"mappings":"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","names":["NodeCache","import_crypto","import_node_cache","NodeCache","crypto"]}