@vunexa/lixa 0.0.1-alpha.8 → 0.1.0

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 (52) hide show
  1. package/README.md +263 -143
  2. package/dist/dao/session-cache.d.ts +11 -0
  3. package/dist/dao/session-cache.d.ts.map +1 -0
  4. package/dist/dao/state-cache.d.ts +8 -6
  5. package/dist/dao/state-cache.d.ts.map +1 -1
  6. package/dist/dao/types.d.ts +376 -3
  7. package/dist/dao/types.d.ts.map +1 -1
  8. package/dist/export-types/index.d.ts +1397 -0
  9. package/dist/export-types/tsdoc-metadata.json +11 -0
  10. package/dist/index.cjs +1035 -0
  11. package/dist/index.cjs.map +1 -0
  12. package/dist/index.d.cts +1361 -0
  13. package/dist/index.d.ts +11 -2
  14. package/dist/index.d.ts.map +1 -1
  15. package/dist/index.js +992 -9
  16. package/dist/index.js.map +1 -1
  17. package/dist/lixa.d.ts +286 -19
  18. package/dist/lixa.d.ts.map +1 -1
  19. package/dist/models/session.d.ts +316 -0
  20. package/dist/models/session.d.ts.map +1 -0
  21. package/dist/providers/IProvider.d.ts +127 -4
  22. package/dist/providers/IProvider.d.ts.map +1 -1
  23. package/dist/providers/index.d.ts +0 -2
  24. package/dist/providers/index.d.ts.map +1 -1
  25. package/dist/types.d.ts +195 -24
  26. package/dist/types.d.ts.map +1 -1
  27. package/dist/utils/user-info.d.ts +82 -0
  28. package/dist/utils/user-info.d.ts.map +1 -0
  29. package/package.json +15 -10
  30. package/dist/dao/state-cache.js +0 -18
  31. package/dist/dao/state-cache.js.map +0 -1
  32. package/dist/dao/types.js +0 -2
  33. package/dist/dao/types.js.map +0 -1
  34. package/dist/lixa.js +0 -248
  35. package/dist/lixa.js.map +0 -1
  36. package/dist/providers/IProvider.js +0 -2
  37. package/dist/providers/IProvider.js.map +0 -1
  38. package/dist/providers/github.d.ts +0 -9
  39. package/dist/providers/github.d.ts.map +0 -1
  40. package/dist/providers/github.js +0 -8
  41. package/dist/providers/github.js.map +0 -1
  42. package/dist/providers/google.d.ts +0 -9
  43. package/dist/providers/google.d.ts.map +0 -1
  44. package/dist/providers/google.js +0 -8
  45. package/dist/providers/google.js.map +0 -1
  46. package/dist/providers/index.js +0 -3
  47. package/dist/providers/index.js.map +0 -1
  48. package/dist/types.js +0 -2
  49. package/dist/types.js.map +0 -1
  50. package/dist/utils/constants.js +0 -4
  51. package/dist/utils/constants.js.map +0 -1
  52. package/index.d.ts +0 -227
