@vunexa/lixa 0.0.1-alpha.18 → 0.0.1-alpha.20
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 +293 -11
- package/dist/export-types/index.d.ts +5 -0
- package/dist/index.cjs +17 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +5 -0
- package/dist/index.js +17 -1
- package/dist/index.js.map +1 -1
- package/dist/lixa.d.ts +3 -0
- package/dist/lixa.d.ts.map +1 -1
- package/dist/types.d.ts +2 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -123,6 +123,158 @@ app.get("/auth/:provider/callback", async (req, res) => {
|
|
|
123
123
|
|
|
124
124
|
## Advanced Usage
|
|
125
125
|
|
|
126
|
+
### Custom State Storage (StateDao)
|
|
127
|
+
|
|
128
|
+
By default, Lixa uses an in-memory cache for state management. For production applications or serverless environments, you should implement a custom state storage:
|
|
129
|
+
|
|
130
|
+
```typescript
|
|
131
|
+
import { Lixa } from "@vunexa/lixa";
|
|
132
|
+
|
|
133
|
+
// Example: DynamoDB state storage
|
|
134
|
+
const dynamoDbStateDao = {
|
|
135
|
+
saveState: async (state: string, data: any, expiresInSeconds: number) => {
|
|
136
|
+
await dynamoDB.put({
|
|
137
|
+
TableName: "oauth-states",
|
|
138
|
+
Item: {
|
|
139
|
+
state,
|
|
140
|
+
data: JSON.stringify(data),
|
|
141
|
+
expiresAt: Math.floor(Date.now() / 1000) + expiresInSeconds,
|
|
142
|
+
},
|
|
143
|
+
});
|
|
144
|
+
},
|
|
145
|
+
|
|
146
|
+
getState: async (state: string) => {
|
|
147
|
+
const result = await dynamoDB.get({
|
|
148
|
+
TableName: "oauth-states",
|
|
149
|
+
Key: { state },
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
if (!result.Item) return null;
|
|
153
|
+
|
|
154
|
+
if (result.Item.expiresAt < Math.floor(Date.now() / 1000)) {
|
|
155
|
+
return null; // Expired
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
return JSON.parse(result.Item.data);
|
|
159
|
+
},
|
|
160
|
+
|
|
161
|
+
deleteState: async (state: string) => {
|
|
162
|
+
await dynamoDB.delete({
|
|
163
|
+
TableName: "oauth-states",
|
|
164
|
+
Key: { state },
|
|
165
|
+
});
|
|
166
|
+
},
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
const lixa = new Lixa({
|
|
170
|
+
providers: { /* ... */ },
|
|
171
|
+
stateDao: dynamoDbStateDao,
|
|
172
|
+
});
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
**Important**: The state data includes a `codeVerifier` field required for PKCE. Make sure your storage preserves all fields in the data object.
|
|
176
|
+
|
|
177
|
+
### Custom Session Storage (SessionDao)
|
|
178
|
+
|
|
179
|
+
Similar to state storage, you can implement custom session storage:
|
|
180
|
+
|
|
181
|
+
```typescript
|
|
182
|
+
const customSessionDao = {
|
|
183
|
+
saveSession: async (sessionId: string, session: any, expiresInSeconds: number) => {
|
|
184
|
+
// Store session in your database
|
|
185
|
+
await db.sessions.create({
|
|
186
|
+
id: sessionId,
|
|
187
|
+
data: session,
|
|
188
|
+
expiresAt: Date.now() + expiresInSeconds * 1000,
|
|
189
|
+
});
|
|
190
|
+
},
|
|
191
|
+
|
|
192
|
+
getSession: async (sessionId: string) => {
|
|
193
|
+
const session = await db.sessions.findById(sessionId);
|
|
194
|
+
if (!session || session.expiresAt < Date.now()) {
|
|
195
|
+
return null;
|
|
196
|
+
}
|
|
197
|
+
return session.data;
|
|
198
|
+
},
|
|
199
|
+
|
|
200
|
+
deleteSession: async (sessionId: string) => {
|
|
201
|
+
await db.sessions.delete(sessionId);
|
|
202
|
+
},
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
const lixa = new Lixa({
|
|
206
|
+
providers: { /* ... */ },
|
|
207
|
+
sessionDao: customSessionDao,
|
|
208
|
+
});
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
### Custom Session Strategy
|
|
212
|
+
|
|
213
|
+
The session strategy controls how user sessions are created from OAuth tokens:
|
|
214
|
+
|
|
215
|
+
```typescript
|
|
216
|
+
const customSessionStrategy = {
|
|
217
|
+
createSession: async (tokenData) => {
|
|
218
|
+
// tokenData contains: access_token, refresh_token, id_token, etc.
|
|
219
|
+
|
|
220
|
+
// Decode ID token to get user info (for OIDC providers like Google)
|
|
221
|
+
let userInfo;
|
|
222
|
+
if (tokenData.id_token) {
|
|
223
|
+
const base64Payload = tokenData.id_token.split('.')[1];
|
|
224
|
+
const payload = Buffer.from(base64Payload, 'base64').toString();
|
|
225
|
+
userInfo = JSON.parse(payload);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// Create or update user in your database
|
|
229
|
+
const user = await db.users.upsert({
|
|
230
|
+
email: userInfo.email,
|
|
231
|
+
name: userInfo.name,
|
|
232
|
+
// ... other fields
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
// Create session in your database
|
|
236
|
+
const sessionId = generateUniqueId();
|
|
237
|
+
await db.sessions.create({
|
|
238
|
+
id: sessionId,
|
|
239
|
+
userId: user.id,
|
|
240
|
+
accessToken: tokenData.access_token,
|
|
241
|
+
refreshToken: tokenData.refresh_token,
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
return {
|
|
245
|
+
token: sessionId,
|
|
246
|
+
raw: {
|
|
247
|
+
...tokenData,
|
|
248
|
+
userId: user.id,
|
|
249
|
+
userInfo,
|
|
250
|
+
},
|
|
251
|
+
};
|
|
252
|
+
},
|
|
253
|
+
};
|
|
254
|
+
|
|
255
|
+
const lixa = new Lixa({
|
|
256
|
+
providers: { /* ... */ },
|
|
257
|
+
sessionStrategy: customSessionStrategy,
|
|
258
|
+
});
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
### Debug Mode
|
|
262
|
+
|
|
263
|
+
Enable debug logging to troubleshoot OAuth flows:
|
|
264
|
+
|
|
265
|
+
```typescript
|
|
266
|
+
const lixa = new Lixa({
|
|
267
|
+
providers: { /* ... */ },
|
|
268
|
+
debug: true, // Enables detailed logging
|
|
269
|
+
});
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
Debug mode logs:
|
|
273
|
+
- Token exchange requests and responses
|
|
274
|
+
- State validation
|
|
275
|
+
- Session creation
|
|
276
|
+
- Error details from OAuth providers
|
|
277
|
+
|
|
126
278
|
### Custom Provider Registration
|
|
127
279
|
|
|
128
280
|
You can register custom OAuth providers by implementing the `IProvider` interface:
|
|
@@ -136,7 +288,7 @@ class CustomProvider implements IProvider {
|
|
|
136
288
|
userInfoEndpoint = "https://custom-provider.com/api/user";
|
|
137
289
|
}
|
|
138
290
|
|
|
139
|
-
// Register the custom provider
|
|
291
|
+
// Register the custom provider BEFORE creating Lixa instance
|
|
140
292
|
Lixa.registerProvider({
|
|
141
293
|
custom: new CustomProvider(),
|
|
142
294
|
});
|
|
@@ -161,6 +313,76 @@ const lixa = new Lixa({
|
|
|
161
313
|
if (Lixa.isProviderRegistered("google")) {
|
|
162
314
|
console.log("Google provider is available");
|
|
163
315
|
}
|
|
316
|
+
|
|
317
|
+
// Get list of all registered providers
|
|
318
|
+
const providers = Lixa.getRegisteredProviders();
|
|
319
|
+
console.log("Available providers:", providers);
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
## Common Pitfalls & Solutions
|
|
323
|
+
|
|
324
|
+
### 1. "Invalid or expired state" Error
|
|
325
|
+
|
|
326
|
+
**Cause**: The state parameter is not being stored or retrieved correctly.
|
|
327
|
+
|
|
328
|
+
**Solution**: Implement a custom `stateDao` that persists state across requests. The default in-memory cache doesn't work in serverless or multi-instance environments.
|
|
329
|
+
|
|
330
|
+
### 2. "Missing code verifier" Error
|
|
331
|
+
|
|
332
|
+
**Cause**: The `codeVerifier` field is not being preserved in your state storage.
|
|
333
|
+
|
|
334
|
+
**Solution**: Ensure your `stateDao.saveState()` stores ALL fields from the data object, including `codeVerifier`:
|
|
335
|
+
|
|
336
|
+
```typescript
|
|
337
|
+
saveState: async (state: string, data: any, expiresInSeconds: number) => {
|
|
338
|
+
// ✅ Correct: Store the entire data object
|
|
339
|
+
await storage.save({ state, data, expiresAt: ... });
|
|
340
|
+
|
|
341
|
+
// ❌ Wrong: Only storing some fields
|
|
342
|
+
await storage.save({ state, provider: data.provider, expiresAt: ... });
|
|
343
|
+
}
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
### 3. Token Exchange Fails with 400 Bad Request
|
|
347
|
+
|
|
348
|
+
**Causes**:
|
|
349
|
+
- Redirect URI mismatch between your config and OAuth provider console
|
|
350
|
+
- Invalid client ID or secret
|
|
351
|
+
- Code has already been used or expired
|
|
352
|
+
|
|
353
|
+
**Solution**:
|
|
354
|
+
- Enable debug mode to see the exact error from the provider
|
|
355
|
+
- Verify redirect URI matches exactly (including protocol, port, path)
|
|
356
|
+
- Check that client credentials are correct
|
|
357
|
+
|
|
358
|
+
### 4. Session Not Found After Creation
|
|
359
|
+
|
|
360
|
+
**Cause**: Using default in-memory session storage in serverless/distributed environments.
|
|
361
|
+
|
|
362
|
+
**Solution**: Implement a custom `sessionDao` that uses persistent storage (database, Redis, etc.).
|
|
363
|
+
|
|
364
|
+
### 5. User Info is Undefined
|
|
365
|
+
|
|
366
|
+
**Cause**: The `sessionStrategy.createSession()` receives raw token data, not user info.
|
|
367
|
+
|
|
368
|
+
**Solution**: Decode the `id_token` (for OIDC providers) or fetch user info from the provider's API:
|
|
369
|
+
|
|
370
|
+
```typescript
|
|
371
|
+
createSession: async (tokenData) => {
|
|
372
|
+
// For OIDC providers (Google, etc.)
|
|
373
|
+
if (tokenData.id_token) {
|
|
374
|
+
const base64Payload = tokenData.id_token.split('.')[1];
|
|
375
|
+
const userInfo = JSON.parse(Buffer.from(base64Payload, 'base64').toString());
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
// For OAuth-only providers (GitHub, etc.)
|
|
379
|
+
else if (tokenData.access_token) {
|
|
380
|
+
const response = await fetch(providerUserInfoEndpoint, {
|
|
381
|
+
headers: { Authorization: `Bearer ${tokenData.access_token}` }
|
|
382
|
+
});
|
|
383
|
+
const userInfo = await response.json();
|
|
384
|
+
}
|
|
385
|
+
}
|
|
164
386
|
```
|
|
165
387
|
|
|
166
388
|
## API Reference
|
|
@@ -173,14 +395,16 @@ if (Lixa.isProviderRegistered("google")) {
|
|
|
173
395
|
|
|
174
396
|
#### Static Methods
|
|
175
397
|
|
|
176
|
-
- `Lixa.registerProvider(providerMap: { [key: string]: IProvider })` - Register custom providers
|
|
398
|
+
- `Lixa.registerProvider(providerMap: { [key: string]: IProvider })` - Register custom providers before creating instances
|
|
177
399
|
- `Lixa.isProviderRegistered(provider: string): boolean` - Check if a provider is registered
|
|
400
|
+
- `Lixa.getRegisteredProviders(): string[]` - Get list of all registered provider names
|
|
401
|
+
- `Lixa.generateRandomState(): string` - Generate a cryptographically secure random state string
|
|
178
402
|
|
|
179
403
|
#### Instance Methods
|
|
180
404
|
|
|
181
|
-
- `
|
|
182
|
-
- `
|
|
183
|
-
- `
|
|
405
|
+
- `getAuthUrl(provider: string, state: string): string` - Generate authorization URL for a provider. Automatically stores state with PKCE code verifier.
|
|
406
|
+
- `handleCallback({ provider, code, state }): Promise<string>` - Handle OAuth callback, validate state, exchange code for tokens, and create session. Returns session ID.
|
|
407
|
+
- `fetchSessionInfo(sessionId: string): Promise<Session | null>` - Retrieve session information by session ID
|
|
184
408
|
|
|
185
409
|
### Types
|
|
186
410
|
|
|
@@ -190,21 +414,36 @@ interface ProviderConfig {
|
|
|
190
414
|
clientSecret: string;
|
|
191
415
|
redirectUri: string;
|
|
192
416
|
scopes: string[];
|
|
193
|
-
extraConfig?: Record<string, any>;
|
|
417
|
+
extraConfig?: Record<string, any>; // Provider-specific parameters
|
|
194
418
|
}
|
|
195
419
|
|
|
196
420
|
interface LixaConfig {
|
|
197
421
|
providers: Record<string, ProviderConfig>;
|
|
198
422
|
sessionStrategy?: SessionStrategy;
|
|
423
|
+
stateDao?: StateDao; // Custom state storage
|
|
424
|
+
sessionDao?: SessionDao; // Custom session storage
|
|
425
|
+
debug?: boolean; // Enable debug logging
|
|
199
426
|
}
|
|
200
427
|
|
|
201
428
|
interface SessionStrategy {
|
|
202
|
-
createSession(
|
|
429
|
+
createSession(tokenData: any): Promise<Session>;
|
|
203
430
|
}
|
|
204
431
|
|
|
205
432
|
interface Session {
|
|
206
|
-
token: string;
|
|
207
|
-
raw: any;
|
|
433
|
+
token: string; // Your custom session identifier
|
|
434
|
+
raw: any; // Raw data you want to store with the session
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
interface StateDao {
|
|
438
|
+
saveState(state: string, data: any, expiresInSeconds: number): Promise<void>;
|
|
439
|
+
getState(state: string): Promise<any | null>;
|
|
440
|
+
deleteState(state: string): Promise<void>;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
interface SessionDao {
|
|
444
|
+
saveSession(sessionId: string, session: Session, expiresInSeconds: number): Promise<void>;
|
|
445
|
+
getSession(sessionId: string): Promise<Session | null>;
|
|
446
|
+
deleteSession(sessionId: string): Promise<void>;
|
|
208
447
|
}
|
|
209
448
|
|
|
210
449
|
interface IProvider {
|
|
@@ -216,8 +455,51 @@ interface IProvider {
|
|
|
216
455
|
|
|
217
456
|
## Built-in Providers
|
|
218
457
|
|
|
219
|
-
|
|
220
|
-
- **
|
|
458
|
+
### Google
|
|
459
|
+
- **Type**: OAuth 2.0 + OpenID Connect (OIDC)
|
|
460
|
+
- **Authorization Endpoint**: `https://accounts.google.com/o/oauth2/v2/auth`
|
|
461
|
+
- **Token Endpoint**: `https://oauth2.googleapis.com/token`
|
|
462
|
+
- **User Info Endpoint**: `https://www.googleapis.com/oauth2/v2/userinfo`
|
|
463
|
+
- **Supports**: PKCE, ID tokens, refresh tokens
|
|
464
|
+
- **Common Scopes**: `openid`, `email`, `profile`
|
|
465
|
+
|
|
466
|
+
### GitHub
|
|
467
|
+
- **Type**: OAuth 2.0
|
|
468
|
+
- **Authorization Endpoint**: `https://github.com/login/oauth/authorize`
|
|
469
|
+
- **Token Endpoint**: `https://github.com/login/oauth/access_token`
|
|
470
|
+
- **User Info Endpoint**: `https://api.github.com/user`
|
|
471
|
+
- **Supports**: PKCE
|
|
472
|
+
- **Common Scopes**: `read:user`, `user:email`
|
|
473
|
+
|
|
474
|
+
## Security Considerations
|
|
475
|
+
|
|
476
|
+
### PKCE (Proof Key for Code Exchange)
|
|
477
|
+
|
|
478
|
+
Lixa automatically implements PKCE for all OAuth flows:
|
|
479
|
+
- Generates a cryptographically secure code verifier
|
|
480
|
+
- Creates SHA-256 code challenge
|
|
481
|
+
- Stores code verifier with state
|
|
482
|
+
- Sends code verifier during token exchange
|
|
483
|
+
|
|
484
|
+
This protects against authorization code interception attacks.
|
|
485
|
+
|
|
486
|
+
### State Parameter
|
|
487
|
+
|
|
488
|
+
The state parameter prevents CSRF attacks:
|
|
489
|
+
- Always generated using cryptographically secure random bytes
|
|
490
|
+
- Must be validated on callback
|
|
491
|
+
- Automatically stored and validated when using custom `stateDao`
|
|
492
|
+
- Single-use (deleted after validation)
|
|
493
|
+
|
|
494
|
+
### Best Practices
|
|
495
|
+
|
|
496
|
+
1. **Always use HTTPS** in production for redirect URIs
|
|
497
|
+
2. **Implement custom storage** (StateDao/SessionDao) for production
|
|
498
|
+
3. **Set short TTLs** for state (5 minutes) and sessions (24 hours recommended)
|
|
499
|
+
4. **Validate state parameter** on every callback
|
|
500
|
+
5. **Store tokens securely** - never expose access/refresh tokens to client-side code
|
|
501
|
+
6. **Use HttpOnly cookies** for session tokens
|
|
502
|
+
7. **Enable debug mode** only in development
|
|
221
503
|
|
|
222
504
|
## Development
|
|
223
505
|
|
|
@@ -85,12 +85,15 @@ export declare class Lixa<TConfig extends LixaConfig<any> = LixaConfig> {
|
|
|
85
85
|
private stateDao;
|
|
86
86
|
private sesionDao;
|
|
87
87
|
private sessionStrategy;
|
|
88
|
+
private debug;
|
|
88
89
|
/**
|
|
89
90
|
* Creates a new Lixa instance with the provided configuration.
|
|
90
91
|
*
|
|
91
92
|
* @param config - The configuration object containing provider settings and optional session strategy
|
|
92
93
|
*/
|
|
93
94
|
constructor(config: TConfig);
|
|
95
|
+
private log;
|
|
96
|
+
private logError;
|
|
94
97
|
/**
|
|
95
98
|
* Checks if a provider is both registered and configured for this instance.
|
|
96
99
|
* This is a type guard that narrows the provider type for use with getAuthUrl.
|
|
@@ -219,6 +222,8 @@ export declare interface LixaConfig<TRegisteredProviders extends string = string
|
|
|
219
222
|
stateDao?: StateDao;
|
|
220
223
|
/** Optiona: custom session storage implementation */
|
|
221
224
|
sessionDao?: SessionDao;
|
|
225
|
+
/** Enable debug logging */
|
|
226
|
+
debug?: boolean;
|
|
222
227
|
}
|
|
223
228
|
|
|
224
229
|
/**
|
package/dist/index.cjs
CHANGED
|
@@ -108,6 +108,7 @@ var Lixa = class _Lixa {
|
|
|
108
108
|
stateDao;
|
|
109
109
|
sesionDao;
|
|
110
110
|
sessionStrategy;
|
|
111
|
+
debug;
|
|
111
112
|
/**
|
|
112
113
|
* Creates a new Lixa instance with the provided configuration.
|
|
113
114
|
*
|
|
@@ -125,6 +126,17 @@ var Lixa = class _Lixa {
|
|
|
125
126
|
this.stateDao = config.stateDao || _Lixa.LOCAL_STATE_CACHE;
|
|
126
127
|
this.sesionDao = config.sessionDao || _Lixa.LOCAL_SESSION_CACHE;
|
|
127
128
|
this.sessionStrategy = config.sessionStrategy || _Lixa.DEFAULT_SESSION_STRATEGY;
|
|
129
|
+
this.debug = config.debug || false;
|
|
130
|
+
}
|
|
131
|
+
log(...args) {
|
|
132
|
+
if (this.debug) {
|
|
133
|
+
console.log("[Lixa]", ...args);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
logError(...args) {
|
|
137
|
+
if (this.debug) {
|
|
138
|
+
console.error("[Lixa]", ...args);
|
|
139
|
+
}
|
|
128
140
|
}
|
|
129
141
|
/**
|
|
130
142
|
* Checks if a provider is both registered and configured for this instance.
|
|
@@ -331,6 +343,8 @@ var Lixa = class _Lixa {
|
|
|
331
343
|
body.code_verifier = codeVerifier;
|
|
332
344
|
}
|
|
333
345
|
const params = new URLSearchParams(body);
|
|
346
|
+
this.log("Token Exchange - Request body:", params.toString());
|
|
347
|
+
this.log("Token Exchange - Token endpoint:", providerImpl.tokenEndpoint);
|
|
334
348
|
const response = await fetch(providerImpl.tokenEndpoint, {
|
|
335
349
|
method: "POST",
|
|
336
350
|
headers: {
|
|
@@ -340,8 +354,10 @@ var Lixa = class _Lixa {
|
|
|
340
354
|
body: params.toString()
|
|
341
355
|
});
|
|
342
356
|
if (!response.ok) {
|
|
357
|
+
const errorBody = await response.text();
|
|
358
|
+
this.logError("Token Exchange - Error response:", errorBody);
|
|
343
359
|
throw new Error(
|
|
344
|
-
`Token exchange failed: ${response.status} ${response.statusText}`
|
|
360
|
+
`Token exchange failed: ${response.status} ${response.statusText} - ${errorBody}`
|
|
345
361
|
);
|
|
346
362
|
}
|
|
347
363
|
return response.json();
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/lixa.ts","../src/dao/state-cache.ts","../src/dao/session-cache.ts","../src/models/session.ts"],"sourcesContent":["/**\n * A flexible, provider-agnostic OAuth 2.0 and OpenID Connect (OIDC) client library for backend applications.\n * \n * @remarks\n * This package simplifies multi-provider authentication flows (e.g., Google, GitHub), supports extensible session management, and enables custom provider registration.\n * \n * @packageDocumentation\n */\n\nexport { Lixa } from \"./lixa\";\nexport {\n type ProviderConfig,\n type LixaConfig,\n type SafeLixaConfig,\n} from \"./types\";\nexport { type Session, type SessionStrategy, DefaultSessionStrategy } from \"./models/session\";\nexport { type IProvider } from \"./providers\";\n","import { randomBytes } from \"crypto\";\nimport { type LixaConfig, type ProviderConfig } from \"./types\";\nimport { IProvider } from \"./providers\";\nimport { LocalStateCache } from \"./dao/state-cache\";\nimport { SessionDao, StateDao } from \"./dao/types\";\nimport crypto from \"crypto\";\nimport { LocalSessionCache } from \"./dao/session-cache\";\nimport { type Session, type SessionStrategy, DefaultSessionStrategy } from \"./models/session\";\n\n/**\n * Global registry of registered provider names\n */\ntype RegisteredProviders = string;\n\n/**\n * Type representing the keys of configured providers\n */\ntype ConfiguredProviderKey<T extends LixaConfig<any>> = keyof T['providers'];\n\n/**\n * A flexible, provider-agnostic OAuth 2.0 and OpenID Connect (OIDC) client library.\n *\n * @remarks\n * Lixa simplifies multi-provider authentication flows and supports extensible session management.\n *\n * @example\n * ```typescript\n * import { Lixa } from '@vunexa/lixa';\n * import { GoogleProvider } from '@vunexa/lixa/providers';\n * \n * // Register providers before using them\n * Lixa.registerProvider({ google: new GoogleProvider() });\n * \n * const config = Lixa.createConfig({\n * providers: {\n * google: {\n * clientId: 'your-client-id',\n * clientSecret: 'your-client-secret',\n * redirectUri: 'https://yourapp.com/auth/google/callback',\n * scopes: ['openid', 'email', 'profile']\n * }\n * }\n * });\n * \n * const lixa = new Lixa(config);\n * ```\n *\n * @public\n */\nclass Lixa<TConfig extends LixaConfig<any> = LixaConfig> {\n private static CONFIGURED_PROVIDERS: Map<string, IProvider> = new Map();\n private static LOCAL_STATE_CACHE = new LocalStateCache();\n private static LOCAL_SESSION_CACHE = new LocalSessionCache();\n private static DEFAULT_SESSION_STRATEGY = new DefaultSessionStrategy();\n private config: TConfig;\n private stateDao: StateDao;\n private sesionDao: SessionDao;\n private sessionStrategy: SessionStrategy;\n\n /**\n * Creates a new Lixa instance with the provided configuration.\n *\n * @param config - The configuration object containing provider settings and optional session strategy\n */\n constructor(config: TConfig) {\n // Validate that all providers in config are registered\n const configuredProviders = Object.keys(config.providers);\n const registeredProviders = Lixa.getRegisteredProviders();\n \n for (const provider of configuredProviders) {\n if (!registeredProviders.includes(provider.toLowerCase())) {\n throw new Error(`Provider '${provider}' is not registered. Please register it first using Lixa.registerProvider()`);\n }\n }\n \n this.config = config;\n this.stateDao = config.stateDao || Lixa.LOCAL_STATE_CACHE;\n this.sesionDao = config.sessionDao || Lixa.LOCAL_SESSION_CACHE;\n this.sessionStrategy = config.sessionStrategy || Lixa.DEFAULT_SESSION_STRATEGY;\n }\n\n /**\n * Checks if a provider is both registered and configured for this instance.\n * This is a type guard that narrows the provider type for use with getAuthUrl.\n *\n * @param provider - The provider name to check (case-insensitive)\n * @returns True if the provider is registered and configured, false otherwise\n *\n * @example\n * ```typescript\n * if (lixa.isProviderConfigured(provider)) {\n * // TypeScript now knows provider is a valid ConfiguredProviderKey\n * const authUrl = lixa.getAuthUrl(provider, state);\n * }\n * ```\n */\n public isProviderConfigured<T extends string>(provider: T): provider is T & ConfiguredProviderKey<TConfig> {\n const providerType = provider.toLowerCase();\n return Lixa.CONFIGURED_PROVIDERS.has(providerType) &&\n this.config.providers.hasOwnProperty(providerType);\n }\n\n /**\n * Registers custom OAuth providers for use with Lixa.\n *\n * @param providerMap - A map of provider names to IProvider implementations\n *\n * @example\n * ```typescript\n * class CustomProvider implements IProvider {\n * authorizationEndpoint = 'https://custom.com/oauth/authorize';\n * tokenEndpoint = 'https://custom.com/oauth/token';\n * userInfoEndpoint = 'https://custom.com/api/user';\n * }\n *\n * Lixa.registerProvider({ custom: new CustomProvider() });\n * ```\n */\n public static registerProvider<T extends Record<string, IProvider>>(providerMap: T): void {\n Object.entries(providerMap).forEach(([key, providerImpl]) => {\n Lixa.CONFIGURED_PROVIDERS.set(key.toLowerCase(), providerImpl);\n });\n }\n\n /**\n * Gets the list of registered provider names.\n * \n * @returns Array of registered provider names\n */\n public static getRegisteredProviders(): string[] {\n return Array.from(Lixa.CONFIGURED_PROVIDERS.keys());\n }\n\n /**\n * Creates a type-safe configuration that only allows registered providers.\n * \n * @param config - Configuration object with providers that must be registered\n * @returns The same configuration object, but with type safety for registered providers\n */\n public static createConfig<T extends Record<string, ProviderConfig>>(\n config: LixaConfig<keyof T & string> & { providers: T }\n ): LixaConfig<keyof T & string> {\n // Validate that all providers in config are registered\n const configuredProviders = Object.keys(config.providers);\n const registeredProviders = Lixa.getRegisteredProviders();\n \n for (const provider of configuredProviders) {\n if (!registeredProviders.includes(provider.toLowerCase())) {\n throw new Error(`Provider '${provider}' is not registered. Please register it first using Lixa.registerProvider()`);\n }\n }\n \n return config;\n }\n\n /**\n * Generates a cryptographically secure random state parameter for OAuth flows.\n *\n * @returns A 32-character hexadecimal string\n *\n * @remarks\n * The state parameter is used to prevent CSRF attacks in OAuth flows.\n */\n public static generateRandomState(): string {\n return randomBytes(16).toString(\"hex\");\n }\n\n /**\n * Generates a cryptographically secure code verifier for PKCE flows.\n *\n * @returns A 64-character hexadecimal string\n *\n * @remarks\n * The code verifier is used in PKCE (Proof Key for Code Exchange) to enhance security.\n */\n private static generateCodeVerifier(): string {\n return randomBytes(32).toString(\"hex\");\n }\n\n private static buildCodeChallenge(codeVerifier: string): string {\n const hash = crypto\n .createHash(\"sha256\")\n .update(codeVerifier)\n .digest(\"base64\");\n\n // Convert to base64url\n return hash.replace(/\\+/g, \"-\").replace(/\\//g, \"_\").replace(/=+$/, \"\");\n }\n\n /**\n * Generates the authorization URL for the specified provider.\n *\n * @param provider - The provider name (must be a configured provider key)\n * @param state - The state parameter for CSRF protection\n * @returns The complete authorization URL to redirect users to\n *\n * @throws Error when the provider is not configured\n *\n * @example\n * ```typescript\n * const state = Lixa.generateRandomState();\n * const authUrl = lixa.getAuthUrl('google', state);\n * res.redirect(authUrl);\n * ```\n */\n public getAuthUrl(provider: ConfiguredProviderKey<TConfig> | string, state: string): string {\n const providerType = String(provider).toLowerCase();\n const providerConfig = this.findProviderByType(providerType);\n const providerImpl = Lixa.CONFIGURED_PROVIDERS.get(providerType);\n\n if (!providerConfig || !providerImpl) {\n throw new Error(`Provider ${providerType} not configured`);\n }\n\n const codeVerifier = Lixa.generateCodeVerifier();\n const codeChallenge = Lixa.buildCodeChallenge(codeVerifier);\n\n // Cache the state paramaeter with TTL of 5 minutes (300 seconds)\n // We dont care about value. we are onl interested in key existence\n this.stateDao.saveState(\n state,\n {\n createdAt: Date.now(),\n provider: providerType,\n codeVerifier,\n },\n 300 // 5 minutes in seconds\n );\n\n const params = new URLSearchParams({\n client_id: providerConfig.clientId,\n redirect_uri: providerConfig.redirectUri,\n scope: providerConfig.scopes.join(\" \"),\n state,\n response_type: \"code\",\n code_challenge: codeChallenge,\n code_challenge_method: \"S256\",\n ...providerConfig.extraConfig,\n });\n\n return `${providerImpl.authorizationEndpoint}?${params.toString()}`;\n }\n\n /**\n * Handles the OAuth callback and creates a user session.\n *\n * @param provider - The provider name (must be a configured provider key)\n * @param code - The authorization code from the provider\n * @param state - The state parameter for validation\n * @returns A Promise that resolves to the session ID\n *\n * @throws Error when code or state is missing/invalid, or provider is not configured\n *\n * @example\n * ```typescript\n * const sessionId = await lixa.handleCallback({\n * provider: 'google',\n * code: req.query.code,\n * state: req.query.state\n * });\n * ```\n */\n public async handleCallback({\n provider,\n code,\n state,\n }: {\n provider: ConfiguredProviderKey<TConfig> | string;\n code: string;\n state?: string;\n }): Promise<string> {\n if (!code || code.trim() === \"\") {\n throw new Error(\"Invalid or missing code in callback\");\n }\n\n if (!state || state.trim() === \"\") {\n throw new Error(\"Invalid or missing state in callback\");\n }\n\n //Validate state here\n const cachedState = await this.stateDao.getState(state);\n if (!cachedState) {\n throw new Error(\"Invalid or expired state\");\n }\n // State is valid, remove it from cache to prevent reuse\n await this.stateDao.deleteState(state);\n\n //Get code verifier from cached state\n const codeVerifier = cachedState.codeVerifier;\n\n const providerType = String(provider).toLowerCase();\n const providerConfig = this.findProviderByType(providerType);\n const providerImpl = Lixa.CONFIGURED_PROVIDERS.get(providerType);\n\n if (!providerConfig || !providerImpl) {\n throw new Error(`Provider ${String(provider)} not configured`);\n }\n\n // Exchange code for tokens and fetch user info here.\n const tokens = await this.exchangeCodeForToken(\n code,\n providerConfig,\n providerImpl,\n codeVerifier\n );\n\n\n const session = await this.sessionStrategy.createSession(tokens);\n\n // Generate unique session ID\n const sessionId = randomBytes(32).toString(\"hex\");\n\n // Store session with 24 hour TTL (86400 seconds)\n await this.sesionDao.saveSession(sessionId, session, 86400);\n\n return sessionId;\n }\n\n public fetchSessionInfo(sessionId: string): Promise<Session | null> {\n return this.sesionDao.getSession(sessionId);\n }\n\n private async exchangeCodeForToken(\n code: string,\n providerConfig: ProviderConfig,\n providerImpl: IProvider,\n codeVerifier: string\n ): Promise<any> {\n // Build the request body\n const body: Record<string, string> = {\n client_id: providerConfig.clientId,\n client_secret: providerConfig.clientSecret,\n code,\n redirect_uri: providerConfig.redirectUri,\n grant_type: \"authorization_code\",\n };\n\n if (codeVerifier) {\n body.code_verifier = codeVerifier;\n }\n const params = new URLSearchParams(body);\n\n const response = await fetch(providerImpl.tokenEndpoint, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/x-www-form-urlencoded\",\n Accept: \"application/json\",\n },\n body: params.toString(),\n });\n\n if (!response.ok) {\n throw new Error(\n `Token exchange failed: ${response.status} ${response.statusText}`\n );\n }\n\n return response.json();\n }\n\n private findProviderByType(providerType: string): ProviderConfig | undefined {\n return this.config.providers[providerType];\n }\n}\n\nexport { Lixa };\n","import NodeCache from 'node-cache';\nimport { StateDao } from \"./types\";\n\nclass LocalStateCache implements StateDao {\n private cache: NodeCache;\n\n constructor(defaultTtlSeconds: number = 600) {\n this.cache = new NodeCache({ stdTTL: defaultTtlSeconds });\n }\n\n async saveState(state: string, data: any, expiresInSeconds: number): Promise<void> {\n this.cache.set(state, data, expiresInSeconds);\n }\n\n async getState(state: string): Promise<any | null> {\n return this.cache.get(state) || null;\n }\n\n async deleteState(state: string): Promise<void> {\n this.cache.del(state);\n }\n}\n\nexport { LocalStateCache };\n","import NodeCache from 'node-cache';\nimport { SessionDao } from \"./types\";\n\nclass LocalSessionCache implements SessionDao {\n private cache: NodeCache;\n\n constructor(defaultTtlSeconds: number = 600) {\n this.cache = new NodeCache({ stdTTL: defaultTtlSeconds });\n }\n\n async saveSession(state: string, data: any, expiresInSeconds: number): Promise<void> {\n this.cache.set(state, data, expiresInSeconds);\n }\n\n async getSession(state: string): Promise<any | null> {\n return this.cache.get(state) || null;\n }\n\n async deleteSession(state: string): Promise<void> {\n this.cache.del(state);\n }\n}\n\nexport { LocalSessionCache };\n","/**\n * Represents a user session after successful OAuth authentication.\n *\n * @public\n */\nexport interface Session {\n /** The session token (typically the access token) */\n token: string;\n /** Raw token data from the OAuth provider */\n raw: any;\n}\n\n/**\n * Strategy interface for custom session creation.\n *\n * @public\n */\nexport interface SessionStrategy {\n /**\n * Creates a session from OAuth token data.\n *\n * @param userInfo - The token data received from the OAuth provider\n * @returns A Promise that resolves to a Session object\n */\n createSession(userInfo: any): Promise<Session>;\n}\n\n/**\n * Default session strategy that works with any OAuth provider.\n * Extracts common token information and creates a standardized session.\n *\n * @public\n */\nexport class DefaultSessionStrategy implements SessionStrategy {\n /**\n * Creates a session from OAuth token data.\n * Handles common OAuth token formats and extracts the access token.\n *\n * @param tokenData - The token data received from the OAuth provider\n * @returns A Promise that resolves to a Session object\n */\n async createSession(tokenData: any): Promise<Session> {\n // Extract access token from various possible formats\n const accessToken = tokenData.access_token || \n tokenData.accessToken || \n tokenData.token ||\n tokenData;\n\n if (!accessToken || typeof accessToken !== 'string') {\n throw new Error('No valid access token found in OAuth response');\n }\n\n return {\n token: accessToken,\n raw: tokenData,\n };\n }\n}"],"mappings":"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","names":["NodeCache","import_crypto","import_node_cache","NodeCache","crypto"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/lixa.ts","../src/dao/state-cache.ts","../src/dao/session-cache.ts","../src/models/session.ts"],"sourcesContent":["/**\n * A flexible, provider-agnostic OAuth 2.0 and OpenID Connect (OIDC) client library for backend applications.\n * \n * @remarks\n * This package simplifies multi-provider authentication flows (e.g., Google, GitHub), supports extensible session management, and enables custom provider registration.\n * \n * @packageDocumentation\n */\n\nexport { Lixa } from \"./lixa\";\nexport {\n type ProviderConfig,\n type LixaConfig,\n type SafeLixaConfig,\n} from \"./types\";\nexport { type Session, type SessionStrategy, DefaultSessionStrategy } from \"./models/session\";\nexport { type IProvider } from \"./providers\";\n","import { randomBytes } from \"crypto\";\nimport { type LixaConfig, type ProviderConfig } from \"./types\";\nimport { IProvider } from \"./providers\";\nimport { LocalStateCache } from \"./dao/state-cache\";\nimport { SessionDao, StateDao } from \"./dao/types\";\nimport crypto from \"crypto\";\nimport { LocalSessionCache } from \"./dao/session-cache\";\nimport { type Session, type SessionStrategy, DefaultSessionStrategy } from \"./models/session\";\n\n/**\n * Global registry of registered provider names\n */\ntype RegisteredProviders = string;\n\n/**\n * Type representing the keys of configured providers\n */\ntype ConfiguredProviderKey<T extends LixaConfig<any>> = keyof T['providers'];\n\n/**\n * A flexible, provider-agnostic OAuth 2.0 and OpenID Connect (OIDC) client library.\n *\n * @remarks\n * Lixa simplifies multi-provider authentication flows and supports extensible session management.\n *\n * @example\n * ```typescript\n * import { Lixa } from '@vunexa/lixa';\n * import { GoogleProvider } from '@vunexa/lixa/providers';\n * \n * // Register providers before using them\n * Lixa.registerProvider({ google: new GoogleProvider() });\n * \n * const config = Lixa.createConfig({\n * providers: {\n * google: {\n * clientId: 'your-client-id',\n * clientSecret: 'your-client-secret',\n * redirectUri: 'https://yourapp.com/auth/google/callback',\n * scopes: ['openid', 'email', 'profile']\n * }\n * }\n * });\n * \n * const lixa = new Lixa(config);\n * ```\n *\n * @public\n */\nclass Lixa<TConfig extends LixaConfig<any> = LixaConfig> {\n private static CONFIGURED_PROVIDERS: Map<string, IProvider> = new Map();\n private static LOCAL_STATE_CACHE = new LocalStateCache();\n private static LOCAL_SESSION_CACHE = new LocalSessionCache();\n private static DEFAULT_SESSION_STRATEGY = new DefaultSessionStrategy();\n private config: TConfig;\n private stateDao: StateDao;\n private sesionDao: SessionDao;\n private sessionStrategy: SessionStrategy;\n private debug: boolean;\n\n /**\n * Creates a new Lixa instance with the provided configuration.\n *\n * @param config - The configuration object containing provider settings and optional session strategy\n */\n constructor(config: TConfig) {\n // Validate that all providers in config are registered\n const configuredProviders = Object.keys(config.providers);\n const registeredProviders = Lixa.getRegisteredProviders();\n \n for (const provider of configuredProviders) {\n if (!registeredProviders.includes(provider.toLowerCase())) {\n throw new Error(`Provider '${provider}' is not registered. Please register it first using Lixa.registerProvider()`);\n }\n }\n \n this.config = config;\n this.stateDao = config.stateDao || Lixa.LOCAL_STATE_CACHE;\n this.sesionDao = config.sessionDao || Lixa.LOCAL_SESSION_CACHE;\n this.sessionStrategy = config.sessionStrategy || Lixa.DEFAULT_SESSION_STRATEGY;\n this.debug = config.debug || false;\n }\n\n private log(...args: any[]) {\n if (this.debug) {\n console.log('[Lixa]', ...args);\n }\n }\n\n private logError(...args: any[]) {\n if (this.debug) {\n console.error('[Lixa]', ...args);\n }\n }\n\n /**\n * Checks if a provider is both registered and configured for this instance.\n * This is a type guard that narrows the provider type for use with getAuthUrl.\n *\n * @param provider - The provider name to check (case-insensitive)\n * @returns True if the provider is registered and configured, false otherwise\n *\n * @example\n * ```typescript\n * if (lixa.isProviderConfigured(provider)) {\n * // TypeScript now knows provider is a valid ConfiguredProviderKey\n * const authUrl = lixa.getAuthUrl(provider, state);\n * }\n * ```\n */\n public isProviderConfigured<T extends string>(provider: T): provider is T & ConfiguredProviderKey<TConfig> {\n const providerType = provider.toLowerCase();\n return Lixa.CONFIGURED_PROVIDERS.has(providerType) &&\n this.config.providers.hasOwnProperty(providerType);\n }\n\n /**\n * Registers custom OAuth providers for use with Lixa.\n *\n * @param providerMap - A map of provider names to IProvider implementations\n *\n * @example\n * ```typescript\n * class CustomProvider implements IProvider {\n * authorizationEndpoint = 'https://custom.com/oauth/authorize';\n * tokenEndpoint = 'https://custom.com/oauth/token';\n * userInfoEndpoint = 'https://custom.com/api/user';\n * }\n *\n * Lixa.registerProvider({ custom: new CustomProvider() });\n * ```\n */\n public static registerProvider<T extends Record<string, IProvider>>(providerMap: T): void {\n Object.entries(providerMap).forEach(([key, providerImpl]) => {\n Lixa.CONFIGURED_PROVIDERS.set(key.toLowerCase(), providerImpl);\n });\n }\n\n /**\n * Gets the list of registered provider names.\n * \n * @returns Array of registered provider names\n */\n public static getRegisteredProviders(): string[] {\n return Array.from(Lixa.CONFIGURED_PROVIDERS.keys());\n }\n\n /**\n * Creates a type-safe configuration that only allows registered providers.\n * \n * @param config - Configuration object with providers that must be registered\n * @returns The same configuration object, but with type safety for registered providers\n */\n public static createConfig<T extends Record<string, ProviderConfig>>(\n config: LixaConfig<keyof T & string> & { providers: T }\n ): LixaConfig<keyof T & string> {\n // Validate that all providers in config are registered\n const configuredProviders = Object.keys(config.providers);\n const registeredProviders = Lixa.getRegisteredProviders();\n \n for (const provider of configuredProviders) {\n if (!registeredProviders.includes(provider.toLowerCase())) {\n throw new Error(`Provider '${provider}' is not registered. Please register it first using Lixa.registerProvider()`);\n }\n }\n \n return config;\n }\n\n /**\n * Generates a cryptographically secure random state parameter for OAuth flows.\n *\n * @returns A 32-character hexadecimal string\n *\n * @remarks\n * The state parameter is used to prevent CSRF attacks in OAuth flows.\n */\n public static generateRandomState(): string {\n return randomBytes(16).toString(\"hex\");\n }\n\n /**\n * Generates a cryptographically secure code verifier for PKCE flows.\n *\n * @returns A 64-character hexadecimal string\n *\n * @remarks\n * The code verifier is used in PKCE (Proof Key for Code Exchange) to enhance security.\n */\n private static generateCodeVerifier(): string {\n return randomBytes(32).toString(\"hex\");\n }\n\n private static buildCodeChallenge(codeVerifier: string): string {\n const hash = crypto\n .createHash(\"sha256\")\n .update(codeVerifier)\n .digest(\"base64\");\n\n // Convert to base64url\n return hash.replace(/\\+/g, \"-\").replace(/\\//g, \"_\").replace(/=+$/, \"\");\n }\n\n /**\n * Generates the authorization URL for the specified provider.\n *\n * @param provider - The provider name (must be a configured provider key)\n * @param state - The state parameter for CSRF protection\n * @returns The complete authorization URL to redirect users to\n *\n * @throws Error when the provider is not configured\n *\n * @example\n * ```typescript\n * const state = Lixa.generateRandomState();\n * const authUrl = lixa.getAuthUrl('google', state);\n * res.redirect(authUrl);\n * ```\n */\n public getAuthUrl(provider: ConfiguredProviderKey<TConfig> | string, state: string): string {\n const providerType = String(provider).toLowerCase();\n const providerConfig = this.findProviderByType(providerType);\n const providerImpl = Lixa.CONFIGURED_PROVIDERS.get(providerType);\n\n if (!providerConfig || !providerImpl) {\n throw new Error(`Provider ${providerType} not configured`);\n }\n\n const codeVerifier = Lixa.generateCodeVerifier();\n const codeChallenge = Lixa.buildCodeChallenge(codeVerifier);\n\n // Cache the state paramaeter with TTL of 5 minutes (300 seconds)\n // We dont care about value. we are onl interested in key existence\n this.stateDao.saveState(\n state,\n {\n createdAt: Date.now(),\n provider: providerType,\n codeVerifier,\n },\n 300 // 5 minutes in seconds\n );\n\n const params = new URLSearchParams({\n client_id: providerConfig.clientId,\n redirect_uri: providerConfig.redirectUri,\n scope: providerConfig.scopes.join(\" \"),\n state,\n response_type: \"code\",\n code_challenge: codeChallenge,\n code_challenge_method: \"S256\",\n ...providerConfig.extraConfig,\n });\n\n return `${providerImpl.authorizationEndpoint}?${params.toString()}`;\n }\n\n /**\n * Handles the OAuth callback and creates a user session.\n *\n * @param provider - The provider name (must be a configured provider key)\n * @param code - The authorization code from the provider\n * @param state - The state parameter for validation\n * @returns A Promise that resolves to the session ID\n *\n * @throws Error when code or state is missing/invalid, or provider is not configured\n *\n * @example\n * ```typescript\n * const sessionId = await lixa.handleCallback({\n * provider: 'google',\n * code: req.query.code,\n * state: req.query.state\n * });\n * ```\n */\n public async handleCallback({\n provider,\n code,\n state,\n }: {\n provider: ConfiguredProviderKey<TConfig> | string;\n code: string;\n state?: string;\n }): Promise<string> {\n if (!code || code.trim() === \"\") {\n throw new Error(\"Invalid or missing code in callback\");\n }\n\n if (!state || state.trim() === \"\") {\n throw new Error(\"Invalid or missing state in callback\");\n }\n\n //Validate state here\n const cachedState = await this.stateDao.getState(state);\n if (!cachedState) {\n throw new Error(\"Invalid or expired state\");\n }\n // State is valid, remove it from cache to prevent reuse\n await this.stateDao.deleteState(state);\n\n //Get code verifier from cached state\n const codeVerifier = cachedState.codeVerifier;\n\n const providerType = String(provider).toLowerCase();\n const providerConfig = this.findProviderByType(providerType);\n const providerImpl = Lixa.CONFIGURED_PROVIDERS.get(providerType);\n\n if (!providerConfig || !providerImpl) {\n throw new Error(`Provider ${String(provider)} not configured`);\n }\n\n // Exchange code for tokens and fetch user info here.\n const tokens = await this.exchangeCodeForToken(\n code,\n providerConfig,\n providerImpl,\n codeVerifier\n );\n\n\n const session = await this.sessionStrategy.createSession(tokens);\n\n // Generate unique session ID\n const sessionId = randomBytes(32).toString(\"hex\");\n\n // Store session with 24 hour TTL (86400 seconds)\n await this.sesionDao.saveSession(sessionId, session, 86400);\n\n return sessionId;\n }\n\n public fetchSessionInfo(sessionId: string): Promise<Session | null> {\n return this.sesionDao.getSession(sessionId);\n }\n\n private async exchangeCodeForToken(\n code: string,\n providerConfig: ProviderConfig,\n providerImpl: IProvider,\n codeVerifier: string\n ): Promise<any> {\n // Build the request body\n const body: Record<string, string> = {\n client_id: providerConfig.clientId,\n client_secret: providerConfig.clientSecret,\n code,\n redirect_uri: providerConfig.redirectUri,\n grant_type: \"authorization_code\",\n };\n\n if (codeVerifier) {\n body.code_verifier = codeVerifier;\n }\n const params = new URLSearchParams(body);\n\n this.log('Token Exchange - Request body:', params.toString());\n this.log('Token Exchange - Token endpoint:', providerImpl.tokenEndpoint);\n \n const response = await fetch(providerImpl.tokenEndpoint, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/x-www-form-urlencoded\",\n Accept: \"application/json\",\n },\n body: params.toString(),\n });\n\n if (!response.ok) {\n const errorBody = await response.text();\n this.logError('Token Exchange - Error response:', errorBody);\n throw new Error(\n `Token exchange failed: ${response.status} ${response.statusText} - ${errorBody}`\n );\n }\n\n return response.json();\n }\n\n private findProviderByType(providerType: string): ProviderConfig | undefined {\n return this.config.providers[providerType];\n }\n}\n\nexport { Lixa };\n","import NodeCache from 'node-cache';\nimport { StateDao } from \"./types\";\n\nclass LocalStateCache implements StateDao {\n private cache: NodeCache;\n\n constructor(defaultTtlSeconds: number = 600) {\n this.cache = new NodeCache({ stdTTL: defaultTtlSeconds });\n }\n\n async saveState(state: string, data: any, expiresInSeconds: number): Promise<void> {\n this.cache.set(state, data, expiresInSeconds);\n }\n\n async getState(state: string): Promise<any | null> {\n return this.cache.get(state) || null;\n }\n\n async deleteState(state: string): Promise<void> {\n this.cache.del(state);\n }\n}\n\nexport { LocalStateCache };\n","import NodeCache from 'node-cache';\nimport { SessionDao } from \"./types\";\n\nclass LocalSessionCache implements SessionDao {\n private cache: NodeCache;\n\n constructor(defaultTtlSeconds: number = 600) {\n this.cache = new NodeCache({ stdTTL: defaultTtlSeconds });\n }\n\n async saveSession(state: string, data: any, expiresInSeconds: number): Promise<void> {\n this.cache.set(state, data, expiresInSeconds);\n }\n\n async getSession(state: string): Promise<any | null> {\n return this.cache.get(state) || null;\n }\n\n async deleteSession(state: string): Promise<void> {\n this.cache.del(state);\n }\n}\n\nexport { LocalSessionCache };\n","/**\n * Represents a user session after successful OAuth authentication.\n *\n * @public\n */\nexport interface Session {\n /** The session token (typically the access token) */\n token: string;\n /** Raw token data from the OAuth provider */\n raw: any;\n}\n\n/**\n * Strategy interface for custom session creation.\n *\n * @public\n */\nexport interface SessionStrategy {\n /**\n * Creates a session from OAuth token data.\n *\n * @param userInfo - The token data received from the OAuth provider\n * @returns A Promise that resolves to a Session object\n */\n createSession(userInfo: any): Promise<Session>;\n}\n\n/**\n * Default session strategy that works with any OAuth provider.\n * Extracts common token information and creates a standardized session.\n *\n * @public\n */\nexport class DefaultSessionStrategy implements SessionStrategy {\n /**\n * Creates a session from OAuth token data.\n * Handles common OAuth token formats and extracts the access token.\n *\n * @param tokenData - The token data received from the OAuth provider\n * @returns A Promise that resolves to a Session object\n */\n async createSession(tokenData: any): Promise<Session> {\n // Extract access token from various possible formats\n const accessToken = tokenData.access_token || \n tokenData.accessToken || \n tokenData.token ||\n tokenData;\n\n if (!accessToken || typeof accessToken !== 'string') {\n throw new Error('No valid access token found in OAuth response');\n }\n\n return {\n token: accessToken,\n raw: tokenData,\n };\n }\n}"],"mappings":"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","names":["NodeCache","import_crypto","import_node_cache","NodeCache","crypto"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -85,6 +85,8 @@ interface LixaConfig<TRegisteredProviders extends string = string> {
|
|
|
85
85
|
stateDao?: StateDao;
|
|
86
86
|
/** Optiona: custom session storage implementation */
|
|
87
87
|
sessionDao?: SessionDao;
|
|
88
|
+
/** Enable debug logging */
|
|
89
|
+
debug?: boolean;
|
|
88
90
|
}
|
|
89
91
|
/**
|
|
90
92
|
* Helper type to create a configuration with only registered providers.
|
|
@@ -139,12 +141,15 @@ declare class Lixa<TConfig extends LixaConfig<any> = LixaConfig> {
|
|
|
139
141
|
private stateDao;
|
|
140
142
|
private sesionDao;
|
|
141
143
|
private sessionStrategy;
|
|
144
|
+
private debug;
|
|
142
145
|
/**
|
|
143
146
|
* Creates a new Lixa instance with the provided configuration.
|
|
144
147
|
*
|
|
145
148
|
* @param config - The configuration object containing provider settings and optional session strategy
|
|
146
149
|
*/
|
|
147
150
|
constructor(config: TConfig);
|
|
151
|
+
private log;
|
|
152
|
+
private logError;
|
|
148
153
|
/**
|
|
149
154
|
* Checks if a provider is both registered and configured for this instance.
|
|
150
155
|
* This is a type guard that narrows the provider type for use with getAuthUrl.
|
package/dist/index.js
CHANGED
|
@@ -71,6 +71,7 @@ var Lixa = class _Lixa {
|
|
|
71
71
|
stateDao;
|
|
72
72
|
sesionDao;
|
|
73
73
|
sessionStrategy;
|
|
74
|
+
debug;
|
|
74
75
|
/**
|
|
75
76
|
* Creates a new Lixa instance with the provided configuration.
|
|
76
77
|
*
|
|
@@ -88,6 +89,17 @@ var Lixa = class _Lixa {
|
|
|
88
89
|
this.stateDao = config.stateDao || _Lixa.LOCAL_STATE_CACHE;
|
|
89
90
|
this.sesionDao = config.sessionDao || _Lixa.LOCAL_SESSION_CACHE;
|
|
90
91
|
this.sessionStrategy = config.sessionStrategy || _Lixa.DEFAULT_SESSION_STRATEGY;
|
|
92
|
+
this.debug = config.debug || false;
|
|
93
|
+
}
|
|
94
|
+
log(...args) {
|
|
95
|
+
if (this.debug) {
|
|
96
|
+
console.log("[Lixa]", ...args);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
logError(...args) {
|
|
100
|
+
if (this.debug) {
|
|
101
|
+
console.error("[Lixa]", ...args);
|
|
102
|
+
}
|
|
91
103
|
}
|
|
92
104
|
/**
|
|
93
105
|
* Checks if a provider is both registered and configured for this instance.
|
|
@@ -294,6 +306,8 @@ var Lixa = class _Lixa {
|
|
|
294
306
|
body.code_verifier = codeVerifier;
|
|
295
307
|
}
|
|
296
308
|
const params = new URLSearchParams(body);
|
|
309
|
+
this.log("Token Exchange - Request body:", params.toString());
|
|
310
|
+
this.log("Token Exchange - Token endpoint:", providerImpl.tokenEndpoint);
|
|
297
311
|
const response = await fetch(providerImpl.tokenEndpoint, {
|
|
298
312
|
method: "POST",
|
|
299
313
|
headers: {
|
|
@@ -303,8 +317,10 @@ var Lixa = class _Lixa {
|
|
|
303
317
|
body: params.toString()
|
|
304
318
|
});
|
|
305
319
|
if (!response.ok) {
|
|
320
|
+
const errorBody = await response.text();
|
|
321
|
+
this.logError("Token Exchange - Error response:", errorBody);
|
|
306
322
|
throw new Error(
|
|
307
|
-
`Token exchange failed: ${response.status} ${response.statusText}`
|
|
323
|
+
`Token exchange failed: ${response.status} ${response.statusText} - ${errorBody}`
|
|
308
324
|
);
|
|
309
325
|
}
|
|
310
326
|
return response.json();
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lixa.ts","../src/dao/state-cache.ts","../src/dao/session-cache.ts","../src/models/session.ts"],"sourcesContent":["import { randomBytes } from \"crypto\";\nimport { type LixaConfig, type ProviderConfig } from \"./types\";\nimport { IProvider } from \"./providers\";\nimport { LocalStateCache } from \"./dao/state-cache\";\nimport { SessionDao, StateDao } from \"./dao/types\";\nimport crypto from \"crypto\";\nimport { LocalSessionCache } from \"./dao/session-cache\";\nimport { type Session, type SessionStrategy, DefaultSessionStrategy } from \"./models/session\";\n\n/**\n * Global registry of registered provider names\n */\ntype RegisteredProviders = string;\n\n/**\n * Type representing the keys of configured providers\n */\ntype ConfiguredProviderKey<T extends LixaConfig<any>> = keyof T['providers'];\n\n/**\n * A flexible, provider-agnostic OAuth 2.0 and OpenID Connect (OIDC) client library.\n *\n * @remarks\n * Lixa simplifies multi-provider authentication flows and supports extensible session management.\n *\n * @example\n * ```typescript\n * import { Lixa } from '@vunexa/lixa';\n * import { GoogleProvider } from '@vunexa/lixa/providers';\n * \n * // Register providers before using them\n * Lixa.registerProvider({ google: new GoogleProvider() });\n * \n * const config = Lixa.createConfig({\n * providers: {\n * google: {\n * clientId: 'your-client-id',\n * clientSecret: 'your-client-secret',\n * redirectUri: 'https://yourapp.com/auth/google/callback',\n * scopes: ['openid', 'email', 'profile']\n * }\n * }\n * });\n * \n * const lixa = new Lixa(config);\n * ```\n *\n * @public\n */\nclass Lixa<TConfig extends LixaConfig<any> = LixaConfig> {\n private static CONFIGURED_PROVIDERS: Map<string, IProvider> = new Map();\n private static LOCAL_STATE_CACHE = new LocalStateCache();\n private static LOCAL_SESSION_CACHE = new LocalSessionCache();\n private static DEFAULT_SESSION_STRATEGY = new DefaultSessionStrategy();\n private config: TConfig;\n private stateDao: StateDao;\n private sesionDao: SessionDao;\n private sessionStrategy: SessionStrategy;\n\n /**\n * Creates a new Lixa instance with the provided configuration.\n *\n * @param config - The configuration object containing provider settings and optional session strategy\n */\n constructor(config: TConfig) {\n // Validate that all providers in config are registered\n const configuredProviders = Object.keys(config.providers);\n const registeredProviders = Lixa.getRegisteredProviders();\n \n for (const provider of configuredProviders) {\n if (!registeredProviders.includes(provider.toLowerCase())) {\n throw new Error(`Provider '${provider}' is not registered. Please register it first using Lixa.registerProvider()`);\n }\n }\n \n this.config = config;\n this.stateDao = config.stateDao || Lixa.LOCAL_STATE_CACHE;\n this.sesionDao = config.sessionDao || Lixa.LOCAL_SESSION_CACHE;\n this.sessionStrategy = config.sessionStrategy || Lixa.DEFAULT_SESSION_STRATEGY;\n }\n\n /**\n * Checks if a provider is both registered and configured for this instance.\n * This is a type guard that narrows the provider type for use with getAuthUrl.\n *\n * @param provider - The provider name to check (case-insensitive)\n * @returns True if the provider is registered and configured, false otherwise\n *\n * @example\n * ```typescript\n * if (lixa.isProviderConfigured(provider)) {\n * // TypeScript now knows provider is a valid ConfiguredProviderKey\n * const authUrl = lixa.getAuthUrl(provider, state);\n * }\n * ```\n */\n public isProviderConfigured<T extends string>(provider: T): provider is T & ConfiguredProviderKey<TConfig> {\n const providerType = provider.toLowerCase();\n return Lixa.CONFIGURED_PROVIDERS.has(providerType) &&\n this.config.providers.hasOwnProperty(providerType);\n }\n\n /**\n * Registers custom OAuth providers for use with Lixa.\n *\n * @param providerMap - A map of provider names to IProvider implementations\n *\n * @example\n * ```typescript\n * class CustomProvider implements IProvider {\n * authorizationEndpoint = 'https://custom.com/oauth/authorize';\n * tokenEndpoint = 'https://custom.com/oauth/token';\n * userInfoEndpoint = 'https://custom.com/api/user';\n * }\n *\n * Lixa.registerProvider({ custom: new CustomProvider() });\n * ```\n */\n public static registerProvider<T extends Record<string, IProvider>>(providerMap: T): void {\n Object.entries(providerMap).forEach(([key, providerImpl]) => {\n Lixa.CONFIGURED_PROVIDERS.set(key.toLowerCase(), providerImpl);\n });\n }\n\n /**\n * Gets the list of registered provider names.\n * \n * @returns Array of registered provider names\n */\n public static getRegisteredProviders(): string[] {\n return Array.from(Lixa.CONFIGURED_PROVIDERS.keys());\n }\n\n /**\n * Creates a type-safe configuration that only allows registered providers.\n * \n * @param config - Configuration object with providers that must be registered\n * @returns The same configuration object, but with type safety for registered providers\n */\n public static createConfig<T extends Record<string, ProviderConfig>>(\n config: LixaConfig<keyof T & string> & { providers: T }\n ): LixaConfig<keyof T & string> {\n // Validate that all providers in config are registered\n const configuredProviders = Object.keys(config.providers);\n const registeredProviders = Lixa.getRegisteredProviders();\n \n for (const provider of configuredProviders) {\n if (!registeredProviders.includes(provider.toLowerCase())) {\n throw new Error(`Provider '${provider}' is not registered. Please register it first using Lixa.registerProvider()`);\n }\n }\n \n return config;\n }\n\n /**\n * Generates a cryptographically secure random state parameter for OAuth flows.\n *\n * @returns A 32-character hexadecimal string\n *\n * @remarks\n * The state parameter is used to prevent CSRF attacks in OAuth flows.\n */\n public static generateRandomState(): string {\n return randomBytes(16).toString(\"hex\");\n }\n\n /**\n * Generates a cryptographically secure code verifier for PKCE flows.\n *\n * @returns A 64-character hexadecimal string\n *\n * @remarks\n * The code verifier is used in PKCE (Proof Key for Code Exchange) to enhance security.\n */\n private static generateCodeVerifier(): string {\n return randomBytes(32).toString(\"hex\");\n }\n\n private static buildCodeChallenge(codeVerifier: string): string {\n const hash = crypto\n .createHash(\"sha256\")\n .update(codeVerifier)\n .digest(\"base64\");\n\n // Convert to base64url\n return hash.replace(/\\+/g, \"-\").replace(/\\//g, \"_\").replace(/=+$/, \"\");\n }\n\n /**\n * Generates the authorization URL for the specified provider.\n *\n * @param provider - The provider name (must be a configured provider key)\n * @param state - The state parameter for CSRF protection\n * @returns The complete authorization URL to redirect users to\n *\n * @throws Error when the provider is not configured\n *\n * @example\n * ```typescript\n * const state = Lixa.generateRandomState();\n * const authUrl = lixa.getAuthUrl('google', state);\n * res.redirect(authUrl);\n * ```\n */\n public getAuthUrl(provider: ConfiguredProviderKey<TConfig> | string, state: string): string {\n const providerType = String(provider).toLowerCase();\n const providerConfig = this.findProviderByType(providerType);\n const providerImpl = Lixa.CONFIGURED_PROVIDERS.get(providerType);\n\n if (!providerConfig || !providerImpl) {\n throw new Error(`Provider ${providerType} not configured`);\n }\n\n const codeVerifier = Lixa.generateCodeVerifier();\n const codeChallenge = Lixa.buildCodeChallenge(codeVerifier);\n\n // Cache the state paramaeter with TTL of 5 minutes (300 seconds)\n // We dont care about value. we are onl interested in key existence\n this.stateDao.saveState(\n state,\n {\n createdAt: Date.now(),\n provider: providerType,\n codeVerifier,\n },\n 300 // 5 minutes in seconds\n );\n\n const params = new URLSearchParams({\n client_id: providerConfig.clientId,\n redirect_uri: providerConfig.redirectUri,\n scope: providerConfig.scopes.join(\" \"),\n state,\n response_type: \"code\",\n code_challenge: codeChallenge,\n code_challenge_method: \"S256\",\n ...providerConfig.extraConfig,\n });\n\n return `${providerImpl.authorizationEndpoint}?${params.toString()}`;\n }\n\n /**\n * Handles the OAuth callback and creates a user session.\n *\n * @param provider - The provider name (must be a configured provider key)\n * @param code - The authorization code from the provider\n * @param state - The state parameter for validation\n * @returns A Promise that resolves to the session ID\n *\n * @throws Error when code or state is missing/invalid, or provider is not configured\n *\n * @example\n * ```typescript\n * const sessionId = await lixa.handleCallback({\n * provider: 'google',\n * code: req.query.code,\n * state: req.query.state\n * });\n * ```\n */\n public async handleCallback({\n provider,\n code,\n state,\n }: {\n provider: ConfiguredProviderKey<TConfig> | string;\n code: string;\n state?: string;\n }): Promise<string> {\n if (!code || code.trim() === \"\") {\n throw new Error(\"Invalid or missing code in callback\");\n }\n\n if (!state || state.trim() === \"\") {\n throw new Error(\"Invalid or missing state in callback\");\n }\n\n //Validate state here\n const cachedState = await this.stateDao.getState(state);\n if (!cachedState) {\n throw new Error(\"Invalid or expired state\");\n }\n // State is valid, remove it from cache to prevent reuse\n await this.stateDao.deleteState(state);\n\n //Get code verifier from cached state\n const codeVerifier = cachedState.codeVerifier;\n\n const providerType = String(provider).toLowerCase();\n const providerConfig = this.findProviderByType(providerType);\n const providerImpl = Lixa.CONFIGURED_PROVIDERS.get(providerType);\n\n if (!providerConfig || !providerImpl) {\n throw new Error(`Provider ${String(provider)} not configured`);\n }\n\n // Exchange code for tokens and fetch user info here.\n const tokens = await this.exchangeCodeForToken(\n code,\n providerConfig,\n providerImpl,\n codeVerifier\n );\n\n\n const session = await this.sessionStrategy.createSession(tokens);\n\n // Generate unique session ID\n const sessionId = randomBytes(32).toString(\"hex\");\n\n // Store session with 24 hour TTL (86400 seconds)\n await this.sesionDao.saveSession(sessionId, session, 86400);\n\n return sessionId;\n }\n\n public fetchSessionInfo(sessionId: string): Promise<Session | null> {\n return this.sesionDao.getSession(sessionId);\n }\n\n private async exchangeCodeForToken(\n code: string,\n providerConfig: ProviderConfig,\n providerImpl: IProvider,\n codeVerifier: string\n ): Promise<any> {\n // Build the request body\n const body: Record<string, string> = {\n client_id: providerConfig.clientId,\n client_secret: providerConfig.clientSecret,\n code,\n redirect_uri: providerConfig.redirectUri,\n grant_type: \"authorization_code\",\n };\n\n if (codeVerifier) {\n body.code_verifier = codeVerifier;\n }\n const params = new URLSearchParams(body);\n\n const response = await fetch(providerImpl.tokenEndpoint, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/x-www-form-urlencoded\",\n Accept: \"application/json\",\n },\n body: params.toString(),\n });\n\n if (!response.ok) {\n throw new Error(\n `Token exchange failed: ${response.status} ${response.statusText}`\n );\n }\n\n return response.json();\n }\n\n private findProviderByType(providerType: string): ProviderConfig | undefined {\n return this.config.providers[providerType];\n }\n}\n\nexport { Lixa };\n","import NodeCache from 'node-cache';\nimport { StateDao } from \"./types\";\n\nclass LocalStateCache implements StateDao {\n private cache: NodeCache;\n\n constructor(defaultTtlSeconds: number = 600) {\n this.cache = new NodeCache({ stdTTL: defaultTtlSeconds });\n }\n\n async saveState(state: string, data: any, expiresInSeconds: number): Promise<void> {\n this.cache.set(state, data, expiresInSeconds);\n }\n\n async getState(state: string): Promise<any | null> {\n return this.cache.get(state) || null;\n }\n\n async deleteState(state: string): Promise<void> {\n this.cache.del(state);\n }\n}\n\nexport { LocalStateCache };\n","import NodeCache from 'node-cache';\nimport { SessionDao } from \"./types\";\n\nclass LocalSessionCache implements SessionDao {\n private cache: NodeCache;\n\n constructor(defaultTtlSeconds: number = 600) {\n this.cache = new NodeCache({ stdTTL: defaultTtlSeconds });\n }\n\n async saveSession(state: string, data: any, expiresInSeconds: number): Promise<void> {\n this.cache.set(state, data, expiresInSeconds);\n }\n\n async getSession(state: string): Promise<any | null> {\n return this.cache.get(state) || null;\n }\n\n async deleteSession(state: string): Promise<void> {\n this.cache.del(state);\n }\n}\n\nexport { LocalSessionCache };\n","/**\n * Represents a user session after successful OAuth authentication.\n *\n * @public\n */\nexport interface Session {\n /** The session token (typically the access token) */\n token: string;\n /** Raw token data from the OAuth provider */\n raw: any;\n}\n\n/**\n * Strategy interface for custom session creation.\n *\n * @public\n */\nexport interface SessionStrategy {\n /**\n * Creates a session from OAuth token data.\n *\n * @param userInfo - The token data received from the OAuth provider\n * @returns A Promise that resolves to a Session object\n */\n createSession(userInfo: any): Promise<Session>;\n}\n\n/**\n * Default session strategy that works with any OAuth provider.\n * Extracts common token information and creates a standardized session.\n *\n * @public\n */\nexport class DefaultSessionStrategy implements SessionStrategy {\n /**\n * Creates a session from OAuth token data.\n * Handles common OAuth token formats and extracts the access token.\n *\n * @param tokenData - The token data received from the OAuth provider\n * @returns A Promise that resolves to a Session object\n */\n async createSession(tokenData: any): Promise<Session> {\n // Extract access token from various possible formats\n const accessToken = tokenData.access_token || \n tokenData.accessToken || \n tokenData.token ||\n tokenData;\n\n if (!accessToken || typeof accessToken !== 'string') {\n throw new Error('No valid access token found in OAuth response');\n }\n\n return {\n token: accessToken,\n raw: tokenData,\n };\n }\n}"],"mappings":"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","names":["NodeCache"]}
|
|
1
|
+
{"version":3,"sources":["../src/lixa.ts","../src/dao/state-cache.ts","../src/dao/session-cache.ts","../src/models/session.ts"],"sourcesContent":["import { randomBytes } from \"crypto\";\nimport { type LixaConfig, type ProviderConfig } from \"./types\";\nimport { IProvider } from \"./providers\";\nimport { LocalStateCache } from \"./dao/state-cache\";\nimport { SessionDao, StateDao } from \"./dao/types\";\nimport crypto from \"crypto\";\nimport { LocalSessionCache } from \"./dao/session-cache\";\nimport { type Session, type SessionStrategy, DefaultSessionStrategy } from \"./models/session\";\n\n/**\n * Global registry of registered provider names\n */\ntype RegisteredProviders = string;\n\n/**\n * Type representing the keys of configured providers\n */\ntype ConfiguredProviderKey<T extends LixaConfig<any>> = keyof T['providers'];\n\n/**\n * A flexible, provider-agnostic OAuth 2.0 and OpenID Connect (OIDC) client library.\n *\n * @remarks\n * Lixa simplifies multi-provider authentication flows and supports extensible session management.\n *\n * @example\n * ```typescript\n * import { Lixa } from '@vunexa/lixa';\n * import { GoogleProvider } from '@vunexa/lixa/providers';\n * \n * // Register providers before using them\n * Lixa.registerProvider({ google: new GoogleProvider() });\n * \n * const config = Lixa.createConfig({\n * providers: {\n * google: {\n * clientId: 'your-client-id',\n * clientSecret: 'your-client-secret',\n * redirectUri: 'https://yourapp.com/auth/google/callback',\n * scopes: ['openid', 'email', 'profile']\n * }\n * }\n * });\n * \n * const lixa = new Lixa(config);\n * ```\n *\n * @public\n */\nclass Lixa<TConfig extends LixaConfig<any> = LixaConfig> {\n private static CONFIGURED_PROVIDERS: Map<string, IProvider> = new Map();\n private static LOCAL_STATE_CACHE = new LocalStateCache();\n private static LOCAL_SESSION_CACHE = new LocalSessionCache();\n private static DEFAULT_SESSION_STRATEGY = new DefaultSessionStrategy();\n private config: TConfig;\n private stateDao: StateDao;\n private sesionDao: SessionDao;\n private sessionStrategy: SessionStrategy;\n private debug: boolean;\n\n /**\n * Creates a new Lixa instance with the provided configuration.\n *\n * @param config - The configuration object containing provider settings and optional session strategy\n */\n constructor(config: TConfig) {\n // Validate that all providers in config are registered\n const configuredProviders = Object.keys(config.providers);\n const registeredProviders = Lixa.getRegisteredProviders();\n \n for (const provider of configuredProviders) {\n if (!registeredProviders.includes(provider.toLowerCase())) {\n throw new Error(`Provider '${provider}' is not registered. Please register it first using Lixa.registerProvider()`);\n }\n }\n \n this.config = config;\n this.stateDao = config.stateDao || Lixa.LOCAL_STATE_CACHE;\n this.sesionDao = config.sessionDao || Lixa.LOCAL_SESSION_CACHE;\n this.sessionStrategy = config.sessionStrategy || Lixa.DEFAULT_SESSION_STRATEGY;\n this.debug = config.debug || false;\n }\n\n private log(...args: any[]) {\n if (this.debug) {\n console.log('[Lixa]', ...args);\n }\n }\n\n private logError(...args: any[]) {\n if (this.debug) {\n console.error('[Lixa]', ...args);\n }\n }\n\n /**\n * Checks if a provider is both registered and configured for this instance.\n * This is a type guard that narrows the provider type for use with getAuthUrl.\n *\n * @param provider - The provider name to check (case-insensitive)\n * @returns True if the provider is registered and configured, false otherwise\n *\n * @example\n * ```typescript\n * if (lixa.isProviderConfigured(provider)) {\n * // TypeScript now knows provider is a valid ConfiguredProviderKey\n * const authUrl = lixa.getAuthUrl(provider, state);\n * }\n * ```\n */\n public isProviderConfigured<T extends string>(provider: T): provider is T & ConfiguredProviderKey<TConfig> {\n const providerType = provider.toLowerCase();\n return Lixa.CONFIGURED_PROVIDERS.has(providerType) &&\n this.config.providers.hasOwnProperty(providerType);\n }\n\n /**\n * Registers custom OAuth providers for use with Lixa.\n *\n * @param providerMap - A map of provider names to IProvider implementations\n *\n * @example\n * ```typescript\n * class CustomProvider implements IProvider {\n * authorizationEndpoint = 'https://custom.com/oauth/authorize';\n * tokenEndpoint = 'https://custom.com/oauth/token';\n * userInfoEndpoint = 'https://custom.com/api/user';\n * }\n *\n * Lixa.registerProvider({ custom: new CustomProvider() });\n * ```\n */\n public static registerProvider<T extends Record<string, IProvider>>(providerMap: T): void {\n Object.entries(providerMap).forEach(([key, providerImpl]) => {\n Lixa.CONFIGURED_PROVIDERS.set(key.toLowerCase(), providerImpl);\n });\n }\n\n /**\n * Gets the list of registered provider names.\n * \n * @returns Array of registered provider names\n */\n public static getRegisteredProviders(): string[] {\n return Array.from(Lixa.CONFIGURED_PROVIDERS.keys());\n }\n\n /**\n * Creates a type-safe configuration that only allows registered providers.\n * \n * @param config - Configuration object with providers that must be registered\n * @returns The same configuration object, but with type safety for registered providers\n */\n public static createConfig<T extends Record<string, ProviderConfig>>(\n config: LixaConfig<keyof T & string> & { providers: T }\n ): LixaConfig<keyof T & string> {\n // Validate that all providers in config are registered\n const configuredProviders = Object.keys(config.providers);\n const registeredProviders = Lixa.getRegisteredProviders();\n \n for (const provider of configuredProviders) {\n if (!registeredProviders.includes(provider.toLowerCase())) {\n throw new Error(`Provider '${provider}' is not registered. Please register it first using Lixa.registerProvider()`);\n }\n }\n \n return config;\n }\n\n /**\n * Generates a cryptographically secure random state parameter for OAuth flows.\n *\n * @returns A 32-character hexadecimal string\n *\n * @remarks\n * The state parameter is used to prevent CSRF attacks in OAuth flows.\n */\n public static generateRandomState(): string {\n return randomBytes(16).toString(\"hex\");\n }\n\n /**\n * Generates a cryptographically secure code verifier for PKCE flows.\n *\n * @returns A 64-character hexadecimal string\n *\n * @remarks\n * The code verifier is used in PKCE (Proof Key for Code Exchange) to enhance security.\n */\n private static generateCodeVerifier(): string {\n return randomBytes(32).toString(\"hex\");\n }\n\n private static buildCodeChallenge(codeVerifier: string): string {\n const hash = crypto\n .createHash(\"sha256\")\n .update(codeVerifier)\n .digest(\"base64\");\n\n // Convert to base64url\n return hash.replace(/\\+/g, \"-\").replace(/\\//g, \"_\").replace(/=+$/, \"\");\n }\n\n /**\n * Generates the authorization URL for the specified provider.\n *\n * @param provider - The provider name (must be a configured provider key)\n * @param state - The state parameter for CSRF protection\n * @returns The complete authorization URL to redirect users to\n *\n * @throws Error when the provider is not configured\n *\n * @example\n * ```typescript\n * const state = Lixa.generateRandomState();\n * const authUrl = lixa.getAuthUrl('google', state);\n * res.redirect(authUrl);\n * ```\n */\n public getAuthUrl(provider: ConfiguredProviderKey<TConfig> | string, state: string): string {\n const providerType = String(provider).toLowerCase();\n const providerConfig = this.findProviderByType(providerType);\n const providerImpl = Lixa.CONFIGURED_PROVIDERS.get(providerType);\n\n if (!providerConfig || !providerImpl) {\n throw new Error(`Provider ${providerType} not configured`);\n }\n\n const codeVerifier = Lixa.generateCodeVerifier();\n const codeChallenge = Lixa.buildCodeChallenge(codeVerifier);\n\n // Cache the state paramaeter with TTL of 5 minutes (300 seconds)\n // We dont care about value. we are onl interested in key existence\n this.stateDao.saveState(\n state,\n {\n createdAt: Date.now(),\n provider: providerType,\n codeVerifier,\n },\n 300 // 5 minutes in seconds\n );\n\n const params = new URLSearchParams({\n client_id: providerConfig.clientId,\n redirect_uri: providerConfig.redirectUri,\n scope: providerConfig.scopes.join(\" \"),\n state,\n response_type: \"code\",\n code_challenge: codeChallenge,\n code_challenge_method: \"S256\",\n ...providerConfig.extraConfig,\n });\n\n return `${providerImpl.authorizationEndpoint}?${params.toString()}`;\n }\n\n /**\n * Handles the OAuth callback and creates a user session.\n *\n * @param provider - The provider name (must be a configured provider key)\n * @param code - The authorization code from the provider\n * @param state - The state parameter for validation\n * @returns A Promise that resolves to the session ID\n *\n * @throws Error when code or state is missing/invalid, or provider is not configured\n *\n * @example\n * ```typescript\n * const sessionId = await lixa.handleCallback({\n * provider: 'google',\n * code: req.query.code,\n * state: req.query.state\n * });\n * ```\n */\n public async handleCallback({\n provider,\n code,\n state,\n }: {\n provider: ConfiguredProviderKey<TConfig> | string;\n code: string;\n state?: string;\n }): Promise<string> {\n if (!code || code.trim() === \"\") {\n throw new Error(\"Invalid or missing code in callback\");\n }\n\n if (!state || state.trim() === \"\") {\n throw new Error(\"Invalid or missing state in callback\");\n }\n\n //Validate state here\n const cachedState = await this.stateDao.getState(state);\n if (!cachedState) {\n throw new Error(\"Invalid or expired state\");\n }\n // State is valid, remove it from cache to prevent reuse\n await this.stateDao.deleteState(state);\n\n //Get code verifier from cached state\n const codeVerifier = cachedState.codeVerifier;\n\n const providerType = String(provider).toLowerCase();\n const providerConfig = this.findProviderByType(providerType);\n const providerImpl = Lixa.CONFIGURED_PROVIDERS.get(providerType);\n\n if (!providerConfig || !providerImpl) {\n throw new Error(`Provider ${String(provider)} not configured`);\n }\n\n // Exchange code for tokens and fetch user info here.\n const tokens = await this.exchangeCodeForToken(\n code,\n providerConfig,\n providerImpl,\n codeVerifier\n );\n\n\n const session = await this.sessionStrategy.createSession(tokens);\n\n // Generate unique session ID\n const sessionId = randomBytes(32).toString(\"hex\");\n\n // Store session with 24 hour TTL (86400 seconds)\n await this.sesionDao.saveSession(sessionId, session, 86400);\n\n return sessionId;\n }\n\n public fetchSessionInfo(sessionId: string): Promise<Session | null> {\n return this.sesionDao.getSession(sessionId);\n }\n\n private async exchangeCodeForToken(\n code: string,\n providerConfig: ProviderConfig,\n providerImpl: IProvider,\n codeVerifier: string\n ): Promise<any> {\n // Build the request body\n const body: Record<string, string> = {\n client_id: providerConfig.clientId,\n client_secret: providerConfig.clientSecret,\n code,\n redirect_uri: providerConfig.redirectUri,\n grant_type: \"authorization_code\",\n };\n\n if (codeVerifier) {\n body.code_verifier = codeVerifier;\n }\n const params = new URLSearchParams(body);\n\n this.log('Token Exchange - Request body:', params.toString());\n this.log('Token Exchange - Token endpoint:', providerImpl.tokenEndpoint);\n \n const response = await fetch(providerImpl.tokenEndpoint, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/x-www-form-urlencoded\",\n Accept: \"application/json\",\n },\n body: params.toString(),\n });\n\n if (!response.ok) {\n const errorBody = await response.text();\n this.logError('Token Exchange - Error response:', errorBody);\n throw new Error(\n `Token exchange failed: ${response.status} ${response.statusText} - ${errorBody}`\n );\n }\n\n return response.json();\n }\n\n private findProviderByType(providerType: string): ProviderConfig | undefined {\n return this.config.providers[providerType];\n }\n}\n\nexport { Lixa };\n","import NodeCache from 'node-cache';\nimport { StateDao } from \"./types\";\n\nclass LocalStateCache implements StateDao {\n private cache: NodeCache;\n\n constructor(defaultTtlSeconds: number = 600) {\n this.cache = new NodeCache({ stdTTL: defaultTtlSeconds });\n }\n\n async saveState(state: string, data: any, expiresInSeconds: number): Promise<void> {\n this.cache.set(state, data, expiresInSeconds);\n }\n\n async getState(state: string): Promise<any | null> {\n return this.cache.get(state) || null;\n }\n\n async deleteState(state: string): Promise<void> {\n this.cache.del(state);\n }\n}\n\nexport { LocalStateCache };\n","import NodeCache from 'node-cache';\nimport { SessionDao } from \"./types\";\n\nclass LocalSessionCache implements SessionDao {\n private cache: NodeCache;\n\n constructor(defaultTtlSeconds: number = 600) {\n this.cache = new NodeCache({ stdTTL: defaultTtlSeconds });\n }\n\n async saveSession(state: string, data: any, expiresInSeconds: number): Promise<void> {\n this.cache.set(state, data, expiresInSeconds);\n }\n\n async getSession(state: string): Promise<any | null> {\n return this.cache.get(state) || null;\n }\n\n async deleteSession(state: string): Promise<void> {\n this.cache.del(state);\n }\n}\n\nexport { LocalSessionCache };\n","/**\n * Represents a user session after successful OAuth authentication.\n *\n * @public\n */\nexport interface Session {\n /** The session token (typically the access token) */\n token: string;\n /** Raw token data from the OAuth provider */\n raw: any;\n}\n\n/**\n * Strategy interface for custom session creation.\n *\n * @public\n */\nexport interface SessionStrategy {\n /**\n * Creates a session from OAuth token data.\n *\n * @param userInfo - The token data received from the OAuth provider\n * @returns A Promise that resolves to a Session object\n */\n createSession(userInfo: any): Promise<Session>;\n}\n\n/**\n * Default session strategy that works with any OAuth provider.\n * Extracts common token information and creates a standardized session.\n *\n * @public\n */\nexport class DefaultSessionStrategy implements SessionStrategy {\n /**\n * Creates a session from OAuth token data.\n * Handles common OAuth token formats and extracts the access token.\n *\n * @param tokenData - The token data received from the OAuth provider\n * @returns A Promise that resolves to a Session object\n */\n async createSession(tokenData: any): Promise<Session> {\n // Extract access token from various possible formats\n const accessToken = tokenData.access_token || \n tokenData.accessToken || \n tokenData.token ||\n tokenData;\n\n if (!accessToken || typeof accessToken !== 'string') {\n throw new Error('No valid access token found in OAuth response');\n }\n\n return {\n token: accessToken,\n raw: tokenData,\n };\n }\n}"],"mappings":"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","names":["NodeCache"]}
|
package/dist/lixa.d.ts
CHANGED
|
@@ -44,12 +44,15 @@ declare class Lixa<TConfig extends LixaConfig<any> = LixaConfig> {
|
|
|
44
44
|
private stateDao;
|
|
45
45
|
private sesionDao;
|
|
46
46
|
private sessionStrategy;
|
|
47
|
+
private debug;
|
|
47
48
|
/**
|
|
48
49
|
* Creates a new Lixa instance with the provided configuration.
|
|
49
50
|
*
|
|
50
51
|
* @param config - The configuration object containing provider settings and optional session strategy
|
|
51
52
|
*/
|
|
52
53
|
constructor(config: TConfig);
|
|
54
|
+
private log;
|
|
55
|
+
private logError;
|
|
53
56
|
/**
|
|
54
57
|
* Checks if a provider is both registered and configured for this instance.
|
|
55
58
|
* This is a type guard that narrows the provider type for use with getAuthUrl.
|
package/dist/lixa.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lixa.d.ts","sourceRoot":"","sources":["../src/lixa.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,UAAU,EAAE,KAAK,cAAc,EAAE,MAAM,SAAS,CAAC;AAC/D,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAKxC,OAAO,EAAE,KAAK,OAAO,EAAgD,MAAM,kBAAkB,CAAC;AAO9F;;GAEG;AACH,KAAK,qBAAqB,CAAC,CAAC,SAAS,UAAU,CAAC,GAAG,CAAC,IAAI,MAAM,CAAC,CAAC,WAAW,CAAC,CAAC;AAE7E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,cAAM,IAAI,CAAC,OAAO,SAAS,UAAU,CAAC,GAAG,CAAC,GAAG,UAAU;IACrD,OAAO,CAAC,MAAM,CAAC,oBAAoB,CAAqC;IACxE,OAAO,CAAC,MAAM,CAAC,iBAAiB,CAAyB;IACzD,OAAO,CAAC,MAAM,CAAC,mBAAmB,CAA2B;IAC7D,OAAO,CAAC,MAAM,CAAC,wBAAwB,CAAgC;IACvE,OAAO,CAAC,MAAM,CAAU;IACxB,OAAO,CAAC,QAAQ,CAAW;IAC3B,OAAO,CAAC,SAAS,CAAa;IAC9B,OAAO,CAAC,eAAe,CAAkB;
|
|
1
|
+
{"version":3,"file":"lixa.d.ts","sourceRoot":"","sources":["../src/lixa.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,UAAU,EAAE,KAAK,cAAc,EAAE,MAAM,SAAS,CAAC;AAC/D,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAKxC,OAAO,EAAE,KAAK,OAAO,EAAgD,MAAM,kBAAkB,CAAC;AAO9F;;GAEG;AACH,KAAK,qBAAqB,CAAC,CAAC,SAAS,UAAU,CAAC,GAAG,CAAC,IAAI,MAAM,CAAC,CAAC,WAAW,CAAC,CAAC;AAE7E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,cAAM,IAAI,CAAC,OAAO,SAAS,UAAU,CAAC,GAAG,CAAC,GAAG,UAAU;IACrD,OAAO,CAAC,MAAM,CAAC,oBAAoB,CAAqC;IACxE,OAAO,CAAC,MAAM,CAAC,iBAAiB,CAAyB;IACzD,OAAO,CAAC,MAAM,CAAC,mBAAmB,CAA2B;IAC7D,OAAO,CAAC,MAAM,CAAC,wBAAwB,CAAgC;IACvE,OAAO,CAAC,MAAM,CAAU;IACxB,OAAO,CAAC,QAAQ,CAAW;IAC3B,OAAO,CAAC,SAAS,CAAa;IAC9B,OAAO,CAAC,eAAe,CAAkB;IACzC,OAAO,CAAC,KAAK,CAAU;IAEvB;;;;OAIG;gBACS,MAAM,EAAE,OAAO;IAkB3B,OAAO,CAAC,GAAG;IAMX,OAAO,CAAC,QAAQ;IAMhB;;;;;;;;;;;;;;OAcG;IACI,oBAAoB,CAAC,CAAC,SAAS,MAAM,EAAE,QAAQ,EAAE,CAAC,GAAG,QAAQ,IAAI,CAAC,GAAG,qBAAqB,CAAC,OAAO,CAAC;IAM1G;;;;;;;;;;;;;;;OAeG;WACW,gBAAgB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,EAAE,WAAW,EAAE,CAAC,GAAG,IAAI;IAMzF;;;;OAIG;WACW,sBAAsB,IAAI,MAAM,EAAE;IAIhD;;;;;OAKG;WACW,YAAY,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,EACjE,MAAM,EAAE,UAAU,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC,GAAG;QAAE,SAAS,EAAE,CAAC,CAAA;KAAE,GACtD,UAAU,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC;IAc/B;;;;;;;OAOG;WACW,mBAAmB,IAAI,MAAM;IAI3C;;;;;;;OAOG;IACH,OAAO,CAAC,MAAM,CAAC,oBAAoB;IAInC,OAAO,CAAC,MAAM,CAAC,kBAAkB;IAUjC;;;;;;;;;;;;;;;OAeG;IACI,UAAU,CAAC,QAAQ,EAAE,qBAAqB,CAAC,OAAO,CAAC,GAAG,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM;IAsC3F;;;;;;;;;;;;;;;;;;OAkBG;IACU,cAAc,CAAC,EAC1B,QAAQ,EACR,IAAI,EACJ,KAAK,GACN,EAAE;QACD,QAAQ,EAAE,qBAAqB,CAAC,OAAO,CAAC,GAAG,MAAM,CAAC;QAClD,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,GAAG,OAAO,CAAC,MAAM,CAAC;IAgDZ,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC;YAIrD,oBAAoB;IA2ClC,OAAO,CAAC,kBAAkB;CAG3B;AAED,OAAO,EAAE,IAAI,EAAE,CAAC"}
|
package/dist/types.d.ts
CHANGED
|
@@ -33,6 +33,8 @@ export interface LixaConfig<TRegisteredProviders extends string = string> {
|
|
|
33
33
|
stateDao?: StateDao;
|
|
34
34
|
/** Optiona: custom session storage implementation */
|
|
35
35
|
sessionDao?: SessionDao;
|
|
36
|
+
/** Enable debug logging */
|
|
37
|
+
debug?: boolean;
|
|
36
38
|
}
|
|
37
39
|
/**
|
|
38
40
|
* Helper type to create a configuration with only registered providers.
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAGnD,OAAO,EAAE,eAAe,EAAE,CAAC;AAE3B;;;;GAIG;AACH,MAAM,WAAW,cAAc;IAC7B,mDAAmD;IACnD,QAAQ,EAAE,MAAM,CAAC;IACjB,uDAAuD;IACvD,YAAY,EAAE,MAAM,CAAC;IACrB,oDAAoD;IACpD,WAAW,EAAE,MAAM,CAAC;IACpB,uCAAuC;IACvC,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,4DAA4D;IAC5D,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CACnC;AAED;;;;;GAKG;AACH,MAAM,WAAW,UAAU,CAAC,oBAAoB,SAAS,MAAM,GAAG,MAAM;IACtE,+DAA+D;IAC/D,SAAS,EAAE,MAAM,CAAC,oBAAoB,EAAE,cAAc,CAAC,CAAC;IACxD,gDAAgD;IAChD,eAAe,CAAC,EAAE,eAAe,CAAC;IAClC,mDAAmD;IACnD,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,qDAAqD;IACrD,UAAU,CAAC,EAAE,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAGnD,OAAO,EAAE,eAAe,EAAE,CAAC;AAE3B;;;;GAIG;AACH,MAAM,WAAW,cAAc;IAC7B,mDAAmD;IACnD,QAAQ,EAAE,MAAM,CAAC;IACjB,uDAAuD;IACvD,YAAY,EAAE,MAAM,CAAC;IACrB,oDAAoD;IACpD,WAAW,EAAE,MAAM,CAAC;IACpB,uCAAuC;IACvC,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,4DAA4D;IAC5D,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CACnC;AAED;;;;;GAKG;AACH,MAAM,WAAW,UAAU,CAAC,oBAAoB,SAAS,MAAM,GAAG,MAAM;IACtE,+DAA+D;IAC/D,SAAS,EAAE,MAAM,CAAC,oBAAoB,EAAE,cAAc,CAAC,CAAC;IACxD,gDAAgD;IAChD,eAAe,CAAC,EAAE,eAAe,CAAC;IAClC,mDAAmD;IACnD,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,qDAAqD;IACrD,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,2BAA2B;IAC3B,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED;;;;;GAKG;AACH,MAAM,MAAM,cAAc,CAAC,UAAU,SAAS,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,IAAI,UAAU,CAAC,MAAM,UAAU,GAAG,MAAM,CAAC,GAAG;IACtH,SAAS,EAAE,UAAU,CAAC;CACvB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vunexa/lixa",
|
|
3
|
-
"version": "0.0.1-alpha.
|
|
3
|
+
"version": "0.0.1-alpha.20",
|
|
4
4
|
"description": "Lixa is a flexible, provider-agnostic OAuth and OpenID Connect (OIDC) client library that simplifies multi-provider authentication flows. It supports seamless integration with providers like Google and GitHub, offers extensible session management, and enables dynamic provider resolution based on callback URLs.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"oauth",
|