@vunexa/lixa 0.0.1-alpha.21 → 0.0.1-alpha.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +135 -58
- package/dist/dao/session-cache.d.ts +2 -2
- package/dist/dao/session-cache.d.ts.map +1 -1
- package/dist/dao/state-cache.d.ts +3 -3
- package/dist/dao/state-cache.d.ts.map +1 -1
- package/dist/dao/types.d.ts +13 -6
- package/dist/dao/types.d.ts.map +1 -1
- package/dist/export-types/index.d.ts +82 -21
- package/dist/index.cjs +9 -9
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +82 -22
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -9
- package/dist/index.js.map +1 -1
- package/dist/lixa.d.ts +7 -7
- package/dist/lixa.d.ts.map +1 -1
- package/dist/models/session.d.ts +60 -7
- package/dist/models/session.d.ts.map +1 -1
- package/dist/types.d.ts +2 -1
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -52,11 +52,11 @@ interface StateData {
|
|
|
52
52
|
* class RedisStateDao implements StateDao {
|
|
53
53
|
* constructor(private redis: RedisClient) {}
|
|
54
54
|
*
|
|
55
|
-
* async saveState(state: string, data:
|
|
55
|
+
* async saveState(state: string, data: StateData, expiresInSeconds: number): Promise<void> {
|
|
56
56
|
* await this.redis.setex(`oauth:state:${state}`, expiresInSeconds, JSON.stringify(data));
|
|
57
57
|
* }
|
|
58
58
|
*
|
|
59
|
-
* async getState(state: string): Promise<
|
|
59
|
+
* async getState(state: string): Promise<StateData | null> {
|
|
60
60
|
* const data = await this.redis.get(`oauth:state:${state}`);
|
|
61
61
|
* return data ? JSON.parse(data) : null;
|
|
62
62
|
* }
|
|
@@ -159,6 +159,8 @@ interface StateDao {
|
|
|
159
159
|
* @example
|
|
160
160
|
* Database implementation:
|
|
161
161
|
* ```typescript
|
|
162
|
+
* import { Session } from '../models/session';
|
|
163
|
+
*
|
|
162
164
|
* class DatabaseSessionDao implements SessionDao {
|
|
163
165
|
* constructor(private db: Database) {}
|
|
164
166
|
*
|
|
@@ -198,17 +200,21 @@ interface SessionDao {
|
|
|
198
200
|
*
|
|
199
201
|
* @remarks
|
|
200
202
|
* The session data structure is defined by your SessionStrategy implementation.
|
|
201
|
-
* The default strategy returns
|
|
203
|
+
* The default strategy returns a Session object with token and raw OAuth token response.
|
|
202
204
|
*
|
|
203
205
|
* @example
|
|
204
206
|
* ```typescript
|
|
205
207
|
* await sessionDao.saveSession('session-123', \{
|
|
206
208
|
* token: 'access-token',
|
|
207
|
-
* raw: \{
|
|
209
|
+
* raw: \{
|
|
210
|
+
* access_token: 'token',
|
|
211
|
+
* token_type: 'Bearer',
|
|
212
|
+
* expires_in: 3600
|
|
213
|
+
* \}
|
|
208
214
|
* \}, 86400);
|
|
209
215
|
* ```
|
|
210
216
|
*/
|
|
211
|
-
saveSession(sessionId: string, data:
|
|
217
|
+
saveSession<T = unknown>(sessionId: string, data: T, expiresInSeconds: number): Promise<void>;
|
|
212
218
|
/**
|
|
213
219
|
* Retrieves a session by ID.
|
|
214
220
|
*
|
|
@@ -217,6 +223,7 @@ interface SessionDao {
|
|
|
217
223
|
*
|
|
218
224
|
* @remarks
|
|
219
225
|
* This method is called to retrieve user session data for authenticated requests.
|
|
226
|
+
* The returned data should match the structure saved by saveSession.
|
|
220
227
|
*
|
|
221
228
|
* @example
|
|
222
229
|
* ```typescript
|
|
@@ -226,7 +233,7 @@ interface SessionDao {
|
|
|
226
233
|
* }
|
|
227
234
|
* ```
|
|
228
235
|
*/
|
|
229
|
-
getSession(sessionId: string): Promise<
|
|
236
|
+
getSession<T = unknown>(sessionId: string): Promise<T | null>;
|
|
230
237
|
/**
|
|
231
238
|
* Deletes a session (e.g., on logout).
|
|
232
239
|
*
|
|
@@ -243,6 +250,54 @@ interface SessionDao {
|
|
|
243
250
|
deleteSession(sessionId: string): Promise<void>;
|
|
244
251
|
}
|
|
245
252
|
|
|
253
|
+
/**
|
|
254
|
+
* OAuth 2.0 token response structure.
|
|
255
|
+
* Based on RFC 6749 Section 5.1 and OpenID Connect Core 1.0 Section 3.1.3.3
|
|
256
|
+
*
|
|
257
|
+
* @remarks
|
|
258
|
+
* This interface represents the standard OAuth 2.0 token response with
|
|
259
|
+
* optional OpenID Connect extensions. All OAuth providers should return
|
|
260
|
+
* at minimum the required fields (access_token, token_type).
|
|
261
|
+
*
|
|
262
|
+
* @public
|
|
263
|
+
*/
|
|
264
|
+
interface OAuthTokenResponse {
|
|
265
|
+
/**
|
|
266
|
+
* OAuth 2.0 access token (required).
|
|
267
|
+
* Used to access protected resources on behalf of the user.
|
|
268
|
+
*/
|
|
269
|
+
access_token: string;
|
|
270
|
+
/**
|
|
271
|
+
* Token type (required).
|
|
272
|
+
* Typically "Bearer" for OAuth 2.0.
|
|
273
|
+
*/
|
|
274
|
+
token_type: string;
|
|
275
|
+
/**
|
|
276
|
+
* Token expiration time in seconds (optional).
|
|
277
|
+
* Time until the access token expires.
|
|
278
|
+
*/
|
|
279
|
+
expires_in?: number;
|
|
280
|
+
/**
|
|
281
|
+
* OAuth 2.0 refresh token (optional).
|
|
282
|
+
* Used to obtain new access tokens without re-authentication.
|
|
283
|
+
*/
|
|
284
|
+
refresh_token?: string;
|
|
285
|
+
/**
|
|
286
|
+
* Granted OAuth scopes (optional).
|
|
287
|
+
* Space-separated list of scopes that were granted.
|
|
288
|
+
*/
|
|
289
|
+
scope?: string;
|
|
290
|
+
/**
|
|
291
|
+
* OpenID Connect ID token (optional).
|
|
292
|
+
* JWT containing user identity claims (only present for OIDC providers).
|
|
293
|
+
*/
|
|
294
|
+
id_token?: string;
|
|
295
|
+
/**
|
|
296
|
+
* Additional provider-specific fields.
|
|
297
|
+
* Some providers may include extra fields like user_id, account_id, etc.
|
|
298
|
+
*/
|
|
299
|
+
[key: string]: unknown;
|
|
300
|
+
}
|
|
246
301
|
/**
|
|
247
302
|
* Represents a user session after successful OAuth authentication.
|
|
248
303
|
*
|
|
@@ -255,7 +310,7 @@ interface SessionDao {
|
|
|
255
310
|
*
|
|
256
311
|
* @public
|
|
257
312
|
*/
|
|
258
|
-
interface Session {
|
|
313
|
+
interface Session<TRaw = OAuthTokenResponse> {
|
|
259
314
|
/**
|
|
260
315
|
* The session token or identifier.
|
|
261
316
|
* This could be an access token, a session ID, a JWT, or any other identifier
|
|
@@ -275,7 +330,7 @@ interface Session {
|
|
|
275
330
|
* - id_token: OpenID Connect ID token (if using OIDC)
|
|
276
331
|
* - scope: Granted scopes
|
|
277
332
|
*/
|
|
278
|
-
raw:
|
|
333
|
+
raw: TRaw;
|
|
279
334
|
}
|
|
280
335
|
/**
|
|
281
336
|
* Strategy interface for custom session creation.
|
|
@@ -295,10 +350,15 @@ interface Session {
|
|
|
295
350
|
* @example
|
|
296
351
|
* Custom session strategy with database integration:
|
|
297
352
|
* ```typescript
|
|
353
|
+
* interface CustomSessionData extends OAuthTokenResponse {
|
|
354
|
+
* userId: string;
|
|
355
|
+
* email: string;
|
|
356
|
+
* }
|
|
357
|
+
*
|
|
298
358
|
* class DatabaseSessionStrategy implements SessionStrategy {
|
|
299
359
|
* constructor(private db: Database) {}
|
|
300
360
|
*
|
|
301
|
-
* async createSession(tokenData:
|
|
361
|
+
* async createSession(tokenData: OAuthTokenResponse): Promise<Session<CustomSessionData>> {
|
|
302
362
|
* // Decode ID token for OIDC providers
|
|
303
363
|
* const idToken = tokenData.id_token;
|
|
304
364
|
* const payload = decodeJwt(idToken);
|
|
@@ -319,7 +379,7 @@ interface Session {
|
|
|
319
379
|
* userId: user.id,
|
|
320
380
|
* accessToken: tokenData.access_token,
|
|
321
381
|
* refreshToken: tokenData.refresh_token,
|
|
322
|
-
* expiresAt: new Date(Date.now() + tokenData.expires_in * 1000)
|
|
382
|
+
* expiresAt: new Date(Date.now() + (tokenData.expires_in || 3600) * 1000)
|
|
323
383
|
* });
|
|
324
384
|
*
|
|
325
385
|
* return {
|
|
@@ -361,7 +421,7 @@ interface SessionStrategy {
|
|
|
361
421
|
* @example
|
|
362
422
|
* Simple implementation:
|
|
363
423
|
* ```typescript
|
|
364
|
-
* async createSession(tokenData:
|
|
424
|
+
* async createSession(tokenData: OAuthTokenResponse): Promise<Session> {
|
|
365
425
|
* return {
|
|
366
426
|
* token: tokenData.access_token,
|
|
367
427
|
* raw: tokenData
|
|
@@ -369,7 +429,7 @@ interface SessionStrategy {
|
|
|
369
429
|
* }
|
|
370
430
|
* ```
|
|
371
431
|
*/
|
|
372
|
-
createSession(tokenData:
|
|
432
|
+
createSession(tokenData: OAuthTokenResponse): Promise<Session>;
|
|
373
433
|
}
|
|
374
434
|
/**
|
|
375
435
|
* Default session strategy that works with any OAuth provider.
|
|
@@ -385,7 +445,7 @@ declare class DefaultSessionStrategy implements SessionStrategy {
|
|
|
385
445
|
* @param tokenData - The token data received from the OAuth provider
|
|
386
446
|
* @returns A Promise that resolves to a Session object
|
|
387
447
|
*/
|
|
388
|
-
createSession(tokenData:
|
|
448
|
+
createSession(tokenData: OAuthTokenResponse): Promise<Session>;
|
|
389
449
|
}
|
|
390
450
|
|
|
391
451
|
/**
|
|
@@ -568,7 +628,7 @@ type ProviderConfig = {
|
|
|
568
628
|
/** Array of OAuth scopes to request */
|
|
569
629
|
scopes: string[];
|
|
570
630
|
/** Additional provider-specific configuration parameters */
|
|
571
|
-
extraConfig?: Record<string,
|
|
631
|
+
extraConfig?: Record<string, string>;
|
|
572
632
|
} & ({
|
|
573
633
|
provider?: never;
|
|
574
634
|
} | {
|
|
@@ -679,7 +739,7 @@ type SafeLixaConfig<TProviders extends Record<string, ProviderConfig>> = LixaCon
|
|
|
679
739
|
/**
|
|
680
740
|
* Type representing the keys of configured providers
|
|
681
741
|
*/
|
|
682
|
-
type ConfiguredProviderKey<T extends LixaConfig<
|
|
742
|
+
type ConfiguredProviderKey<T extends LixaConfig<Record<string, ProviderConfig>>> = keyof T['providers'];
|
|
683
743
|
/**
|
|
684
744
|
* A flexible, provider-agnostic OAuth 2.0 and OpenID Connect (OIDC) client library.
|
|
685
745
|
*
|
|
@@ -688,7 +748,7 @@ type ConfiguredProviderKey<T extends LixaConfig<any>> = keyof T['providers'];
|
|
|
688
748
|
* Providers can be passed inline in the configuration, eliminating the need for pre-registration.
|
|
689
749
|
*
|
|
690
750
|
* @example
|
|
691
|
-
* Using built-in providers from
|
|
751
|
+
* Using built-in providers from \@vunexa/lixa-providers:
|
|
692
752
|
* ```typescript
|
|
693
753
|
* import { Lixa } from '@vunexa/lixa';
|
|
694
754
|
* import { GoogleProvider } from '@vunexa/lixa-providers';
|
|
@@ -732,7 +792,7 @@ type ConfiguredProviderKey<T extends LixaConfig<any>> = keyof T['providers'];
|
|
|
732
792
|
*
|
|
733
793
|
* @public
|
|
734
794
|
*/
|
|
735
|
-
declare class Lixa<TConfig extends LixaConfig<
|
|
795
|
+
declare class Lixa<TConfig extends LixaConfig<Record<string, ProviderConfig>> = LixaConfig> {
|
|
736
796
|
private static DEFAULT_PROVIDERS;
|
|
737
797
|
private static CONFIGURED_PROVIDERS;
|
|
738
798
|
private static LOCAL_STATE_CACHE;
|
|
@@ -748,7 +808,7 @@ declare class Lixa<TConfig extends LixaConfig<any> = LixaConfig> {
|
|
|
748
808
|
*
|
|
749
809
|
* @remarks
|
|
750
810
|
* Providers can be passed inline in the configuration using the `provider` field.
|
|
751
|
-
* Provider resolution priority: inline custom provider
|
|
811
|
+
* Provider resolution priority: inline custom provider \> default providers \> legacy registry.
|
|
752
812
|
*
|
|
753
813
|
* @param config - The configuration object containing provider settings and optional session strategy
|
|
754
814
|
*
|
|
@@ -804,7 +864,7 @@ declare class Lixa<TConfig extends LixaConfig<any> = LixaConfig> {
|
|
|
804
864
|
isProviderConfigured<T extends string>(provider: T): provider is T & ConfiguredProviderKey<TConfig>;
|
|
805
865
|
/**
|
|
806
866
|
* Gets a provider implementation by name.
|
|
807
|
-
* Resolution priority: inline custom provider
|
|
867
|
+
* Resolution priority: inline custom provider \> default providers \> legacy registry
|
|
808
868
|
*
|
|
809
869
|
* @param name - The provider name (case-insensitive)
|
|
810
870
|
* @param config - The provider configuration
|
|
@@ -915,7 +975,7 @@ declare class Lixa<TConfig extends LixaConfig<any> = LixaConfig> {
|
|
|
915
975
|
* - Sent to the token endpoint to prove the client's identity
|
|
916
976
|
*
|
|
917
977
|
* @see {@link https://datatracker.ietf.org/doc/html/rfc7636 | RFC 7636 - PKCE}
|
|
918
|
-
* @see
|
|
978
|
+
* @see buildCodeChallenge for the corresponding challenge generation
|
|
919
979
|
*
|
|
920
980
|
* @internal
|
|
921
981
|
*/
|
|
@@ -959,7 +1019,7 @@ declare class Lixa<TConfig extends LixaConfig<any> = LixaConfig> {
|
|
|
959
1019
|
*
|
|
960
1020
|
* @see {@link https://datatracker.ietf.org/doc/html/rfc7636 | RFC 7636 - PKCE}
|
|
961
1021
|
* @see {@link https://datatracker.ietf.org/doc/html/rfc4648#section-5 | RFC 4648 - Base64url Encoding}
|
|
962
|
-
* @see
|
|
1022
|
+
* @see generateCodeVerifier for the verifier generation
|
|
963
1023
|
*
|
|
964
1024
|
* @internal
|
|
965
1025
|
*/
|
|
@@ -1010,4 +1070,4 @@ declare class Lixa<TConfig extends LixaConfig<any> = LixaConfig> {
|
|
|
1010
1070
|
private findProviderByType;
|
|
1011
1071
|
}
|
|
1012
1072
|
|
|
1013
|
-
export { DefaultSessionStrategy, type IProvider, Lixa, type LixaConfig, type ProviderConfig, type SafeLixaConfig, type Session, type SessionDao, type SessionStrategy, type StateDao, type StateData };
|
|
1073
|
+
export { DefaultSessionStrategy, type IProvider, Lixa, type LixaConfig, type OAuthTokenResponse, type ProviderConfig, type SafeLixaConfig, type Session, type SessionDao, type SessionStrategy, type StateDao, type StateData };
|
package/dist/index.d.ts
CHANGED
|
@@ -16,6 +16,6 @@
|
|
|
16
16
|
* @packageDocumentation
|
|
17
17
|
*/
|
|
18
18
|
export { Lixa } from "./lixa";
|
|
19
|
-
export { type ProviderConfig, type LixaConfig, type SafeLixaConfig, type IProvider, type SessionStrategy, type Session, type StateDao, type SessionDao, type StateData, } from "./types";
|
|
19
|
+
export { type ProviderConfig, type LixaConfig, type SafeLixaConfig, type IProvider, type SessionStrategy, type Session, type OAuthTokenResponse, type StateDao, type SessionDao, type StateData, } from "./types";
|
|
20
20
|
export { DefaultSessionStrategy } from "./models/session";
|
|
21
21
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAC9B,OAAO,EACL,KAAK,cAAc,EACnB,KAAK,UAAU,EACf,KAAK,cAAc,EACnB,KAAK,SAAS,EACd,KAAK,eAAe,EACpB,KAAK,OAAO,EACZ,KAAK,QAAQ,EACb,KAAK,UAAU,EACf,KAAK,SAAS,GACf,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAC9B,OAAO,EACL,KAAK,cAAc,EACnB,KAAK,UAAU,EACf,KAAK,cAAc,EACnB,KAAK,SAAS,EACd,KAAK,eAAe,EACpB,KAAK,OAAO,EACZ,KAAK,kBAAkB,EACvB,KAAK,QAAQ,EACb,KAAK,UAAU,EACf,KAAK,SAAS,GACf,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -50,12 +50,11 @@ var DefaultSessionStrategy = class {
|
|
|
50
50
|
* @returns A Promise that resolves to a Session object
|
|
51
51
|
*/
|
|
52
52
|
async createSession(tokenData) {
|
|
53
|
-
|
|
54
|
-
if (!accessToken || typeof accessToken !== "string") {
|
|
53
|
+
if (!tokenData.access_token || typeof tokenData.access_token !== "string") {
|
|
55
54
|
throw new Error("No valid access token found in OAuth response");
|
|
56
55
|
}
|
|
57
56
|
return {
|
|
58
|
-
token:
|
|
57
|
+
token: tokenData.access_token,
|
|
59
58
|
raw: tokenData
|
|
60
59
|
};
|
|
61
60
|
}
|
|
@@ -79,7 +78,7 @@ var Lixa = class _Lixa {
|
|
|
79
78
|
*
|
|
80
79
|
* @remarks
|
|
81
80
|
* Providers can be passed inline in the configuration using the `provider` field.
|
|
82
|
-
* Provider resolution priority: inline custom provider
|
|
81
|
+
* Provider resolution priority: inline custom provider \> default providers \> legacy registry.
|
|
83
82
|
*
|
|
84
83
|
* @param config - The configuration object containing provider settings and optional session strategy
|
|
85
84
|
*
|
|
@@ -207,7 +206,7 @@ var Lixa = class _Lixa {
|
|
|
207
206
|
}
|
|
208
207
|
/**
|
|
209
208
|
* Gets a provider implementation by name.
|
|
210
|
-
* Resolution priority: inline custom provider
|
|
209
|
+
* Resolution priority: inline custom provider \> default providers \> legacy registry
|
|
211
210
|
*
|
|
212
211
|
* @param name - The provider name (case-insensitive)
|
|
213
212
|
* @param config - The provider configuration
|
|
@@ -342,7 +341,7 @@ var Lixa = class _Lixa {
|
|
|
342
341
|
* - Sent to the token endpoint to prove the client's identity
|
|
343
342
|
*
|
|
344
343
|
* @see {@link https://datatracker.ietf.org/doc/html/rfc7636 | RFC 7636 - PKCE}
|
|
345
|
-
* @see
|
|
344
|
+
* @see buildCodeChallenge for the corresponding challenge generation
|
|
346
345
|
*
|
|
347
346
|
* @internal
|
|
348
347
|
*/
|
|
@@ -388,7 +387,7 @@ var Lixa = class _Lixa {
|
|
|
388
387
|
*
|
|
389
388
|
* @see {@link https://datatracker.ietf.org/doc/html/rfc7636 | RFC 7636 - PKCE}
|
|
390
389
|
* @see {@link https://datatracker.ietf.org/doc/html/rfc4648#section-5 | RFC 4648 - Base64url Encoding}
|
|
391
|
-
* @see
|
|
390
|
+
* @see generateCodeVerifier for the verifier generation
|
|
392
391
|
*
|
|
393
392
|
* @internal
|
|
394
393
|
*/
|
|
@@ -516,8 +515,9 @@ var Lixa = class _Lixa {
|
|
|
516
515
|
this.log("INFO", "Session", "Session created successfully", { sessionId });
|
|
517
516
|
return sessionId;
|
|
518
517
|
}
|
|
519
|
-
fetchSessionInfo(sessionId) {
|
|
520
|
-
|
|
518
|
+
async fetchSessionInfo(sessionId) {
|
|
519
|
+
const sessionData = await this.sesionDao.getSession(sessionId);
|
|
520
|
+
return sessionData;
|
|
521
521
|
}
|
|
522
522
|
async exchangeCodeForToken(code, providerConfig, providerImpl, codeVerifier) {
|
|
523
523
|
const body = {
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lixa.ts","../src/dao/state-cache.ts","../src/dao/session-cache.ts","../src/models/session.ts"],"sourcesContent":["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 * 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 * 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<any> = 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?: any): 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 {@link 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 {@link 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 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('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 } 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 * @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 {\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: any;\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 * class DatabaseSessionStrategy implements SessionStrategy {\n * constructor(private db: Database) {}\n * \n * async createSession(tokenData: any): Promise<Session> {\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 * 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: any): Promise<Session> {\n * return {\n * token: tokenData.access_token,\n * raw: tokenData\n * };\n * }\n * ```\n */\n createSession(tokenData: 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"]}
|
|
1
|
+
{"version":3,"sources":["../src/lixa.ts","../src/dao/state-cache.ts","../src/dao/session-cache.ts","../src/models/session.ts"],"sourcesContent":["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"]}
|
package/dist/lixa.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { type Session } from "./models/session";
|
|
|
4
4
|
/**
|
|
5
5
|
* Type representing the keys of configured providers
|
|
6
6
|
*/
|
|
7
|
-
type ConfiguredProviderKey<T extends LixaConfig<
|
|
7
|
+
type ConfiguredProviderKey<T extends LixaConfig<Record<string, ProviderConfig>>> = keyof T['providers'];
|
|
8
8
|
/**
|
|
9
9
|
* A flexible, provider-agnostic OAuth 2.0 and OpenID Connect (OIDC) client library.
|
|
10
10
|
*
|
|
@@ -13,7 +13,7 @@ type ConfiguredProviderKey<T extends LixaConfig<any>> = keyof T['providers'];
|
|
|
13
13
|
* Providers can be passed inline in the configuration, eliminating the need for pre-registration.
|
|
14
14
|
*
|
|
15
15
|
* @example
|
|
16
|
-
* Using built-in providers from
|
|
16
|
+
* Using built-in providers from \@vunexa/lixa-providers:
|
|
17
17
|
* ```typescript
|
|
18
18
|
* import { Lixa } from '@vunexa/lixa';
|
|
19
19
|
* import { GoogleProvider } from '@vunexa/lixa-providers';
|
|
@@ -57,7 +57,7 @@ type ConfiguredProviderKey<T extends LixaConfig<any>> = keyof T['providers'];
|
|
|
57
57
|
*
|
|
58
58
|
* @public
|
|
59
59
|
*/
|
|
60
|
-
declare class Lixa<TConfig extends LixaConfig<
|
|
60
|
+
declare class Lixa<TConfig extends LixaConfig<Record<string, ProviderConfig>> = LixaConfig> {
|
|
61
61
|
private static DEFAULT_PROVIDERS;
|
|
62
62
|
private static CONFIGURED_PROVIDERS;
|
|
63
63
|
private static LOCAL_STATE_CACHE;
|
|
@@ -73,7 +73,7 @@ declare class Lixa<TConfig extends LixaConfig<any> = LixaConfig> {
|
|
|
73
73
|
*
|
|
74
74
|
* @remarks
|
|
75
75
|
* Providers can be passed inline in the configuration using the `provider` field.
|
|
76
|
-
* Provider resolution priority: inline custom provider
|
|
76
|
+
* Provider resolution priority: inline custom provider \> default providers \> legacy registry.
|
|
77
77
|
*
|
|
78
78
|
* @param config - The configuration object containing provider settings and optional session strategy
|
|
79
79
|
*
|
|
@@ -129,7 +129,7 @@ declare class Lixa<TConfig extends LixaConfig<any> = LixaConfig> {
|
|
|
129
129
|
isProviderConfigured<T extends string>(provider: T): provider is T & ConfiguredProviderKey<TConfig>;
|
|
130
130
|
/**
|
|
131
131
|
* Gets a provider implementation by name.
|
|
132
|
-
* Resolution priority: inline custom provider
|
|
132
|
+
* Resolution priority: inline custom provider \> default providers \> legacy registry
|
|
133
133
|
*
|
|
134
134
|
* @param name - The provider name (case-insensitive)
|
|
135
135
|
* @param config - The provider configuration
|
|
@@ -240,7 +240,7 @@ declare class Lixa<TConfig extends LixaConfig<any> = LixaConfig> {
|
|
|
240
240
|
* - Sent to the token endpoint to prove the client's identity
|
|
241
241
|
*
|
|
242
242
|
* @see {@link https://datatracker.ietf.org/doc/html/rfc7636 | RFC 7636 - PKCE}
|
|
243
|
-
* @see
|
|
243
|
+
* @see buildCodeChallenge for the corresponding challenge generation
|
|
244
244
|
*
|
|
245
245
|
* @internal
|
|
246
246
|
*/
|
|
@@ -284,7 +284,7 @@ declare class Lixa<TConfig extends LixaConfig<any> = LixaConfig> {
|
|
|
284
284
|
*
|
|
285
285
|
* @see {@link https://datatracker.ietf.org/doc/html/rfc7636 | RFC 7636 - PKCE}
|
|
286
286
|
* @see {@link https://datatracker.ietf.org/doc/html/rfc4648#section-5 | RFC 4648 - Base64url Encoding}
|
|
287
|
-
* @see
|
|
287
|
+
* @see generateCodeVerifier for the verifier generation
|
|
288
288
|
*
|
|
289
289
|
* @internal
|
|
290
290
|
*/
|
package/dist/lixa.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lixa.d.ts","sourceRoot":"","sources":["../src/lixa.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,UAAU,EAAE,KAAK,cAAc,EAAE,MAAM,SAAS,CAAC;AAC/D,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAKxC,OAAO,EAAE,KAAK,OAAO,
|
|
1
|
+
{"version":3,"file":"lixa.d.ts","sourceRoot":"","sources":["../src/lixa.ts"],"names":[],"mappings":"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"}
|