@@ -0,0 +1,1361 @@
1
+ /**
2
+ * OAuth 2.0 token response structure.
3
+ * Based on RFC 6749 Section 5.1 and OpenID Connect Core 1.0 Section 3.1.3.3
4
+ *
5
+ * @remarks
6
+ * This interface represents the standard OAuth 2.0 token response with
7
+ * optional OpenID Connect extensions. All OAuth providers should return
8
+ * at minimum the required fields (access_token, token_type).
9
+ *
10
+ * @public
11
+ */
12
+ interface OAuthTokenResponse {
13
+ /**
14
+ * OAuth 2.0 access token (required).
15
+ * Used to access protected resources on behalf of the user.
16
+ */
17
+ access_token: string;
18
+ /**
19
+ * Token type (required).
20
+ * Typically "Bearer" for OAuth 2.0.
21
+ */
22
+ token_type: string;
23
+ /**
24
+ * Token expiration time in seconds (optional).
25
+ * Time until the access token expires.
26
+ */
27
+ expires_in?: number;
28
+ /**
29
+ * OAuth 2.0 refresh token (optional).
30
+ * Used to obtain new access tokens without re-authentication.
31
+ */
32
+ refresh_token?: string;
33
+ /**
34
+ * Granted OAuth scopes (optional).
35
+ * Space-separated list of scopes that were granted.
36
+ */
37
+ scope?: string;
38
+ /**
39
+ * OpenID Connect ID token (optional).
40
+ * JWT containing user identity claims (only present for OIDC providers).
41
+ */
42
+ id_token?: string;
43
+ /**
44
+ * Additional provider-specific fields.
45
+ * Some providers may include extra fields like user_id, account_id, etc.
46
+ */
47
+ [key: string]: string | number | boolean | undefined;
48
+ }
49
+ /**
50
+ * Represents a linked provider account within a user's session.
51
+ *
52
+ * @public
53
+ */
54
+ interface LinkedAccount {
55
+ /** The provider identifier (e.g. 'github', 'google') */
56
+ provider: string;
57
+ /** Provider user ID if available */
58
+ providerUserId?: string | undefined;
59
+ /** User email for this provider */
60
+ email?: string | undefined;
61
+ /** OAuth access token for this provider */
62
+ accessToken: string;
63
+ /** Full raw token response from provider */
64
+ raw: OAuthTokenResponse;
65
+ /** Unix timestamp in milliseconds when account was linked */
66
+ linkedAt: number;
67
+ }
68
+ /**
69
+ * Represents a connected resource provider token (e.g. GitHub Repo access, Google Drive)
70
+ * obtained post-authentication via Lixa's Resource Connection API.
71
+ *
72
+ * @public
73
+ */
74
+ interface ConnectedResource {
75
+ /** The provider identifier (e.g. 'github', 'google', 'slack') */
76
+ provider: string;
77
+ /** Resource access token */
78
+ accessToken: string;
79
+ /** Optional refresh token for offline resource access */
80
+ refreshToken?: string | undefined;
81
+ /** Resource scopes granted by the user */
82
+ scopes: string[];
83
+ /** Full raw token response from provider */
84
+ raw: OAuthTokenResponse;
85
+ /** Unix timestamp in milliseconds when resource was connected */
86
+ connectedAt: number;
87
+ }
88
+ /**
89
+ * Represents a user session after successful OAuth authentication.
90
+ *
91
+ * @remarks
92
+ * The Session object is returned by SessionStrategy.createSession() and contains
93
+ * the session identifier and any additional data needed for your application.
94
+ *
95
+ * The structure is intentionally flexible to support various session management
96
+ * approaches (JWT tokens, session IDs, multi-SSO account linking, connected resources, etc.).
97
+ *
98
+ * @public
99
+ */
100
+ interface Session<TRaw = OAuthTokenResponse> {
101
+ /**
102
+ * Unique session ID generated by Lixa upon authentication.
103
+ */
104
+ id?: string;
105
+ /**
106
+ * The primary access token or session token identifier.
107
+ */
108
+ token: string;
109
+ /** Unique unified user ID across linked accounts */
110
+ userId?: string;
111
+ /** Primary user email */
112
+ email?: string;
113
+ /** Current active auth provider for this session turn */
114
+ provider?: string;
115
+ /** Linked SSO provider accounts keyed by provider name */
116
+ accounts?: Record<string, LinkedAccount>;
117
+ /** Connected third-party resource provider tokens keyed by provider name */
118
+ resources?: Record<string, ConnectedResource>;
119
+ /**
120
+ * Raw session data.
121
+ * Contains the complete OAuth token response and any additional data
122
+ * your SessionStrategy adds (user info, database IDs, etc.).
123
+ */
124
+ raw: TRaw;
125
+ }
126
+ /**
127
+ * Provider metadata passed to session strategy.
128
+ * Contains provider name and endpoints for user info extraction.
129
+ *
130
+ * @public
131
+ */
132
+ interface ProviderMetadata {
133
+ /** The provider name (e.g., 'google', 'github') */
134
+ name: string;
135
+ /** Provider endpoints */
136
+ endpoints: {
137
+ /** Authorization endpoint URL */
138
+ authorization: string;
139
+ /** Token endpoint URL */
140
+ token: string;
141
+ /** UserInfo endpoint URL */
142
+ userInfo: string;
143
+ };
144
+ }
145
+
146
+ /**
147
+ * OAuth state data structure.
148
+ *
149
+ * @remarks
150
+ * This structure is used internally by Lixa to store OAuth flow state
151
+ * during the authorization process. It contains the information needed
152
+ * to complete the PKCE flow and route callbacks to the correct provider.
153
+ *
154
+ * @public
155
+ */
156
+ interface StateData {
157
+ /**
158
+ * Provider name for callback routing.
159
+ * Used to identify which provider configuration to use when handling the callback.
160
+ *
161
+ * @example 'google', 'github', 'custom'
162
+ */
163
+ provider: string;
164
+ /**
165
+ * PKCE code verifier for secure token exchange.
166
+ * A cryptographically random string (64 hex characters) used in the PKCE flow
167
+ * to prevent authorization code interception attacks.
168
+ *
169
+ * @see RFC 7636 - Proof Key for Code Exchange
170
+ */
171
+ codeVerifier: string;
172
+ /**
173
+ * Unix timestamp in milliseconds when the state was created.
174
+ * Used for debugging and validation purposes.
175
+ */
176
+ createdAt: number;
177
+ }
178
+ /**
179
+ * State storage operations interface.
180
+ *
181
+ * @remarks
182
+ * Groups all state storage operations together. All methods must be implemented
183
+ * if this interface is provided.
184
+ *
185
+ * @public
186
+ */
187
+ interface StateStorage {
188
+ /**
189
+ * Saves OAuth state with expiration.
190
+ *
191
+ * @param state - The state parameter value (random string for CSRF protection)
192
+ * @param data - State data including provider name and PKCE code verifier
193
+ * @param expiresInSeconds - TTL in seconds (typically 300 for 5 minutes)
194
+ */
195
+ saveState(state: string, data: StateData, expiresInSeconds: number): Promise<void>;
196
+ /**
197
+ * Retrieves OAuth state data.
198
+ *
199
+ * @param state - The state parameter value
200
+ * @returns State data or null if not found or expired
201
+ */
202
+ getState(state: string): Promise<StateData | null>;
203
+ /**
204
+ * Deletes OAuth state (called after successful validation).
205
+ *
206
+ * @param state - The state parameter value
207
+ */
208
+ deleteState(state: string): Promise<void>;
209
+ }
210
+ /**
211
+ * State handler for OAuth authorization flow.
212
+ *
213
+ * @remarks
214
+ * The StateHandler manages state generation and storage during the OAuth authorization flow.
215
+ *
216
+ * - GenerateState: Optional. Customizes how state parameters and PKCE verifiers are generated.
217
+ * If not provided, uses default implementation (cryptographically secure random strings).
218
+ *
219
+ * - storage: Optional. Provides custom state storage (save/get/delete operations).
220
+ * If not provided, uses in-memory cache (not suitable for production).
221
+ *
222
+ * For production, implement storage with Redis, database, or other distributed cache.
223
+ *
224
+ * @example
225
+ * Full implementation with Redis:
226
+ * ```typescript
227
+ * import { StateHandler, StateData } from '@vunexa/lixa';
228
+ *
229
+ * const stateHandler: StateHandler = {
230
+ * GenerateState: async (provider) => {
231
+ * const state = generateSecureRandomString(32);
232
+ * const codeVerifier = generateSecureRandomString(64);
233
+ * return {
234
+ * state,
235
+ * data: {
236
+ * provider,
237
+ * codeVerifier,
238
+ * createdAt: Date.now()
239
+ * }
240
+ * };
241
+ * },
242
+ *
243
+ * storage: {
244
+ * saveState: async (state, data, expiresInSeconds) => {
245
+ * await redis.setex(`oauth:state:${state}`, expiresInSeconds, JSON.stringify(data));
246
+ * },
247
+ * getState: async (state) => {
248
+ * const data = await redis.get(`oauth:state:${state}`);
249
+ * return data ? JSON.parse(data) : null;
250
+ * },
251
+ * deleteState: async (state) => {
252
+ * await redis.del(`oauth:state:${state}`);
253
+ * }
254
+ * }
255
+ * };
256
+ * ```
257
+ *
258
+ * @example
259
+ * Minimal implementation (uses defaults):
260
+ * ```typescript
261
+ * const stateHandler: StateHandler = {
262
+ * storage: {
263
+ * saveState: async (state, data, expiresInSeconds) => {
264
+ * await redis.setex(state, expiresInSeconds, JSON.stringify(data));
265
+ * },
266
+ * getState: async (state) => {
267
+ * const data = await redis.get(state);
268
+ * return data ? JSON.parse(data) : null;
269
+ * },
270
+ * deleteState: async (state) => {
271
+ * await redis.del(state);
272
+ * }
273
+ * }
274
+ * };
275
+ * ```
276
+ *
277
+ * @public
278
+ */
279
+ interface StateHandler {
280
+ /**
281
+ * Generates OAuth state parameter and associated data.
282
+ *
283
+ * @param provider - The provider name for callback routing
284
+ * @returns A Promise that resolves to state string and state data
285
+ *
286
+ * @remarks
287
+ * This method generates:
288
+ * - state: A cryptographically secure random string for CSRF protection
289
+ * - codeVerifier: A PKCE code verifier for secure token exchange
290
+ * - createdAt: Timestamp for debugging
291
+ *
292
+ * If not provided, defaults to generating 32-byte hex strings for state
293
+ * and 64-byte hex strings for code verifier.
294
+ *
295
+ * @example
296
+ * ```typescript
297
+ * GenerateState: async (provider) => {
298
+ * const state = crypto.randomBytes(16).toString('hex');
299
+ * const codeVerifier = crypto.randomBytes(32).toString('hex');
300
+ * return {
301
+ * state,
302
+ * data: {
303
+ * provider,
304
+ * codeVerifier,
305
+ * createdAt: Date.now()
306
+ * }
307
+ * };
308
+ * }
309
+ * ```
310
+ */
311
+ generateState?(provider: string): Promise<{
312
+ state: string;
313
+ data: StateData;
314
+ }>;
315
+ /**
316
+ * State storage operations.
317
+ *
318
+ * @remarks
319
+ * Provides methods for saving, retrieving, and deleting OAuth state.
320
+ * All three methods must be implemented together.
321
+ *
322
+ * If not provided, uses in-memory cache (not suitable for production).
323
+ */
324
+ stateStorage?: StateStorage;
325
+ }
326
+ /**
327
+ * Session storage operations interface.
328
+ *
329
+ * @remarks
330
+ * Groups all session storage operations together. All methods must be implemented
331
+ * if this interface is provided.
332
+ *
333
+ * @public
334
+ */
335
+ interface SessionStorage {
336
+ /**
337
+ * Saves a session with expiration.
338
+ *
339
+ * @param sessionId - Unique session identifier
340
+ * @param session - Session data from GenerateSession()
341
+ * @param expiresInSeconds - TTL in seconds (typically 86400 for 24 hours)
342
+ */
343
+ saveSession<T extends Session>(sessionId: string, session: T, expiresInSeconds: number): Promise<void>;
344
+ /**
345
+ * Retrieves a session by ID.
346
+ *
347
+ * @param sessionId - Unique session identifier
348
+ * @returns Session data or null if not found or expired
349
+ */
350
+ getSession<T extends Session>(sessionId: string): Promise<T | null>;
351
+ /**
352
+ * Deletes a session (e.g., on logout).
353
+ *
354
+ * @param sessionId - Unique session identifier
355
+ */
356
+ deleteSession(sessionId: string): Promise<void>;
357
+ /**
358
+ * Optional helper to retrieve an active session by user email for account linking.
359
+ *
360
+ * @param email - Primary user email
361
+ */
362
+ getSessionByEmail?<T extends Session>(email: string): Promise<{
363
+ sessionId: string;
364
+ session: T;
365
+ } | null>;
366
+ }
367
+ /**
368
+ * Session handler for OAuth authentication.
369
+ *
370
+ * @remarks
371
+ * The SessionHandler manages session generation and storage after successful OAuth authentication.
372
+ *
373
+ * - GenerateSession: Optional. Customizes how OAuth tokens are converted into session data.
374
+ * If not provided, uses default implementation (access token as session token).
375
+ *
376
+ * - storage: Optional. Provides custom session storage (save/get/delete operations).
377
+ * If not provided, uses in-memory cache (not suitable for production).
378
+ *
379
+ * For production, implement both GenerateSession (for user creation/lookup) and storage
380
+ * (for persistent session storage with Redis, database, etc.).
381
+ *
382
+ * @example
383
+ * Full implementation with database:
384
+ * ```typescript
385
+ * import { SessionHandler, Session, OAuthTokenResponse, ProviderMetadata, extractUserInfo } from '@vunexa/lixa';
386
+ *
387
+ * const sessionHandler: SessionHandler = {
388
+ * GenerateSession: async (tokenData, providerMetadata) => {
389
+ * // Extract user info and create/retrieve user
390
+ * const { userInfo } = await extractUserInfo(tokenData, providerMetadata);
391
+ * const user = await db.users.upsert({
392
+ * email: userInfo.email,
393
+ * name: userInfo.name
394
+ * });
395
+ *
396
+ * // Return session data (not stored yet)
397
+ * return {
398
+ * token: tokenData.access_token,
399
+ * raw: {
400
+ * ...tokenData,
401
+ * userId: user.id,
402
+ * provider: providerMetadata.name
403
+ * }
404
+ * };
405
+ * },
406
+ *
407
+ * storage: {
408
+ * saveSession: async (sessionId, session, expiresInSeconds) => {
409
+ * const expiresAt = new Date(Date.now() + expiresInSeconds * 1000);
410
+ * await db.sessions.create({
411
+ * id: sessionId,
412
+ * token: session.token,
413
+ * data: session.raw,
414
+ * expiresAt
415
+ * });
416
+ * },
417
+ *
418
+ * getSession: async (sessionId) => {
419
+ * const record = await db.sessions.findOne({
420
+ * id: sessionId,
421
+ * expiresAt: { $gt: new Date() }
422
+ * });
423
+ * return record ? { token: record.token, raw: record.data } : null;
424
+ * },
425
+ *
426
+ * deleteSession: async (sessionId) => {
427
+ * await db.sessions.delete({ id: sessionId });
428
+ * }
429
+ * }
430
+ * };
431
+ * ```
432
+ *
433
+ * @example
434
+ * Minimal implementation (uses defaults):
435
+ * ```typescript
436
+ * const sessionHandler: SessionHandler = {
437
+ * storage: {
438
+ * saveSession: async (sessionId, session, expiresInSeconds) => {
439
+ * await redis.setex(sessionId, expiresInSeconds, JSON.stringify(session));
440
+ * },
441
+ * getSession: async (sessionId) => {
442
+ * const data = await redis.get(sessionId);
443
+ * return data ? JSON.parse(data) : null;
444
+ * },
445
+ * deleteSession: async (sessionId) => {
446
+ * await redis.del(sessionId);
447
+ * }
448
+ * }
449
+ * };
450
+ * ```
451
+ *
452
+ * @public
453
+ */
454
+ interface SessionHandler {
455
+ /**
456
+ * Generates session data from OAuth token data.
457
+ *
458
+ * @param tokenData - The token data received from the OAuth provider's token endpoint
459
+ * @param providerMetadata - Provider metadata including name and endpoints
460
+ * @returns A Promise that resolves to session data
461
+ *
462
+ * @remarks
463
+ * This method is responsible for creating session data from OAuth tokens.
464
+ * It is called after successfully exchanging the authorization code for tokens.
465
+ *
466
+ * Token Data:
467
+ * - access_token: OAuth access token
468
+ * - refresh_token: OAuth refresh token (optional)
469
+ * - expires_in: Token expiration time in seconds
470
+ * - token_type: Token type (usually "Bearer")
471
+ * - id_token: OpenID Connect ID token (for OIDC providers)
472
+ * - scope: Granted scopes
473
+ *
474
+ * Provider Metadata:
475
+ * - name: The provider name (e.g., 'google', 'github')
476
+ * - endpoints: Provider endpoints (authorization, token, userInfo)
477
+ *
478
+ * Your implementation should:
479
+ * 1. Extract user info (using extractUserInfo or decode ID token)
480
+ * 2. Create or lookup users in your database
481
+ * 3. Build and return session data with any custom fields
482
+ *
483
+ * Note: This method should NOT store the session. Storage is handled by the storage object.
484
+ *
485
+ * If not provided, defaults to using the access token as the session token.
486
+ *
487
+ * @example
488
+ * ```typescript
489
+ * GenerateSession: async (tokenData, providerMetadata) => {
490
+ * const { userInfo } = await extractUserInfo(tokenData, providerMetadata);
491
+ * const user = await db.users.upsert({ email: userInfo.email });
492
+ *
493
+ * return {
494
+ * token: tokenData.access_token,
495
+ * raw: {
496
+ * ...tokenData,
497
+ * userId: user.id,
498
+ * provider: providerMetadata.name
499
+ * }
500
+ * };
501
+ * }
502
+ * ```
503
+ */
504
+ generateSession?<T extends Session>(tokenData: OAuthTokenResponse, providerMetadata: ProviderMetadata): Promise<T>;
505
+ /**
506
+ * Session storage operations.
507
+ *
508
+ * @remarks
509
+ * Provides methods for saving, retrieving, and deleting sessions.
510
+ * All three methods must be implemented together.
511
+ *
512
+ * If not provided, uses in-memory cache (not suitable for production).
513
+ */
514
+ sessionStorage?: SessionStorage;
515
+ /**
516
+ * Optional method to generate session data from OAuth tokens.
517
+ *
518
+ * @remarks
519
+ * If not provided, uses default implementation from LocalSessionHandler.
520
+ */
521
+ generateSession?<T extends Session>(tokenData: OAuthTokenResponse, providerMetadata: ProviderMetadata): Promise<T>;
522
+ }
523
+
524
+ /**
525
+ * Interface for OAuth 2.0 and OpenID Connect provider implementations.
526
+ *
527
+ * @remarks
528
+ * Implement this interface to add support for custom OAuth providers.
529
+ * Each provider defines the three core endpoints required for the OAuth 2.0
530
+ * authorization code flow with PKCE.
531
+ *
532
+ * Built-in providers (Google, GitHub) are available in the \@vunexa/lixa-providers package.
533
+ *
534
+ * All implementations must comply with:
535
+ * - RFC 6749 (OAuth 2.0)
536
+ * - RFC 7636 (PKCE)
537
+ * - OpenID Connect Core 1.0 (for OIDC providers)
538
+ *
539
+ * @example
540
+ * Custom provider implementation:
541
+ * ```typescript
542
+ * import { IProvider } from '@vunexa/lixa';
543
+ *
544
+ * class CustomProvider implements IProvider {
545
+ * authorizationEndpoint = 'https://auth.example.com/oauth/authorize';
546
+ * tokenEndpoint = 'https://auth.example.com/oauth/token';
547
+ * userInfoEndpoint = 'https://api.example.com/user';
548
+ * }
549
+ *
550
+ * // Use in configuration
551
+ * const lixa = new Lixa({
552
+ * providers: {
553
+ * custom: {
554
+ * provider: new CustomProvider(),
555
+ * clientId: 'your-client-id',
556
+ * clientSecret: 'your-client-secret',
557
+ * redirectUri: 'https://app.com/callback',
558
+ * scopes: ['read:user']
559
+ * }
560
+ * }
561
+ * });
562
+ * ```
563
+ *
564
+ * @example
565
+ * Object literal provider:
566
+ * ```typescript
567
+ * const customProvider: IProvider = {
568
+ * authorizationEndpoint: 'https://auth.example.com/oauth/authorize',
569
+ * tokenEndpoint: 'https://auth.example.com/oauth/token',
570
+ * userInfoEndpoint: 'https://api.example.com/user'
571
+ * };
572
+ * ```
573
+ *
574
+ * @public
575
+ */
576
+ interface IProvider {
577
+ /**
578
+ * The OAuth 2.0 authorization endpoint URL.
579
+ *
580
+ * @remarks
581
+ * This is the URL where users are redirected to authenticate and authorize your application.
582
+ * The endpoint must support the OAuth 2.0 authorization code flow with PKCE.
583
+ *
584
+ * Standard query parameters sent to this endpoint:
585
+ * - client_id: Your application's client ID
586
+ * - redirect_uri: Where to redirect after authorization
587
+ * - response_type: Always "code" for authorization code flow
588
+ * - scope: Space-separated list of requested scopes
589
+ * - state: Random string for CSRF protection
590
+ * - code_challenge: PKCE code challenge (SHA-256 hash)
591
+ * - code_challenge_method: Always "S256" for SHA-256
592
+ *
593
+ * @example
594
+ * ```typescript
595
+ * authorizationEndpoint = 'https://accounts.google.com/o/oauth2/v2/auth'
596
+ * ```
597
+ */
598
+ authorizationEndpoint: string;
599
+ /**
600
+ * The OAuth 2.0 token endpoint URL.
601
+ *
602
+ * @remarks
603
+ * This is the URL where authorization codes are exchanged for access tokens.
604
+ * The endpoint must support the OAuth 2.0 token exchange with PKCE.
605
+ *
606
+ * Standard parameters sent to this endpoint (POST request):
607
+ * - grant_type: Always "authorization_code"
608
+ * - code: The authorization code from the callback
609
+ * - redirect_uri: Must match the authorization request
610
+ * - client_id: Your application's client ID
611
+ * - client_secret: Your application's client secret
612
+ * - code_verifier: PKCE code verifier (original random string)
613
+ *
614
+ * Expected response:
615
+ * - access_token: OAuth access token
616
+ * - token_type: Token type (usually "Bearer")
617
+ * - expires_in: Token expiration time in seconds
618
+ * - refresh_token: Refresh token (optional)
619
+ * - id_token: OpenID Connect ID token (for OIDC providers)
620
+ * - scope: Granted scopes
621
+ *
622
+ * @example
623
+ * ```typescript
624
+ * tokenEndpoint = 'https://oauth2.googleapis.com/token'
625
+ * ```
626
+ */
627
+ tokenEndpoint: string;
628
+ /**
629
+ * The user information endpoint URL.
630
+ *
631
+ * @remarks
632
+ * This is the URL where user profile information can be retrieved using the access token.
633
+ * For OpenID Connect providers, this is the UserInfo endpoint.
634
+ *
635
+ * The endpoint is called with the access token in the Authorization header:
636
+ * ```
637
+ * Authorization: Bearer <access_token>
638
+ * ```
639
+ *
640
+ * Common response fields:
641
+ * - sub: Subject identifier (user ID)
642
+ * - email: User's email address
643
+ * - name: User's full name
644
+ * - picture: User's profile picture URL
645
+ * - email_verified: Whether email is verified
646
+ *
647
+ * Note: This endpoint is not called automatically by Lixa. Your SessionStrategy
648
+ * can call it if needed to fetch user profile information.
649
+ *
650
+ * @example
651
+ * ```typescript
652
+ * userInfoEndpoint = 'https://www.googleapis.com/oauth2/v2/userinfo'
653
+ * ```
654
+ */
655
+ userInfoEndpoint: string;
656
+ /**
657
+ * Minimal authentication scopes required for identity verification (AuthN).
658
+ *
659
+ * @example ['openid', 'email', 'profile'] or ['read:user', 'user:email']
660
+ */
661
+ authScopes?: string[];
662
+ }
663
+
664
+ /**
665
+ * Configuration for an OAuth provider instance.
666
+ *
667
+ * @remarks
668
+ * For built-in providers (google, github), just provide credentials.
669
+ * For custom providers, include the provider implementation.
670
+ *
671
+ * The provider field uses a discriminated union to ensure type safety:
672
+ * - When omitted or undefined: assumes a built-in provider
673
+ * - When provided: must be a valid IProvider implementation
674
+ *
675
+ * @example
676
+ * Built-in provider configuration:
677
+ * ```typescript
678
+ * {
679
+ * clientId: 'your-client-id',
680
+ * clientSecret: 'your-client-secret',
681
+ * redirectUri: 'https://app.com/callback',
682
+ * scopes: ['openid', 'email']
683
+ * }
684
+ * ```
685
+ *
686
+ * @example
687
+ * Custom provider configuration:
688
+ * ```typescript
689
+ * {
690
+ * provider: new CustomProvider(),
691
+ * clientId: 'your-client-id',
692
+ * clientSecret: 'your-client-secret',
693
+ * redirectUri: 'https://app.com/callback',
694
+ * scopes: ['read:user']
695
+ * }
696
+ * ```
697
+ *
698
+ * @public
699
+ */
700
+ type ProviderConfig = {
701
+ /** The OAuth client ID provided by the provider */
702
+ clientId: string;
703
+ /** The OAuth client secret provided by the provider */
704
+ clientSecret: string;
705
+ /** The redirect URI registered with the provider */
706
+ redirectUri: string;
707
+ /** Array of OAuth scopes to request */
708
+ scopes: string[];
709
+ /** Additional provider-specific configuration parameters */
710
+ extraConfig?: Record<string, string>;
711
+ } & ({
712
+ provider?: never;
713
+ } | {
714
+ provider: IProvider;
715
+ });
716
+ /**
717
+ * Main configuration object for Lixa.
718
+ * Provides type-safe provider name inference.
719
+ *
720
+ * @remarks
721
+ * The generic type parameter TProviders enables TypeScript to infer provider names
722
+ * from the configuration object, providing autocomplete and type checking for
723
+ * provider names in methods like getAuthUrl() and handleCallback().
724
+ *
725
+ * @typeParam TProviders - The provider configuration map type, defaults to a generic record
726
+ *
727
+ * @example
728
+ * Basic configuration with built-in providers:
729
+ * ```typescript
730
+ * import { Lixa } from '@vunexa/lixa';
731
+ * import { GoogleProvider } from '@vunexa/lixa-providers';
732
+ *
733
+ * const lixa = new Lixa({
734
+ * providers: {
735
+ * google: {
736
+ * provider: new GoogleProvider(),
737
+ * clientId: process.env.GOOGLE_CLIENT_ID!,
738
+ * clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
739
+ * redirectUri: 'https://app.com/auth/google/callback',
740
+ * scopes: ['openid', 'email', 'profile']
741
+ * }
742
+ * }
743
+ * });
744
+ * ```
745
+ *
746
+ * @example
747
+ * Configuration with custom session and state handlers:
748
+ * ```typescript
749
+ * const lixa = new Lixa({
750
+ * providers: {
751
+ * google: {
752
+ * provider: new GoogleProvider(),
753
+ * clientId: process.env.GOOGLE_CLIENT_ID!,
754
+ * clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
755
+ * redirectUri: 'https://app.com/auth/google/callback',
756
+ * scopes: ['openid', 'email', 'profile']
757
+ * }
758
+ * },
759
+ * stateHandler: {
760
+ * storage: {
761
+ * saveState: async (state, data, ttl) => await redis.setex(state, ttl, JSON.stringify(data)),
762
+ * getState: async (state) => JSON.parse(await redis.get(state) || 'null'),
763
+ * deleteState: async (state) => await redis.del(state)
764
+ * }
765
+ * },
766
+ * sessionHandler: {
767
+ * GenerateSession: async (tokenData, providerMetadata) => {
768
+ * const { userInfo } = await extractUserInfo(tokenData, providerMetadata);
769
+ * const user = await db.users.upsert({ email: userInfo.email });
770
+ * return { token: tokenData.access_token, raw: { ...tokenData, userId: user.id } };
771
+ * },
772
+ * storage: {
773
+ * saveSession: async (id, session, ttl) => await db.sessions.create({ id, session, ttl }),
774
+ * getSession: async (id) => await db.sessions.findOne({ id }),
775
+ * deleteSession: async (id) => await db.sessions.delete({ id })
776
+ * }
777
+ * },
778
+ * debug: true
779
+ * });
780
+ * ```
781
+ *
782
+ /**
783
+ * Strategy mode for multi-SSO identity account linking.
784
+ *
785
+ * @public
786
+ */
787
+ declare enum AccountLinkingStrategy {
788
+ /** Automatically merge identities matching the same verified primary email address */
789
+ AUTO_LINK_BY_VERIFIED_EMAIL = "AUTO_LINK_BY_VERIFIED_EMAIL",
790
+ /** Keep identity profiles isolated per provider (no automatic account merging) */
791
+ ISOLATED = "ISOLATED"
792
+ }
793
+ /**
794
+ * Supported mode values for account linking configuration.
795
+ *
796
+ * @public
797
+ */
798
+ type AccountLinkingMode = AccountLinkingStrategy | "AUTO_LINK_BY_VERIFIED_EMAIL" | "ISOLATED" | "linkByEmail" | "separate";
799
+ /**
800
+ * Account linking settings for Lixa.
801
+ *
802
+ * @public
803
+ */
804
+ interface AccountLinkingConfig {
805
+ /**
806
+ * Account linking mode strategy:
807
+ * - AccountLinkingStrategy.AUTO_LINK_BY_VERIFIED_EMAIL ("AUTO_LINK_BY_VERIFIED_EMAIL" / "linkByEmail"): Auto-link accounts sharing same verified email.
808
+ * - AccountLinkingStrategy.ISOLATED ("ISOLATED" / "separate"): Keep provider accounts isolated (default).
809
+ *
810
+ * @default AccountLinkingStrategy.ISOLATED
811
+ */
812
+ mode?: AccountLinkingMode;
813
+ /**
814
+ * Whether to require that the email address is verified by the provider before linking.
815
+ *
816
+ * @default true
817
+ */
818
+ requireVerifiedEmail?: boolean;
819
+ }
820
+ /**
821
+ * Main configuration object for Lixa.
822
+ * Provides type-safe provider name inference.
823
+ *
824
+ * @public
825
+ */
826
+ interface LixaConfig<TProviders extends Record<string, ProviderConfig> = Record<string, ProviderConfig>> {
827
+ /**
828
+ * Map of provider names to their configurations.
829
+ * Provider names will be available for autocomplete in getAuthUrl() and handleCallback().
830
+ */
831
+ providers: TProviders;
832
+ /**
833
+ * Account linking configuration for multi-SSO user linking.
834
+ */
835
+ accountLinking?: AccountLinkingConfig;
836
+ /**
837
+ * Optional custom state handler.
838
+ * Handles state generation and storage during OAuth authorization flow.
839
+ *
840
+ * - GenerateState: Customizes how state parameters and PKCE verifiers are generated
841
+ * - storage: Provides persistent state storage (save/get/delete operations)
842
+ *
843
+ * Defaults to in-memory cache if not provided (not suitable for production).
844
+ *
845
+ * @see {@link StateHandler}
846
+ */
847
+ stateHandler?: StateHandler;
848
+ /**
849
+ * Optional custom session handler.
850
+ * Handles session generation and storage after authentication.
851
+ *
852
+ * - GenerateSession: Customizes how OAuth tokens are converted into session data
853
+ * - storage: Provides persistent session storage (save/get/delete operations)
854
+ *
855
+ * Defaults to in-memory cache if not provided (not suitable for production).
856
+ *
857
+ * @see {@link SessionHandler}
858
+ */
859
+ sessionHandler?: SessionHandler;
860
+ /**
861
+ * Enable debug logging.
862
+ * When enabled, outputs structured logs for initialization, auth flow, and errors.
863
+ * Format: [Lixa] [timestamp] [level] [context] message
864
+ */
865
+ debug?: boolean;
866
+ }
867
+ /**
868
+ * Helper type to create a configuration with only registered providers.
869
+ * Use this with Lixa.createConfig() for type safety.
870
+ *
871
+ * @deprecated This type is maintained for backward compatibility.
872
+ * The new inline provider configuration pattern makes this unnecessary.
873
+ *
874
+ * @public
875
+ */
876
+ type SafeLixaConfig<TProviders extends Record<string, ProviderConfig>> = LixaConfig<TProviders> & {
877
+ providers: TProviders;
878
+ };
879
+
880
+ /**
881
+ * Type representing the keys of configured providers
882
+ */
883
+ type ConfiguredProviderKey<T extends LixaConfig<Record<string, ProviderConfig>>> = keyof T['providers'];
884
+ /**
885
+ * A flexible, provider-agnostic OAuth 2.0 and OpenID Connect (OIDC) client library.
886
+ *
887
+ * @remarks
888
+ * Lixa simplifies multi-provider authentication flows and supports extensible session management.
889
+ * Providers can be passed inline in the configuration, eliminating the need for pre-registration.
890
+ *
891
+ * @example
892
+ * Using built-in providers from \@vunexa/lixa-providers:
893
+ * ```typescript
894
+ * import { Lixa } from '@vunexa/lixa';
895
+ * import { GoogleProvider } from '@vunexa/lixa-providers';
896
+ *
897
+ * const lixa = new Lixa({
898
+ * providers: {
899
+ * google: {
900
+ * provider: new GoogleProvider(),
901
+ * clientId: 'your-client-id',
902
+ * clientSecret: 'your-client-secret',
903
+ * redirectUri: 'https://yourapp.com/auth/google/callback',
904
+ * scopes: ['openid', 'email', 'profile']
905
+ * }
906
+ * }
907
+ * });
908
+ * ```
909
+ *
910
+ * @example
911
+ * Using custom inline providers:
912
+ * ```typescript
913
+ * import { Lixa, IProvider } from '@vunexa/lixa';
914
+ *
915
+ * const customProvider: IProvider = {
916
+ * authorizationEndpoint: 'https://custom.com/oauth/authorize',
917
+ * tokenEndpoint: 'https://custom.com/oauth/token',
918
+ * userInfoEndpoint: 'https://custom.com/api/user'
919
+ * };
920
+ *
921
+ * const lixa = new Lixa({
922
+ * providers: {
923
+ * custom: {
924
+ * provider: customProvider,
925
+ * clientId: 'your-client-id',
926
+ * clientSecret: 'your-client-secret',
927
+ * redirectUri: 'https://yourapp.com/auth/custom/callback',
928
+ * scopes: ['read:user']
929
+ * }
930
+ * }
931
+ * });
932
+ * ```
933
+ *
934
+ * @public
935
+ */
936
+ declare class Lixa<TConfig extends LixaConfig<Record<string, ProviderConfig>> = LixaConfig> {
937
+ private static DEFAULT_PROVIDERS;
938
+ private static CONFIGURED_PROVIDERS;
939
+ private static LOCAL_STATE_HANDLER;
940
+ private static LOCAL_SESSION_HANDLER;
941
+ private config;
942
+ private stateHandler;
943
+ private sessionHandler;
944
+ private debug;
945
+ /**
946
+ * Creates a new Lixa instance with the provided configuration.
947
+ *
948
+ * @remarks
949
+ * Providers can be passed inline in the configuration using the `provider` field.
950
+ * Provider resolution priority: inline custom provider \> default providers \> legacy registry.
951
+ *
952
+ * @param config - The configuration object containing provider settings and optional session strategy
953
+ *
954
+ * @throws Error when provider configuration is missing required fields
955
+ * @throws Error when provider implementation is missing required properties
956
+ * @throws Error when provider is not available and no inline implementation is provided
957
+ */
958
+ constructor(config: TConfig);
959
+ /**
960
+ * Validates that a provider configuration has all required credentials.
961
+ *
962
+ * @param name - The provider name
963
+ * @param config - The provider configuration
964
+ * @throws Error when required fields are missing or invalid
965
+ */
966
+ private validateProviderConfig;
967
+ /**
968
+ * Validates that a provider implementation has all required properties.
969
+ *
970
+ * @param name - The provider name
971
+ * @param provider - The provider implementation
972
+ * @throws Error when required properties are missing
973
+ */
974
+ private validateProviderImplementation;
975
+ /**
976
+ * Structured debug logging with standardized format.
977
+ *
978
+ * @param level - Log level (INFO, WARN, ERROR)
979
+ * @param context - Context of the log (Init, Auth, Token, Session, State)
980
+ * @param message - Log message
981
+ * @param data - Optional data to log
982
+ *
983
+ * @remarks
984
+ * Format: [Lixa] [timestamp] [level] [context] message
985
+ * Only logs when debug mode is enabled.
986
+ */
987
+ private log;
988
+ /**
989
+ * Checks if a provider is configured for this instance.
990
+ * This is a type guard that narrows the provider type for use with getAuthUrl.
991
+ *
992
+ * @param provider - The provider name to check (case-insensitive)
993
+ * @returns True if the provider is configured, false otherwise
994
+ *
995
+ * @example
996
+ * ```typescript
997
+ * if (lixa.isProviderConfigured(provider)) {
998
+ * // TypeScript now knows provider is a valid ConfiguredProviderKey
999
+ * const authUrl = lixa.getAuthUrl(provider, state);
1000
+ * }
1001
+ * ```
1002
+ */
1003
+ isProviderConfigured<T extends string>(provider: T): provider is T & ConfiguredProviderKey<TConfig>;
1004
+ /**
1005
+ * Gets a provider implementation by name.
1006
+ * Resolution priority: inline custom provider \> default providers \> legacy registry
1007
+ *
1008
+ * @param name - The provider name (case-insensitive)
1009
+ * @param config - The provider configuration
1010
+ * @returns The provider implementation
1011
+ * @throws Error when provider is not found
1012
+ */
1013
+ private getProvider;
1014
+ /**
1015
+ * Registers custom OAuth providers for use with Lixa.
1016
+ *
1017
+ * @deprecated This method is maintained for backward compatibility.
1018
+ * The recommended approach is to pass providers inline in the configuration:
1019
+ * ```typescript
1020
+ * const lixa = new Lixa({
1021
+ * providers: {
1022
+ * custom: {
1023
+ * provider: new CustomProvider(),
1024
+ * clientId: '...',
1025
+ * // ...
1026
+ * }
1027
+ * }
1028
+ * });
1029
+ * ```
1030
+ *
1031
+ * @param providerMap - A map of provider names to IProvider implementations
1032
+ *
1033
+ * @example
1034
+ * Legacy usage (still supported):
1035
+ * ```typescript
1036
+ * class CustomProvider implements IProvider {
1037
+ * authorizationEndpoint = 'https://custom.com/oauth/authorize';
1038
+ * tokenEndpoint = 'https://custom.com/oauth/token';
1039
+ * userInfoEndpoint = 'https://custom.com/api/user';
1040
+ * }
1041
+ *
1042
+ * Lixa.registerProvider({ custom: new CustomProvider() });
1043
+ * ```
1044
+ */
1045
+ static registerProvider<T extends Record<string, IProvider>>(providerMap: T): void;
1046
+ /**
1047
+ * Gets the list of registered provider names.
1048
+ *
1049
+ * @returns Array of registered provider names
1050
+ */
1051
+ static getRegisteredProviders(): string[];
1052
+ /**
1053
+ * Creates a type-safe configuration.
1054
+ *
1055
+ * @deprecated This method is maintained for backward compatibility.
1056
+ * You can now pass configuration directly to the Lixa constructor without this helper.
1057
+ *
1058
+ * @param config - Configuration object with provider settings
1059
+ * @returns The same configuration object with type safety
1060
+ *
1061
+ * @example
1062
+ * New approach (recommended):
1063
+ * ```typescript
1064
+ * const lixa = new Lixa({
1065
+ * providers: {
1066
+ * google: {
1067
+ * provider: new GoogleProvider(),
1068
+ * clientId: '...',
1069
+ * // ...
1070
+ * }
1071
+ * }
1072
+ * });
1073
+ * ```
1074
+ */
1075
+ static createConfig<T extends Record<string, ProviderConfig>>(config: LixaConfig<T> & {
1076
+ providers: T;
1077
+ }): LixaConfig<T>;
1078
+ /**
1079
+ * Generates a cryptographically secure random state parameter for OAuth flows.
1080
+ *
1081
+ * @returns A 32-character hexadecimal string
1082
+ *
1083
+ * @remarks
1084
+ * The state parameter is used to prevent CSRF attacks in OAuth flows.
1085
+ */
1086
+ static generateRandomState(): string;
1087
+ /**
1088
+ * Generates a cryptographically secure code verifier for PKCE flows.
1089
+ *
1090
+ * @returns A 64-character hexadecimal string (32 random bytes encoded as hex)
1091
+ *
1092
+ * @remarks
1093
+ * This method implements the code verifier generation as specified in RFC 7636 (PKCE).
1094
+ *
1095
+ * **PKCE (Proof Key for Code Exchange)** is a security extension to OAuth 2.0 that
1096
+ * prevents authorization code interception attacks. It's especially important for
1097
+ * public clients (mobile apps, SPAs) but is recommended for all OAuth flows.
1098
+ *
1099
+ * **Generation methodology:**
1100
+ * 1. Generate 32 cryptographically random bytes using Node.js crypto.randomBytes()
1101
+ * 2. Encode the bytes as a hexadecimal string (64 characters)
1102
+ * 3. The verifier is stored securely and used later in the token exchange
1103
+ *
1104
+ * **RFC 7636 Requirements:**
1105
+ * - Minimum length: 43 characters
1106
+ * - Maximum length: 128 characters
1107
+ * - Character set: [A-Z] / [a-z] / [0-9] / "-" / "." / "_" / "~"
1108
+ * - This implementation produces 64 hex characters, meeting the requirements
1109
+ *
1110
+ * The code verifier is:
1111
+ * - Generated when creating the authorization URL
1112
+ * - Stored in state cache with the state parameter
1113
+ * - Retrieved during callback handling
1114
+ * - Sent to the token endpoint to prove the client's identity
1115
+ *
1116
+ * @see {@link https://datatracker.ietf.org/doc/html/rfc7636 | RFC 7636 - PKCE}
1117
+ * @see buildCodeChallenge for the corresponding challenge generation
1118
+ *
1119
+ * @internal
1120
+ */
1121
+ private static generateCodeVerifier;
1122
+ /**
1123
+ * Generates a code challenge from a code verifier for PKCE flows.
1124
+ *
1125
+ * @param codeVerifier - The code verifier string (64 hex characters)
1126
+ * @returns A base64url-encoded SHA-256 hash of the code verifier
1127
+ *
1128
+ * @remarks
1129
+ * This method implements the code challenge generation as specified in RFC 7636 (PKCE)
1130
+ * using the S256 (SHA-256) transformation method.
1131
+ *
1132
+ * **Challenge generation methodology:**
1133
+ * 1. Hash the code verifier using SHA-256
1134
+ * 2. Encode the hash as base64
1135
+ * 3. Convert to base64url format (RFC 4648):
1136
+ * - Replace '+' with '-'
1137
+ * - Replace '/' with '_'
1138
+ * - Remove trailing '=' padding
1139
+ *
1140
+ * **PKCE Flow:**
1141
+ * 1. Client generates code_verifier (random string)
1142
+ * 2. Client creates code_challenge = BASE64URL(SHA256(code_verifier))
1143
+ * 3. Client sends code_challenge to authorization endpoint
1144
+ * 4. Authorization server stores the code_challenge
1145
+ * 5. Client sends code_verifier to token endpoint
1146
+ * 6. Authorization server verifies: SHA256(code_verifier) == code_challenge
1147
+ *
1148
+ * **Security Benefits:**
1149
+ * - Prevents authorization code interception attacks
1150
+ * - Even if an attacker intercepts the authorization code, they cannot
1151
+ * exchange it for tokens without the original code_verifier
1152
+ * - The challenge is sent in the authorization request (public)
1153
+ * - The verifier is sent in the token request (should be kept secret)
1154
+ *
1155
+ * **RFC 7636 Transformation Methods:**
1156
+ * - plain: code_challenge = code_verifier (not recommended)
1157
+ * - S256: code_challenge = BASE64URL(SHA256(code_verifier)) (recommended, used here)
1158
+ *
1159
+ * @see {@link https://datatracker.ietf.org/doc/html/rfc7636 | RFC 7636 - PKCE}
1160
+ * @see {@link https://datatracker.ietf.org/doc/html/rfc4648#section-5 | RFC 4648 - Base64url Encoding}
1161
+ * @see generateCodeVerifier for the verifier generation
1162
+ *
1163
+ * @internal
1164
+ */
1165
+ private static buildCodeChallenge;
1166
+ /**
1167
+ * Generates the authorization URL for the specified provider.
1168
+ *
1169
+ * @param provider - The provider name (must be a configured provider key)
1170
+ * @param state - The state parameter for CSRF protection
1171
+ * @returns The complete authorization URL to redirect users to
1172
+ *
1173
+ * @throws Error when the provider is not configured
1174
+ *
1175
+ * @example
1176
+ * ```typescript
1177
+ * const state = Lixa.generateRandomState();
1178
+ * const authUrl = lixa.getAuthUrl('google', state);
1179
+ * res.redirect(authUrl);
1180
+ * ```
1181
+ */
1182
+ getAuthUrl(provider: ConfiguredProviderKey<TConfig> | string, state?: string): Promise<string>;
1183
+ /**
1184
+ * Restricts primary authentication scopes strictly to AuthN identity scopes.
1185
+ */
1186
+ private resolveAuthNScopes;
1187
+ /**
1188
+ * Handles the OAuth callback and creates a user session.
1189
+ *
1190
+ * @param provider - The provider name (must be a configured provider key)
1191
+ * @param code - The authorization code from the provider
1192
+ * @param state - The state parameter for validation
1193
+ * @returns A Promise that resolves to the session ID
1194
+ *
1195
+ * @throws Error when code or state is missing/invalid, or provider is not configured
1196
+ *
1197
+ * @example
1198
+ * ```typescript
1199
+ * const sessionId = await lixa.handleCallback({
1200
+ * provider: 'google',
1201
+ * code: req.query.code,
1202
+ * state: req.query.state
1203
+ * });
1204
+ * ```
1205
+ */
1206
+ handleCallback({ provider, code, state, }: {
1207
+ provider: ConfiguredProviderKey<TConfig> | string;
1208
+ code: string;
1209
+ state?: string;
1210
+ }): Promise<string>;
1211
+ /**
1212
+ * Explicitly link a new OAuth provider account to an active session.
1213
+ *
1214
+ * @param params - Object containing sessionId, provider, code, and optional state
1215
+ * @returns The active session ID with the newly linked provider
1216
+ */
1217
+ linkAccount(params: {
1218
+ sessionId: string;
1219
+ provider: ConfiguredProviderKey<TConfig> | string;
1220
+ code: string;
1221
+ state?: string;
1222
+ }): Promise<string>;
1223
+ /**
1224
+ * Unlinks an OAuth provider account from an active session.
1225
+ *
1226
+ * @param sessionId - Active session ID
1227
+ * @param providerToUnlink - Provider name to unlink (e.g. 'github')
1228
+ * @returns Promise resolving to true on successful unlink
1229
+ */
1230
+ unlinkAccount(sessionId: string, providerToUnlink: string): Promise<boolean>;
1231
+ /**
1232
+ * Generates an authorization URL for connecting a resource provider (AuthZ) post-login.
1233
+ *
1234
+ * @remarks
1235
+ * Resource authorization is kept strictly separate from primary authentication (AuthN).
1236
+ * Call this method after a user is authenticated to request permissions for external API access
1237
+ * (e.g. GitHub repositories, Google Drive, Slack, etc.).
1238
+ *
1239
+ * @param params - Object containing sessionId, provider, requested resource scopes, and optional state
1240
+ * @returns The authorization URL for resource consent
1241
+ */
1242
+ getResourceAuthUrl(params: {
1243
+ sessionId: string;
1244
+ provider: ConfiguredProviderKey<TConfig> | string;
1245
+ scopes: string[];
1246
+ state?: string;
1247
+ }): Promise<string>;
1248
+ /**
1249
+ * Handles the OAuth callback for a connected resource provider and stores resource tokens on the session.
1250
+ *
1251
+ * @param params - Object containing sessionId, provider, code, state, and requested scopes
1252
+ * @returns Updated Session containing stored resource tokens under session.resources[provider]
1253
+ */
1254
+ handleResourceCallback(params: {
1255
+ sessionId: string;
1256
+ provider: ConfiguredProviderKey<TConfig> | string;
1257
+ code: string;
1258
+ state?: string;
1259
+ scopes?: string[];
1260
+ }): Promise<Session>;
1261
+ /**
1262
+ * Retrieves a connected resource provider token for an active session.
1263
+ *
1264
+ * @param sessionId - Active session ID
1265
+ * @param provider - Provider identifier (e.g. 'github')
1266
+ */
1267
+ getConnectedResource(sessionId: string, provider: string): Promise<ConnectedResource | null>;
1268
+ /**
1269
+ * Disconnects a resource provider from an active session.
1270
+ *
1271
+ * @param sessionId - Active session ID
1272
+ * @param provider - Provider identifier to disconnect
1273
+ */
1274
+ disconnectResource(sessionId: string, provider: string): Promise<boolean>;
1275
+ fetchSessionInfo(sessionId: string): Promise<Session | null>;
1276
+ private exchangeCodeForToken;
1277
+ private findProviderByType;
1278
+ }
1279
+
1280
+ /**
1281
+ * User information extracted from OAuth provider
1282
+ *
1283
+ * @public
1284
+ */
1285
+ interface UserInfo {
1286
+ email: string;
1287
+ id?: string | undefined;
1288
+ sub?: string | undefined;
1289
+ given_name?: string | undefined;
1290
+ family_name?: string | undefined;
1291
+ name?: string | undefined;
1292
+ picture?: string | undefined;
1293
+ email_verified?: boolean | undefined;
1294
+ iss?: string | undefined;
1295
+ }
1296
+ /**
1297
+ * Decode JWT ID token to extract user information
1298
+ *
1299
+ * @public
1300
+ */
1301
+ declare function decodeIdToken(idToken: string): UserInfo;
1302
+ /**
1303
+ * Determine OAuth provider from ID token issuer
1304
+ *
1305
+ * @public
1306
+ */
1307
+ declare function determineProviderFromIssuer(userInfo: UserInfo): string | null;
1308
+ /**
1309
+ * Fetch user info from OAuth provider's userinfo endpoint
1310
+ *
1311
+ * @param accessToken - OAuth access token
1312
+ * @param userInfoEndpoint - The provider's userinfo endpoint URL
1313
+ * @param providerName - Provider name for error messages (optional)
1314
+ * @returns User information from the provider
1315
+ *
1316
+ * @throws Error if the request fails or response is invalid
1317
+ *
1318
+ * @public
1319
+ */
1320
+ declare function fetchUserInfo(accessToken: string, userInfoEndpoint: string): Promise<UserInfo>;
1321
+ /**
1322
+ * Extract user info from OAuth token data
1323
+ *
1324
+ * @param tokenData - OAuth token response from provider
1325
+ * @param providerMetadata - Provider metadata containing endpoints configuration
1326
+ * @returns User info extracted from token or fetched from provider
1327
+ *
1328
+ * @remarks
1329
+ * This function attempts to extract user information in the following order:
1330
+ * 1. Decode ID token if present (preferred method for OIDC providers)
1331
+ * 2. Fetch from userinfo endpoint using access token (uses providerMetadata.endpoints.userInfo)
1332
+ *
1333
+ * The function automatically determines the best method based on available token data.
1334
+ * For OIDC providers (like Google), it decodes the JWT ID token.
1335
+ * For OAuth-only providers (like GitHub), it fetches from the userinfo endpoint.
1336
+ *
1337
+ * @throws Error if no ID token or access token is available
1338
+ * @throws Error if userinfo endpoint is required but not provided in providerMetadata
1339
+ *
1340
+ * @example
1341
+ * With ID token (OIDC provider like Google):
1342
+ * ```typescript
1343
+ * const { userInfo } = await extractUserInfo(tokenData, providerMetadata);
1344
+ * console.log(`User ${userInfo.email} authenticated`);
1345
+ * ```
1346
+ *
1347
+ * @example
1348
+ * Without ID token (OAuth provider like GitHub):
1349
+ * ```typescript
1350
+ * const { userInfo } = await extractUserInfo(tokenData, providerMetadata);
1351
+ * // Automatically fetches from providerMetadata.endpoints.userInfo
1352
+ * console.log(`User ${userInfo.email} authenticated`);
1353
+ * ```
1354
+ *
1355
+ * @public
1356
+ */
1357
+ declare function extractUserInfo(tokenData: OAuthTokenResponse, providerMetadata: ProviderMetadata): Promise<{
1358
+ userInfo: UserInfo;
1359
+ }>;
1360
+
1361
+ export { type AccountLinkingConfig, type AccountLinkingMode, AccountLinkingStrategy, type ConnectedResource, type IProvider, Lixa, type LixaConfig, type OAuthTokenResponse, type ProviderConfig, type ProviderMetadata, type SafeLixaConfig, type Session, type SessionHandler, type SessionStorage, type StateData, type StateHandler, type StateStorage, type UserInfo, decodeIdToken, determineProviderFromIssuer, extractUserInfo, fetchUserInfo };