@noony-serverless/core 0.1.1 → 0.2.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/build/core/core.d.ts +16 -48
- package/build/core/core.js +2 -61
- package/build/core/handler.d.ts +37 -16
- package/build/core/handler.js +131 -42
- package/build/core/index.d.ts +0 -1
- package/build/core/index.js +0 -1
- package/build/middlewares/ConsolidatedValidationMiddleware.d.ts +126 -0
- package/build/middlewares/ConsolidatedValidationMiddleware.js +330 -0
- package/build/middlewares/ProcessingMiddleware.d.ts +138 -0
- package/build/middlewares/ProcessingMiddleware.js +425 -0
- package/build/middlewares/SecurityMiddleware.d.ts +157 -0
- package/build/middlewares/SecurityMiddleware.js +307 -0
- package/build/middlewares/authenticationMiddleware.d.ts +379 -0
- package/build/middlewares/authenticationMiddleware.js +216 -0
- package/build/middlewares/bodyParserMiddleware.d.ts +99 -0
- package/build/middlewares/bodyParserMiddleware.js +99 -0
- package/build/middlewares/bodyValidationMiddleware.d.ts +69 -3
- package/build/middlewares/bodyValidationMiddleware.js +68 -2
- package/build/middlewares/dependencyInjectionMiddleware.d.ts +238 -0
- package/build/middlewares/dependencyInjectionMiddleware.js +238 -0
- package/build/middlewares/errorHandlerMiddleware.d.ts +94 -0
- package/build/middlewares/errorHandlerMiddleware.js +105 -0
- package/build/middlewares/guards/RouteGuards.d.ts +476 -21
- package/build/middlewares/guards/RouteGuards.js +418 -21
- package/build/middlewares/guards/adapters/CustomTokenVerificationPortAdapter.d.ts +271 -0
- package/build/middlewares/guards/adapters/CustomTokenVerificationPortAdapter.js +301 -0
- package/build/middlewares/guards/cache/CacheAdapter.d.ts +369 -28
- package/build/middlewares/guards/cache/CacheAdapter.js +124 -5
- package/build/middlewares/guards/cache/MemoryCacheAdapter.d.ts +113 -4
- package/build/middlewares/guards/cache/MemoryCacheAdapter.js +113 -4
- package/build/middlewares/guards/config/GuardConfiguration.d.ts +568 -18
- package/build/middlewares/guards/config/GuardConfiguration.js +266 -10
- package/build/middlewares/guards/guards/FastAuthGuard.d.ts +5 -5
- package/build/middlewares/guards/guards/PermissionGuardFactory.d.ts +5 -13
- package/build/middlewares/guards/guards/PermissionGuardFactory.js +4 -4
- package/build/middlewares/guards/index.d.ts +43 -1
- package/build/middlewares/guards/index.js +46 -1
- package/build/middlewares/guards/resolvers/ExpressionPermissionResolver.d.ts +1 -1
- package/build/middlewares/guards/resolvers/ExpressionPermissionResolver.js +1 -1
- package/build/middlewares/guards/resolvers/PermissionResolver.d.ts +1 -1
- package/build/middlewares/guards/resolvers/PlainPermissionResolver.d.ts +1 -1
- package/build/middlewares/guards/resolvers/WildcardPermissionResolver.d.ts +1 -1
- package/build/middlewares/guards/services/FastUserContextService.d.ts +20 -33
- package/build/middlewares/guards/services/FastUserContextService.js +19 -5
- package/build/middlewares/headerVariablesMiddleware.d.ts +118 -0
- package/build/middlewares/headerVariablesMiddleware.js +118 -0
- package/build/middlewares/httpAttributesMiddleware.d.ts +235 -0
- package/build/middlewares/httpAttributesMiddleware.js +236 -1
- package/build/middlewares/index.d.ts +3 -1
- package/build/middlewares/index.js +6 -1
- package/build/middlewares/queryParametersMiddleware.d.ts +105 -0
- package/build/middlewares/queryParametersMiddleware.js +105 -0
- package/build/middlewares/rateLimitingMiddleware.d.ts +601 -9
- package/build/middlewares/rateLimitingMiddleware.js +623 -11
- package/build/middlewares/responseWrapperMiddleware.d.ts +170 -1
- package/build/middlewares/responseWrapperMiddleware.js +170 -1
- package/build/middlewares/securityAuditMiddleware.js +5 -5
- package/package.json +11 -9
- package/build/core/containerPool.d.ts +0 -44
- package/build/core/containerPool.js +0 -103
- package/build/middlewares/validationMiddleware.d.ts +0 -9
- package/build/middlewares/validationMiddleware.js +0 -40
|
@@ -20,24 +20,128 @@
|
|
|
20
20
|
* - Comprehensive monitoring and audit trails
|
|
21
21
|
* - Framework-agnostic middleware integration
|
|
22
22
|
*
|
|
23
|
-
*
|
|
23
|
+
* @example
|
|
24
|
+
* Complete guard system setup:
|
|
24
25
|
* ```typescript
|
|
25
|
-
*
|
|
26
|
-
* .use(RouteGuards.requirePermissions(['user:read', 'user:update']))
|
|
26
|
+
* import { RouteGuards, GuardSetup } from '@noony-serverless/core';
|
|
27
27
|
*
|
|
28
|
-
* //
|
|
29
|
-
*
|
|
28
|
+
* // Define user permission source
|
|
29
|
+
* const userPermissionSource = {
|
|
30
|
+
* async getUserPermissions(userId: string): Promise<string[]> {
|
|
31
|
+
* const user = await getUserFromDatabase(userId);
|
|
32
|
+
* return user.permissions;
|
|
33
|
+
* }
|
|
34
|
+
* };
|
|
30
35
|
*
|
|
31
|
-
* //
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
* {
|
|
35
|
-
*
|
|
36
|
-
* {
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
36
|
+
* // Define token validator
|
|
37
|
+
* const tokenValidator = {
|
|
38
|
+
* async validateToken(token: string) {
|
|
39
|
+
* try {
|
|
40
|
+
* const decoded = jwt.verify(token, process.env.JWT_SECRET);
|
|
41
|
+
* return { valid: true, decoded };
|
|
42
|
+
* } catch (error) {
|
|
43
|
+
* return { valid: false, error: error.message };
|
|
44
|
+
* }
|
|
45
|
+
* },
|
|
46
|
+
* extractUserId: (decoded: unknown) => (decoded as any).sub,
|
|
47
|
+
* isTokenExpired: (decoded: unknown) => (decoded as any).exp < Date.now() / 1000
|
|
48
|
+
* };
|
|
49
|
+
*
|
|
50
|
+
* // Configure guard system
|
|
51
|
+
* await RouteGuards.configure(
|
|
52
|
+
* GuardSetup.production(),
|
|
53
|
+
* userPermissionSource,
|
|
54
|
+
* tokenValidator,
|
|
55
|
+
* {
|
|
56
|
+
* tokenHeader: 'authorization',
|
|
57
|
+
* tokenPrefix: 'Bearer ',
|
|
58
|
+
* requireEmailVerification: true,
|
|
59
|
+
* allowInactiveUsers: false
|
|
60
|
+
* }
|
|
61
|
+
* );
|
|
62
|
+
* ```
|
|
63
|
+
*
|
|
64
|
+
* @example
|
|
65
|
+
* Simple permission checks (fastest - ~0.1ms cached):
|
|
66
|
+
* ```typescript
|
|
67
|
+
* import { Handler, RouteGuards } from '@noony-serverless/core';
|
|
68
|
+
*
|
|
69
|
+
* const userManagementHandler = new Handler()
|
|
70
|
+
* .use(RouteGuards.requirePermissions(['user:read', 'user:update']))
|
|
71
|
+
* .handle(async (context) => {
|
|
72
|
+
* // User has either 'user:read' OR 'user:update' permission
|
|
73
|
+
* const users = await getUsers();
|
|
74
|
+
* return { success: true, users };
|
|
75
|
+
* });
|
|
76
|
+
* ```
|
|
77
|
+
*
|
|
78
|
+
* @example
|
|
79
|
+
* Wildcard permission patterns (hierarchical - ~0.2ms cached):
|
|
80
|
+
* ```typescript
|
|
81
|
+
* const adminHandler = new Handler()
|
|
82
|
+
* .use(RouteGuards.requireWildcardPermissions(['admin.*', 'org.reports.*']))
|
|
83
|
+
* .handle(async (context) => {
|
|
84
|
+
* // User has any permission starting with 'admin.' OR 'org.reports.'
|
|
85
|
+
* const adminData = await getAdminDashboard();
|
|
86
|
+
* return { success: true, data: adminData };
|
|
87
|
+
* });
|
|
88
|
+
* ```
|
|
89
|
+
*
|
|
90
|
+
* @example
|
|
91
|
+
* Complex boolean expressions (~0.5ms cached):
|
|
92
|
+
* ```typescript
|
|
93
|
+
* const complexAccessHandler = new Handler()
|
|
94
|
+
* .use(RouteGuards.requireComplexPermissions({
|
|
95
|
+
* or: [
|
|
96
|
+
* { permission: 'admin.users' },
|
|
97
|
+
* { and: [
|
|
98
|
+
* { permission: 'moderator.content' },
|
|
99
|
+
* { permission: 'org.reports.view' }
|
|
100
|
+
* ]}
|
|
101
|
+
* ]
|
|
102
|
+
* }))
|
|
103
|
+
* .handle(async (context) => {
|
|
104
|
+
* // User has 'admin.users' OR ('moderator.content' AND 'org.reports.view')
|
|
105
|
+
* return { success: true, accessGranted: true };
|
|
106
|
+
* });
|
|
107
|
+
* ```
|
|
108
|
+
*
|
|
109
|
+
* @example
|
|
110
|
+
* Authentication-only (no permissions):
|
|
111
|
+
* ```typescript
|
|
112
|
+
* const profileHandler = new Handler()
|
|
113
|
+
* .use(RouteGuards.requireAuth())
|
|
114
|
+
* .handle(async (context) => {
|
|
115
|
+
* // Only checks if user is authenticated
|
|
116
|
+
* const profile = await getUserProfile(context.user.id);
|
|
117
|
+
* return { success: true, profile };
|
|
118
|
+
* });
|
|
119
|
+
* ```
|
|
120
|
+
*
|
|
121
|
+
* @example
|
|
122
|
+
* Cache invalidation for security:
|
|
123
|
+
* ```typescript
|
|
124
|
+
* // Invalidate specific user when permissions change
|
|
125
|
+
* await RouteGuards.invalidateUserPermissions('user-123', 'Permission update');
|
|
126
|
+
*
|
|
127
|
+
* // System-wide invalidation for major updates
|
|
128
|
+
* await RouteGuards.invalidateAllPermissions('System update deployed');
|
|
129
|
+
*
|
|
130
|
+
* // Emergency invalidation for security incidents
|
|
131
|
+
* await RouteGuards.emergencyInvalidation('Security breach detected');
|
|
132
|
+
* ```
|
|
133
|
+
*
|
|
134
|
+
* @example
|
|
135
|
+
* Monitoring and health checks:
|
|
136
|
+
* ```typescript
|
|
137
|
+
* // Get comprehensive system statistics
|
|
138
|
+
* const stats = RouteGuards.getSystemStats();
|
|
139
|
+
* console.log('Guard system performance:', stats.systemHealth);
|
|
140
|
+
*
|
|
141
|
+
* // Perform health check
|
|
142
|
+
* const health = await RouteGuards.healthCheck();
|
|
143
|
+
* console.log('System status:', health.status);
|
|
144
|
+
* console.log('Recommendations:', health.details.recommendations);
|
|
41
145
|
* ```
|
|
42
146
|
*
|
|
43
147
|
* @author Noony Framework Team
|
|
@@ -64,6 +168,50 @@ const ConservativeCacheInvalidation_1 = require("./cache/ConservativeCacheInvali
|
|
|
64
168
|
const FastAuthGuard_1 = require("./guards/FastAuthGuard");
|
|
65
169
|
const PermissionGuardFactory_1 = require("./guards/PermissionGuardFactory");
|
|
66
170
|
const PermissionRegistry_1 = require("./registry/PermissionRegistry");
|
|
171
|
+
const CustomTokenVerificationPortAdapter_1 = require("./adapters/CustomTokenVerificationPortAdapter");
|
|
172
|
+
/**
|
|
173
|
+
* Helper function to check if a token validator is a CustomTokenVerificationPort
|
|
174
|
+
*/
|
|
175
|
+
function isCustomTokenVerificationPort(validator) {
|
|
176
|
+
return (typeof validator === 'object' &&
|
|
177
|
+
'verifyToken' in validator &&
|
|
178
|
+
!('validateToken' in validator));
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Convert any token validator to the TokenValidator interface expected by RouteGuards.
|
|
182
|
+
* Automatically wraps CustomTokenVerificationPort implementations with an adapter.
|
|
183
|
+
*/
|
|
184
|
+
function normalizeTokenValidator(validator) {
|
|
185
|
+
if (isCustomTokenVerificationPort(validator)) {
|
|
186
|
+
// For CustomTokenVerificationPort, we create a generic adapter
|
|
187
|
+
// We use a basic configuration that tries to extract common fields
|
|
188
|
+
return new CustomTokenVerificationPortAdapter_1.CustomTokenVerificationPortAdapter(validator, {
|
|
189
|
+
userIdExtractor: (user) => {
|
|
190
|
+
// Try to extract user ID from common field names
|
|
191
|
+
if (user && typeof user === 'object') {
|
|
192
|
+
const userObj = user;
|
|
193
|
+
return String(userObj.sub ||
|
|
194
|
+
userObj.id ||
|
|
195
|
+
userObj.userId ||
|
|
196
|
+
userObj.user_id ||
|
|
197
|
+
'unknown');
|
|
198
|
+
}
|
|
199
|
+
return 'unknown';
|
|
200
|
+
},
|
|
201
|
+
expirationExtractor: (user) => {
|
|
202
|
+
// Try to extract expiration from common field names
|
|
203
|
+
if (user && typeof user === 'object') {
|
|
204
|
+
const userObj = user;
|
|
205
|
+
const exp = userObj.exp || userObj.expiresAt || userObj.expires_at;
|
|
206
|
+
return typeof exp === 'number' ? exp : undefined;
|
|
207
|
+
}
|
|
208
|
+
return undefined;
|
|
209
|
+
},
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
// Already a TokenValidator, return as-is
|
|
213
|
+
return validator;
|
|
214
|
+
}
|
|
67
215
|
/**
|
|
68
216
|
* Route Guards Facade Implementation
|
|
69
217
|
*
|
|
@@ -107,9 +255,58 @@ let RouteGuards = class RouteGuards {
|
|
|
107
255
|
*
|
|
108
256
|
* @param profile - Environment profile with guard configurations
|
|
109
257
|
* @param permissionSource - User permission data source
|
|
110
|
-
* @param tokenValidator -
|
|
258
|
+
* @param tokenValidator - Token validation service (supports both TokenValidator and CustomTokenVerificationPort)
|
|
111
259
|
* @param authConfig - Authentication guard configuration
|
|
112
260
|
* @returns Promise resolving when configuration is complete
|
|
261
|
+
*
|
|
262
|
+
* @example
|
|
263
|
+
* Using with CustomTokenVerificationPort from AuthenticationMiddleware:
|
|
264
|
+
* ```typescript
|
|
265
|
+
* import { CustomTokenVerificationPort } from '@/middlewares/authenticationMiddleware';
|
|
266
|
+
* import { RouteGuards, GuardSetup } from '@/middlewares/guards';
|
|
267
|
+
*
|
|
268
|
+
* // Same token verifier used across the framework
|
|
269
|
+
* const tokenVerifier: CustomTokenVerificationPort<User> = {
|
|
270
|
+
* async verifyToken(token: string): Promise<User> {
|
|
271
|
+
* const payload = jwt.verify(token, process.env.JWT_SECRET!) as JWTPayload;
|
|
272
|
+
* return {
|
|
273
|
+
* id: payload.sub,
|
|
274
|
+
* email: payload.email,
|
|
275
|
+
* roles: payload.roles || [],
|
|
276
|
+
* sub: payload.sub,
|
|
277
|
+
* exp: payload.exp
|
|
278
|
+
* };
|
|
279
|
+
* }
|
|
280
|
+
* };
|
|
281
|
+
*
|
|
282
|
+
* // Configure RouteGuards with the same verifier
|
|
283
|
+
* await RouteGuards.configure(
|
|
284
|
+
* GuardSetup.production(),
|
|
285
|
+
* userPermissionSource,
|
|
286
|
+
* tokenVerifier, // Automatically wrapped with adapter
|
|
287
|
+
* authConfig
|
|
288
|
+
* );
|
|
289
|
+
* ```
|
|
290
|
+
*
|
|
291
|
+
* @example
|
|
292
|
+
* Traditional usage with TokenValidator (backward compatible):
|
|
293
|
+
* ```typescript
|
|
294
|
+
* const tokenValidator: TokenValidator = {
|
|
295
|
+
* async validateToken(token: string) {
|
|
296
|
+
* // Your existing validation logic
|
|
297
|
+
* return { valid: true, decoded: userPayload };
|
|
298
|
+
* },
|
|
299
|
+
* extractUserId: (decoded) => decoded.sub,
|
|
300
|
+
* isTokenExpired: (decoded) => decoded.exp < Date.now() / 1000
|
|
301
|
+
* };
|
|
302
|
+
*
|
|
303
|
+
* await RouteGuards.configure(
|
|
304
|
+
* GuardSetup.production(),
|
|
305
|
+
* userPermissionSource,
|
|
306
|
+
* tokenValidator, // Works as before
|
|
307
|
+
* authConfig
|
|
308
|
+
* );
|
|
309
|
+
* ```
|
|
113
310
|
*/
|
|
114
311
|
static async configure(profile, permissionSource, tokenValidator, authConfig) {
|
|
115
312
|
if (RouteGuards_1.isConfigured) {
|
|
@@ -119,20 +316,30 @@ let RouteGuards = class RouteGuards {
|
|
|
119
316
|
try {
|
|
120
317
|
// Create guard configuration
|
|
121
318
|
const config = GuardConfiguration_1.GuardConfiguration.fromEnvironmentProfile(profile);
|
|
122
|
-
//
|
|
319
|
+
// Get effective cache type considering environment variable override
|
|
320
|
+
// Environment variable NOONY_GUARD_CACHE_ENABLE takes precedence for security
|
|
321
|
+
const effectiveCacheType = GuardConfiguration_1.GuardConfiguration.getEffectiveCacheType(profile.cacheType);
|
|
322
|
+
// Select cache adapter based on effective cache type
|
|
123
323
|
let cache;
|
|
124
|
-
if (
|
|
324
|
+
if (effectiveCacheType === 'memory') {
|
|
125
325
|
cache = new MemoryCacheAdapter_1.MemoryCacheAdapter({
|
|
126
326
|
maxSize: config.cache.maxEntries || 1000,
|
|
127
327
|
defaultTTL: config.cache.defaultTtlMs || 15 * 60 * 1000,
|
|
128
328
|
name: 'guard-memory-cache',
|
|
129
329
|
});
|
|
130
330
|
}
|
|
131
|
-
else if (
|
|
331
|
+
else if (effectiveCacheType === 'none') {
|
|
132
332
|
cache = new NoopCacheAdapter_1.NoopCacheAdapter();
|
|
333
|
+
// Log cache status for debugging
|
|
334
|
+
if (!GuardConfiguration_1.GuardConfiguration.isCachingEnabled()) {
|
|
335
|
+
console.log(`🚫 Guard caching disabled by environment variable NOONY_GUARD_CACHE_ENABLE`);
|
|
336
|
+
}
|
|
337
|
+
else {
|
|
338
|
+
console.log(`🚫 Guard caching disabled by configuration (cacheType: 'none')`);
|
|
339
|
+
}
|
|
133
340
|
}
|
|
134
341
|
else {
|
|
135
|
-
// Default to memory cache
|
|
342
|
+
// Default to memory cache (redis support would go here)
|
|
136
343
|
cache = new MemoryCacheAdapter_1.MemoryCacheAdapter({
|
|
137
344
|
maxSize: 1000,
|
|
138
345
|
defaultTTL: 15 * 60 * 1000,
|
|
@@ -145,8 +352,10 @@ let RouteGuards = class RouteGuards {
|
|
|
145
352
|
const userContextService = new FastUserContextService_1.FastUserContextService(cache, config, permissionSource, permissionRegistry);
|
|
146
353
|
// Create cache invalidation service
|
|
147
354
|
const cacheInvalidation = new ConservativeCacheInvalidation_1.ConservativeCacheInvalidation(cache);
|
|
355
|
+
// Normalize token validator to ensure compatibility
|
|
356
|
+
const normalizedTokenValidator = normalizeTokenValidator(tokenValidator);
|
|
148
357
|
// Create authentication guard
|
|
149
|
-
const authGuard = new FastAuthGuard_1.FastAuthGuard(cache, config, authConfig, userContextService, cacheInvalidation,
|
|
358
|
+
const authGuard = new FastAuthGuard_1.FastAuthGuard(cache, config, authConfig, userContextService, cacheInvalidation, normalizedTokenValidator);
|
|
150
359
|
// Create permission guard factory
|
|
151
360
|
const guardFactory = new PermissionGuardFactory_1.PermissionGuardFactory(userContextService, config, cache);
|
|
152
361
|
// Register services with TypeDI container
|
|
@@ -165,6 +374,8 @@ let RouteGuards = class RouteGuards {
|
|
|
165
374
|
console.log('✅ RouteGuards configured successfully', {
|
|
166
375
|
environment: profile.environment,
|
|
167
376
|
cacheType: profile.cacheType,
|
|
377
|
+
effectiveCacheType: effectiveCacheType,
|
|
378
|
+
cachingEnabled: GuardConfiguration_1.GuardConfiguration.isCachingEnabled(),
|
|
168
379
|
permissionStrategy: config.security.permissionResolutionStrategy,
|
|
169
380
|
timestamp: new Date().toISOString(),
|
|
170
381
|
});
|
|
@@ -333,6 +544,192 @@ let RouteGuards = class RouteGuards {
|
|
|
333
544
|
const instance = RouteGuards_1.getInstance();
|
|
334
545
|
return instance.performHealthCheck();
|
|
335
546
|
}
|
|
547
|
+
/**
|
|
548
|
+
* Factory method: Configure RouteGuards with CustomTokenVerificationPort for JWT tokens.
|
|
549
|
+
* Provides a streamlined setup for JWT-based authentication with common field extraction.
|
|
550
|
+
*
|
|
551
|
+
* @example
|
|
552
|
+
* Quick JWT setup with CustomTokenVerificationPort:
|
|
553
|
+
* ```typescript
|
|
554
|
+
* import { CustomTokenVerificationPort } from '@/middlewares/authenticationMiddleware';
|
|
555
|
+
*
|
|
556
|
+
* interface JWTUser {
|
|
557
|
+
* sub: string;
|
|
558
|
+
* email: string;
|
|
559
|
+
* roles: string[];
|
|
560
|
+
* exp: number;
|
|
561
|
+
* }
|
|
562
|
+
*
|
|
563
|
+
* const jwtVerifier: CustomTokenVerificationPort<JWTUser> = {
|
|
564
|
+
* async verifyToken(token: string): Promise<JWTUser> {
|
|
565
|
+
* const payload = jwt.verify(token, process.env.JWT_SECRET!) as any;
|
|
566
|
+
* return {
|
|
567
|
+
* sub: payload.sub,
|
|
568
|
+
* email: payload.email,
|
|
569
|
+
* roles: payload.roles || [],
|
|
570
|
+
* exp: payload.exp
|
|
571
|
+
* };
|
|
572
|
+
* }
|
|
573
|
+
* };
|
|
574
|
+
*
|
|
575
|
+
* // One-line setup for JWT authentication
|
|
576
|
+
* await RouteGuards.configureWithJWT(
|
|
577
|
+
* GuardSetup.production(),
|
|
578
|
+
* userPermissionSource,
|
|
579
|
+
* jwtVerifier,
|
|
580
|
+
* {
|
|
581
|
+
* tokenHeader: 'authorization',
|
|
582
|
+
* tokenPrefix: 'Bearer ',
|
|
583
|
+
* requireEmailVerification: true
|
|
584
|
+
* }
|
|
585
|
+
* );
|
|
586
|
+
* ```
|
|
587
|
+
*/
|
|
588
|
+
static async configureWithJWT(profile, permissionSource, jwtVerifier, authConfig) {
|
|
589
|
+
// Create a properly typed adapter for JWT tokens
|
|
590
|
+
const tokenValidator = CustomTokenVerificationPortAdapter_1.TokenVerificationAdapterFactory.forJWT(jwtVerifier);
|
|
591
|
+
await RouteGuards_1.configure(profile, permissionSource, tokenValidator, authConfig);
|
|
592
|
+
}
|
|
593
|
+
/**
|
|
594
|
+
* Factory method: Configure RouteGuards with CustomTokenVerificationPort for API keys.
|
|
595
|
+
* Provides setup for API key-based authentication with flexible field mapping.
|
|
596
|
+
*
|
|
597
|
+
* @example
|
|
598
|
+
* API key authentication setup:
|
|
599
|
+
* ```typescript
|
|
600
|
+
* interface APIKeyUser {
|
|
601
|
+
* keyId: string;
|
|
602
|
+
* permissions: string[];
|
|
603
|
+
* organization: string;
|
|
604
|
+
* expiresAt?: number;
|
|
605
|
+
* isActive: boolean;
|
|
606
|
+
* }
|
|
607
|
+
*
|
|
608
|
+
* const apiKeyVerifier: CustomTokenVerificationPort<APIKeyUser> = {
|
|
609
|
+
* async verifyToken(token: string): Promise<APIKeyUser> {
|
|
610
|
+
* const keyData = await validateAPIKeyInDatabase(token);
|
|
611
|
+
* if (!keyData || !keyData.isActive) {
|
|
612
|
+
* throw new Error('Invalid or inactive API key');
|
|
613
|
+
* }
|
|
614
|
+
* return keyData;
|
|
615
|
+
* }
|
|
616
|
+
* };
|
|
617
|
+
*
|
|
618
|
+
* await RouteGuards.configureWithAPIKey(
|
|
619
|
+
* GuardSetup.production(),
|
|
620
|
+
* userPermissionSource,
|
|
621
|
+
* apiKeyVerifier,
|
|
622
|
+
* {
|
|
623
|
+
* tokenHeader: 'x-api-key',
|
|
624
|
+
* tokenPrefix: '',
|
|
625
|
+
* allowInactiveUsers: false
|
|
626
|
+
* },
|
|
627
|
+
* 'keyId',
|
|
628
|
+
* 'expiresAt'
|
|
629
|
+
* );
|
|
630
|
+
* ```
|
|
631
|
+
*/
|
|
632
|
+
static async configureWithAPIKey(profile, permissionSource, apiKeyVerifier, authConfig, userIdField, expirationField) {
|
|
633
|
+
// Create a properly configured adapter for API keys
|
|
634
|
+
const tokenValidator = CustomTokenVerificationPortAdapter_1.TokenVerificationAdapterFactory.forAPIKey(apiKeyVerifier, userIdField, expirationField);
|
|
635
|
+
await RouteGuards_1.configure(profile, permissionSource, tokenValidator, authConfig);
|
|
636
|
+
}
|
|
637
|
+
/**
|
|
638
|
+
* Factory method: Configure RouteGuards with CustomTokenVerificationPort for OAuth tokens.
|
|
639
|
+
* Provides setup for OAuth-based authentication with scope validation.
|
|
640
|
+
*
|
|
641
|
+
* @example
|
|
642
|
+
* OAuth token authentication with scope requirements:
|
|
643
|
+
* ```typescript
|
|
644
|
+
* interface OAuthUser {
|
|
645
|
+
* sub: string;
|
|
646
|
+
* email: string;
|
|
647
|
+
* scope: string[];
|
|
648
|
+
* exp: number;
|
|
649
|
+
* client_id: string;
|
|
650
|
+
* }
|
|
651
|
+
*
|
|
652
|
+
* const oauthVerifier: CustomTokenVerificationPort<OAuthUser> = {
|
|
653
|
+
* async verifyToken(token: string): Promise<OAuthUser> {
|
|
654
|
+
* const response = await fetch(`${OAUTH_INTROSPECT_URL}`, {
|
|
655
|
+
* method: 'POST',
|
|
656
|
+
* headers: { 'Authorization': `Bearer ${token}` },
|
|
657
|
+
* body: new URLSearchParams({ token })
|
|
658
|
+
* });
|
|
659
|
+
*
|
|
660
|
+
* const tokenInfo = await response.json();
|
|
661
|
+
* if (!tokenInfo.active) {
|
|
662
|
+
* throw new Error('Token is not active');
|
|
663
|
+
* }
|
|
664
|
+
*
|
|
665
|
+
* return tokenInfo as OAuthUser;
|
|
666
|
+
* }
|
|
667
|
+
* };
|
|
668
|
+
*
|
|
669
|
+
* await RouteGuards.configureWithOAuth(
|
|
670
|
+
* GuardSetup.production(),
|
|
671
|
+
* userPermissionSource,
|
|
672
|
+
* oauthVerifier,
|
|
673
|
+
* {
|
|
674
|
+
* tokenHeader: 'authorization',
|
|
675
|
+
* tokenPrefix: 'Bearer ',
|
|
676
|
+
* requireEmailVerification: false
|
|
677
|
+
* },
|
|
678
|
+
* ['read:profile', 'write:data'] // Required OAuth scopes
|
|
679
|
+
* );
|
|
680
|
+
* ```
|
|
681
|
+
*/
|
|
682
|
+
static async configureWithOAuth(profile, permissionSource, oauthVerifier, authConfig, requiredScopes) {
|
|
683
|
+
// Create a properly configured adapter for OAuth tokens
|
|
684
|
+
const tokenValidator = CustomTokenVerificationPortAdapter_1.TokenVerificationAdapterFactory.forOAuth(oauthVerifier, requiredScopes);
|
|
685
|
+
await RouteGuards_1.configure(profile, permissionSource, tokenValidator, authConfig);
|
|
686
|
+
}
|
|
687
|
+
/**
|
|
688
|
+
* Factory method: Configure RouteGuards with a custom CustomTokenVerificationPort adapter.
|
|
689
|
+
* Provides maximum flexibility for custom token validation scenarios.
|
|
690
|
+
*
|
|
691
|
+
* @example
|
|
692
|
+
* Custom token validation with business-specific logic:
|
|
693
|
+
* ```typescript
|
|
694
|
+
* interface CustomUser {
|
|
695
|
+
* userId: string;
|
|
696
|
+
* tenantId: string;
|
|
697
|
+
* roles: string[];
|
|
698
|
+
* sessionExpiry: number;
|
|
699
|
+
* isVerified: boolean;
|
|
700
|
+
* }
|
|
701
|
+
*
|
|
702
|
+
* const customVerifier: CustomTokenVerificationPort<CustomUser> = {
|
|
703
|
+
* async verifyToken(token: string): Promise<CustomUser> {
|
|
704
|
+
* // Your custom verification logic
|
|
705
|
+
* return await verifyCustomToken(token);
|
|
706
|
+
* }
|
|
707
|
+
* };
|
|
708
|
+
*
|
|
709
|
+
* await RouteGuards.configureWithCustom(
|
|
710
|
+
* GuardSetup.production(),
|
|
711
|
+
* userPermissionSource,
|
|
712
|
+
* customVerifier,
|
|
713
|
+
* {
|
|
714
|
+
* tokenHeader: 'x-auth-token',
|
|
715
|
+
* tokenPrefix: 'Custom ',
|
|
716
|
+
* customValidation: async (token, user) => {
|
|
717
|
+
* return user.isVerified && user.tenantId === 'valid-tenant';
|
|
718
|
+
* }
|
|
719
|
+
* },
|
|
720
|
+
* {
|
|
721
|
+
* userIdExtractor: (user) => user.userId,
|
|
722
|
+
* expirationExtractor: (user) => user.sessionExpiry,
|
|
723
|
+
* additionalValidation: (user) => user.isVerified
|
|
724
|
+
* }
|
|
725
|
+
* );
|
|
726
|
+
* ```
|
|
727
|
+
*/
|
|
728
|
+
static async configureWithCustom(profile, permissionSource, customVerifier, authConfig, adapterConfig) {
|
|
729
|
+
// Create a custom configured adapter
|
|
730
|
+
const tokenValidator = CustomTokenVerificationPortAdapter_1.TokenVerificationAdapterFactory.custom(customVerifier, adapterConfig);
|
|
731
|
+
await RouteGuards_1.configure(profile, permissionSource, tokenValidator, authConfig);
|
|
732
|
+
}
|
|
336
733
|
// Private implementation methods
|
|
337
734
|
createPlainPermissionGuard(permissions, options) {
|
|
338
735
|
this.trackGuardCreation();
|