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