@wazobiatech/auth-middleware 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/README.md +986 -0
  2. package/dist/index.d.ts +9 -0
  3. package/dist/index.d.ts.map +1 -0
  4. package/dist/index.js +25 -0
  5. package/dist/index.js.map +1 -0
  6. package/dist/middlewares/express.helper.d.ts +4 -0
  7. package/dist/middlewares/express.helper.d.ts.map +1 -0
  8. package/dist/middlewares/express.helper.js +31 -0
  9. package/dist/middlewares/express.helper.js.map +1 -0
  10. package/dist/middlewares/gql.helper.d.ts +14 -0
  11. package/dist/middlewares/gql.helper.d.ts.map +1 -0
  12. package/dist/middlewares/gql.helper.js +82 -0
  13. package/dist/middlewares/gql.helper.js.map +1 -0
  14. package/dist/middlewares/index.d.ts +5 -0
  15. package/dist/middlewares/index.d.ts.map +1 -0
  16. package/dist/middlewares/index.js +13 -0
  17. package/dist/middlewares/index.js.map +1 -0
  18. package/dist/middlewares/jwt.guard.d.ts +16 -0
  19. package/dist/middlewares/jwt.guard.d.ts.map +1 -0
  20. package/dist/middlewares/jwt.guard.js +336 -0
  21. package/dist/middlewares/jwt.guard.js.map +1 -0
  22. package/dist/middlewares/project.guard.d.ts +49 -0
  23. package/dist/middlewares/project.guard.d.ts.map +1 -0
  24. package/dist/middlewares/project.guard.js +310 -0
  25. package/dist/middlewares/project.guard.js.map +1 -0
  26. package/dist/nestjs/decorators/auth.decorator.d.ts +2 -0
  27. package/dist/nestjs/decorators/auth.decorator.d.ts.map +1 -0
  28. package/dist/nestjs/decorators/auth.decorator.js +10 -0
  29. package/dist/nestjs/decorators/auth.decorator.js.map +1 -0
  30. package/dist/nestjs/decorators/current-user.decorator.d.ts +2 -0
  31. package/dist/nestjs/decorators/current-user.decorator.d.ts.map +1 -0
  32. package/dist/nestjs/decorators/current-user.decorator.js +18 -0
  33. package/dist/nestjs/decorators/current-user.decorator.js.map +1 -0
  34. package/dist/nestjs/guards/jwt-guard.d.ts +8 -0
  35. package/dist/nestjs/guards/jwt-guard.d.ts.map +1 -0
  36. package/dist/nestjs/guards/jwt-guard.js +23 -0
  37. package/dist/nestjs/guards/jwt-guard.js.map +1 -0
  38. package/dist/nestjs/guards/project.guard.d.ts +45 -0
  39. package/dist/nestjs/guards/project.guard.d.ts.map +1 -0
  40. package/dist/nestjs/guards/project.guard.js +352 -0
  41. package/dist/nestjs/guards/project.guard.js.map +1 -0
  42. package/dist/nestjs/index.d.ts +6 -0
  43. package/dist/nestjs/index.d.ts.map +1 -0
  44. package/dist/nestjs/index.js +14 -0
  45. package/dist/nestjs/index.js.map +1 -0
  46. package/dist/nestjs/jwt-auth.module.d.ts +3 -0
  47. package/dist/nestjs/jwt-auth.module.d.ts.map +1 -0
  48. package/dist/nestjs/jwt-auth.module.js +25 -0
  49. package/dist/nestjs/jwt-auth.module.js.map +1 -0
  50. package/dist/nestjs/strategies/jwt-strategy.d.ts +23 -0
  51. package/dist/nestjs/strategies/jwt-strategy.d.ts.map +1 -0
  52. package/dist/nestjs/strategies/jwt-strategy.js +381 -0
  53. package/dist/nestjs/strategies/jwt-strategy.js.map +1 -0
  54. package/dist/test/middleware.test.d.ts +2 -0
  55. package/dist/test/middleware.test.d.ts.map +1 -0
  56. package/dist/test/middleware.test.js +383 -0
  57. package/dist/test/middleware.test.js.map +1 -0
  58. package/dist/types/jwt-payload.d.ts +48 -0
  59. package/dist/types/jwt-payload.d.ts.map +1 -0
  60. package/dist/types/jwt-payload.js +3 -0
  61. package/dist/types/jwt-payload.js.map +1 -0
  62. package/dist/utils/redis.connection.d.ts +9 -0
  63. package/dist/utils/redis.connection.d.ts.map +1 -0
  64. package/dist/utils/redis.connection.js +27 -0
  65. package/dist/utils/redis.connection.js.map +1 -0
  66. package/package.json +99 -0
package/README.md ADDED
@@ -0,0 +1,986 @@
1
+ # @platform/jwt-auth
2
+
3
+ A comprehensive TypeScript authentication library for the Wazobia platform, supporting both user JWT tokens and project service tokens. This library provides authentication middleware for Express.js, NestJS guards, and GraphQL resolvers with Redis caching and JWKS (JSON Web Key Set) validation.
4
+
5
+ ## 🚀 Features
6
+
7
+ - 🔐 **Dual Authentication**: Supports both user JWT authentication and project service authentication
8
+ - 🏗️ **Multiple Framework Support**: Works seamlessly with Express.js, NestJS, and GraphQL
9
+ - 🔑 **JWKS Integration**: Dynamically fetches and caches public keys from JWKS endpoints
10
+ - ⚡ **Redis Caching**: High-performance caching for validated tokens and JWKS
11
+ - 🚫 **Token Revocation**: Built-in support for checking revoked tokens
12
+ - 🏢 **Project-based Security**: Service-to-service authentication with project-specific access control
13
+ - 📝 **TypeScript**: Full TypeScript support with comprehensive type definitions
14
+ - 🛡️ **Security First**: RS512 algorithm, signature verification, and comprehensive validation
15
+ - 📊 **Performance Optimized**: Intelligent caching strategies and minimal memory footprint
16
+
17
+ ## 🏗️ Architecture Overview
18
+
19
+ ### User Authentication (JWT)
20
+ - Validates JWT tokens signed with RS512 algorithm using Mercury service
21
+ - Fetches public keys from project-specific JWKS endpoints (`/api/jwks/{project_uuid}`)
22
+ - Supports intelligent token caching and revocation checking via Redis
23
+ - Extracts comprehensive user context (uuid, email, name, project_uuid)
24
+ - Validates token claims: issuer, audience, expiration, not-before
25
+
26
+ ### Project Authentication
27
+ - Validates project service tokens for secure service-to-service communication
28
+ - Checks service access permissions based on `enabled_services` configuration
29
+ - Supports secret versioning for seamless token rotation without downtime
30
+ - Validates project-specific access controls and service authorization
31
+ - Integrates with Athens service for project management
32
+
33
+ ### Caching Strategy
34
+ - **JWKS Cache**: 5 hours (18000 seconds) for public keys
35
+ - **Token Cache**: Configurable via `CACHE_EXPIRY_TIME` (default: 1 hour)
36
+ - **Revoked Tokens**: Real-time tracking via Redis
37
+ - **Project Metadata**: Cached for performance optimization
38
+
39
+ ## 📦 Installation
40
+
41
+ ```bash
42
+ npm install @platform/jwt-auth
43
+ ```
44
+
45
+ ## 📋 Requirements
46
+
47
+ - Node.js >= 16.0.0
48
+ - TypeScript >= 4.5.0
49
+ - Redis >= 6.0.0 (for caching and token management)
50
+ - Mercury service (JWT issuer and JWKS provider)
51
+ - Athens service (project authentication, optional)
52
+
53
+ ## Quick Start
54
+
55
+ ### Express.js Middleware
56
+
57
+ ```typescript
58
+ import { jwtAuthMiddleware, projectAuthMiddleware } from '@platform/jwt-auth';
59
+
60
+ const app = express();
61
+
62
+ // User authentication
63
+ app.use('/api/user', jwtAuthMiddleware());
64
+
65
+ // Project authentication
66
+ app.use('/api/project', projectAuthMiddleware());
67
+
68
+ // Combined authentication
69
+ app.use('/api/secure', jwtAuthMiddleware(), projectAuthMiddleware());
70
+ ```
71
+
72
+ ### NestJS Guards
73
+
74
+ ```typescript
75
+ import { ProjectAndUserAuth } from '@platform/jwt-auth';
76
+
77
+ @UseGuard(ProjectAndUserAuth) // Combines both JWT and project authentication
78
+ @Controller('secure')
79
+ export class SecureController {
80
+ @Get()
81
+ getSecureData(@CurrentUser() user: AuthUser) {
82
+ return { user, message: 'Authenticated!' };
83
+ }
84
+ }
85
+ ```
86
+
87
+ ### GraphQL Resolvers
88
+
89
+ ```typescript
90
+ import { GraphQLAuthHelper } from '@platform/jwt-auth';
91
+
92
+ export class UserResolver {
93
+ private authHelper = new GraphQLAuthHelper();
94
+
95
+ @Query()
96
+ async getUser(
97
+ @Args() args: any,
98
+ @Context() context: GqlContext
99
+ ) {
100
+ return this.authHelper.withJwtAuth(async (parent, args, ctx, info) => {
101
+ // Your resolver logic here
102
+ return ctx.req.user;
103
+ })(null, args, context, null);
104
+ }
105
+ }
106
+ ```
107
+
108
+ ## ⚙️ Environment Variables
109
+
110
+ ### Required Variables
111
+
112
+ | Variable | Description | Example | Notes |
113
+ |----------|-------------|---------|-------|
114
+ | `MERCURY_BASE_URL` | Mercury service base URL (JWT issuer) | `http://localhost:4000` | Must match JWT `iss` claim |
115
+ | `REDIS_URL` | Redis connection URL for caching | `redis://localhost:6379` | Used for token/JWKS cache |
116
+ | `SERVICE_ID` | Unique identifier for current service | `helios`, `dolos`, `coeus` | Must match Athens service config |
117
+ | `SIGNATURE_SHARED_SECRET` | HMAC shared secret for JWKS security | `your-256-bit-secret` | Keep secure, rotate regularly |
118
+
119
+ ### Optional Variables
120
+
121
+ | Variable | Description | Default | Example |
122
+ |----------|-------------|---------|---------|
123
+ | `NEXUS_ID` | Frontend admin dashboard service ID, Default project UUID for JWKS fallback | `null` | `550e8400-e29b-41d4-a716-446655440000` |
124
+ | `CACHE_EXPIRY_TIME` | Token cache TTL in seconds | `3600` | `7200` |
125
+ | `JWKS_CACHE_TTL` | JWKS public key cache TTL in seconds | `18000` | `21600` |
126
+
127
+ ### Environment File Example
128
+
129
+ Create a `.env` file in your project root:
130
+
131
+ ```bash
132
+ # Mercury Service Configuration (JWT Authentication)
133
+ MERCURY_BASE_URL=http://localhost:4000
134
+
135
+ # Redis Configuration (Caching & Token Management)
136
+ REDIS_URL=redis://localhost:6379/0
137
+
138
+ # Security Configuration
139
+ SIGNATURE_SHARED_SECRET=your-very-secure-256-bit-shared-secret-key
140
+
141
+ # Service Configuration
142
+ SERVICE_ID=helios # Current service identifier
143
+ NEXUS_ID=550e8400-e29b-41d4-a716-446655440000 # Frontend admin dashboard ID (optional)
144
+
145
+ # Cache Configuration (Optional - Performance Tuning)
146
+ CACHE_EXPIRY_TIME=3600 # JWT token cache TTL (1 hour)
147
+ JWKS_CACHE_TTL=18000 # JWKS cache TTL (5 hours)
148
+
149
+ # Additional Configuration (Application Specific)
150
+ NODE_ENV=development
151
+ PORT=3000
152
+ ```
153
+
154
+ ### Detailed Environment Variable Reference
155
+
156
+ #### MERCURY_BASE_URL
157
+ - **Purpose**: Base URL of the Mercury authentication service
158
+ - **Usage**: JWT issuer validation and JWKS endpoint construction (`/api/jwks/{project_uuid}`)
159
+ - **Format**: Complete URL with protocol (e.g., `http://localhost:4000`)
160
+ - **Validation**: Must match the `iss` (issuer) claim in JWT tokens exactly
161
+ - **Examples**:
162
+ - Development: `http://localhost:4000`
163
+ - Production: `https://auth.wazobia.com`
164
+
165
+ #### REDIS_URL
166
+ - **Purpose**: Redis connection string for caching and token management
167
+ - **Usage**: Stores validated tokens, JWKS cache, revoked token lists, and project metadata
168
+ - **Format**: Standard Redis connection URL
169
+ - **Examples**:
170
+ - Local: `redis://localhost:6379`
171
+ - With auth: `redis://username:password@redis-host:6379`
172
+ - With database: `redis://localhost:6379/1`
173
+ - TLS: `rediss://redis-host:6380`
174
+ - **Database Usage**:
175
+ - `/0`: Token cache and JWKS
176
+ - `/1`: Revoked tokens
177
+ - `/2`: Project metadata
178
+
179
+ #### SERVICE_ID
180
+ - **Purpose**: Unique identifier for the current service instance
181
+ - **Usage**: Validates project token `enabled_services` array contains this service
182
+ - **Format**: String identifier (kebab-case recommended)
183
+ - **Examples**: `helios`, `dolos`, `coeus`, `udjat`
184
+ - **Important**: Must exactly match service IDs configured in Athens project management
185
+
186
+ #### SIGNATURE_SHARED_SECRET
187
+ - **Purpose**: HMAC-SHA256 shared secret for JWKS request authentication
188
+ - **Usage**: Signs requests to Mercury JWKS endpoints for additional security
189
+ - **Format**: Base64 or hexadecimal encoded secret (minimum 256 bits recommended)
190
+ - **Security**:
191
+ - Keep secret secure and never commit to version control
192
+ - Rotate regularly (quarterly recommended)
193
+ - Use strong random generation (crypto.randomBytes(32))
194
+
195
+ #### NEXUS_ID (Optional)
196
+ - **Purpose**: Service identifier for the Nexus frontend admin dashboard
197
+ - **Usage**: Special handling for admin dashboard authentication flows
198
+ - **Format**: UUID v4 format
199
+ - **Required**: Only if your service interacts with the Nexus admin interface
200
+ - **Example**: `550e8400-e29b-41d4-a716-446655440000`
201
+
202
+ #### ATHENS_SERVICE_ID (Optional)
203
+ - **Purpose**: Fallback project UUID when JWT tokens don't specify `project_uuid`
204
+ - **Usage**: JWKS endpoint construction for legacy or system tokens
205
+ - **Format**: UUID v4 format
206
+ - **Required**: Only if you have tokens without project context
207
+ - **Example**: `550e8400-e29b-41d4-a716-446655440000`
208
+
209
+ #### CACHE_EXPIRY_TIME (Optional)
210
+ - **Purpose**: TTL for validated JWT token cache entries
211
+ - **Usage**: Redis expiration time for token validation results
212
+ - **Format**: Integer seconds
213
+ - **Default**: `3600` (1 hour)
214
+ - **Considerations**:
215
+ - Lower values: Better security, higher load on Mercury service
216
+ - Higher values: Better performance, potential stale token issues
217
+ - Recommended: 1-2 hours for most applications
218
+
219
+ #### JWKS_CACHE_TTL (Optional)
220
+ - **Purpose**: TTL for JWKS public key cache entries
221
+ - **Usage**: Redis expiration time for fetched public keys
222
+ - **Format**: Integer seconds
223
+ - **Default**: `18000` (5 hours)
224
+ - **Considerations**:
225
+ - JWKS keys rotate infrequently
226
+ - Higher cache times reduce Mercury service load
227
+ - Keys are validated before use even when cached
228
+
229
+ ## Usage Examples
230
+
231
+ ### Express Middleware
232
+
233
+ ```typescript
234
+ import express from 'express';
235
+ import { jwtAuthMiddleware, projectAuthMiddleware } from '@platform/jwt-auth';
236
+ import { AuthenticatedRequest } from '@platform/jwt-auth/types';
237
+
238
+ const app = express();
239
+
240
+ // JWT Authentication only
241
+ app.get('/user/profile', jwtAuthMiddleware(), (req: AuthenticatedRequest, res) => {
242
+ res.json({
243
+ user: req.user // { uuid, email, name }
244
+ });
245
+ });
246
+
247
+ // Project Authentication only
248
+ app.get('/service/health', projectAuthMiddleware(), (req: AuthenticatedRequest, res) => {
249
+ res.json({
250
+ project: req.project // { project_uuid, enabled_services, ... }
251
+ });
252
+ });
253
+
254
+ // Combined Authentication
255
+ app.get('/secure/data',
256
+ jwtAuthMiddleware(),
257
+ projectAuthMiddleware(),
258
+ (req: AuthenticatedRequest, res) => {
259
+ res.json({
260
+ user: req.user,
261
+ project: req.project
262
+ });
263
+ }
264
+ );
265
+ ```
266
+
267
+ ### NestJS Integration
268
+
269
+ ```typescript
270
+ // Module setup
271
+ import { JwtAuthModule } from '@platform/jwt-auth';
272
+
273
+ @Module({
274
+ imports: [JwtAuthModule],
275
+ controllers: [UserController],
276
+ })
277
+ export class AppModule {}
278
+
279
+ // Controller usage
280
+ import { Controller, Get, UseGuards } from '@nestjs/common';
281
+ import { JwtAuthGuard, ProjectAuthGuard, CurrentUser } from '@platform/jwt-auth';
282
+
283
+ @Controller('api')
284
+ export class UserController {
285
+ @Get('profile')
286
+ @UseGuards(JwtAuthGuard)
287
+ getProfile(@CurrentUser() user: AuthUser) {
288
+ return user;
289
+ }
290
+
291
+ @Get('project-data')
292
+ @UseGuards(ProjectAuthGuard)
293
+ getProjectData(@Request() req) {
294
+ return req.project;
295
+ }
296
+
297
+ @Get('secure')
298
+ @UseGuards(JwtAuthGuard, ProjectAuthGuard)
299
+ getSecureData(@CurrentUser() user: AuthUser, @Request() req) {
300
+ return { user, project: req.project };
301
+ }
302
+ }
303
+ ```
304
+
305
+ ### GraphQL Integration
306
+
307
+ ```typescript
308
+ import { GraphQLAuthHelper } from '@platform/jwt-auth';
309
+ import { Resolver, Query, Context, Args } from '@nestjs/graphql';
310
+
311
+ @Resolver()
312
+ export class UserResolver {
313
+ private authHelper = new GraphQLAuthHelper();
314
+
315
+ @Query()
316
+ async getCurrentUser(@Context() context: GqlContext) {
317
+ return this.authHelper.withJwtAuth(async (parent, args, ctx) => {
318
+ return ctx.req.user;
319
+ })(null, {}, context, null);
320
+ }
321
+
322
+ @Query()
323
+ async getProjectInfo(@Context() context: GqlContext) {
324
+ return this.authHelper.withProjectAuth(async (parent, args, ctx) => {
325
+ return ctx.req.project;
326
+ })(null, {}, context, null);
327
+ }
328
+
329
+ @Query()
330
+ async getSecureData(@Context() context: GqlContext) {
331
+ return this.authHelper.withCombinedAuth(async (parent, args, ctx) => {
332
+ return {
333
+ user: ctx.req.user,
334
+ project: ctx.req.project
335
+ };
336
+ })(null, {}, context, null);
337
+ }
338
+ }
339
+ ```
340
+
341
+ ## Token Format
342
+
343
+ ### JWT User Token
344
+ ```json
345
+ {
346
+ "sub": {
347
+ "uuid": "user-uuid",
348
+ "email": "user@example.com",
349
+ "name": "User Name"
350
+ },
351
+ "project_uuid": "project-uuid",
352
+ "type": "user",
353
+ "iss": "https://auth.yourdomain.com",
354
+ "aud": "https://api.yourdomain.com",
355
+ "exp": 1640995200,
356
+ "nbf": 1640908800,
357
+ "iat": 1640908800,
358
+ "jti": "token-id"
359
+ }
360
+ ```
361
+
362
+ ### Project Service Token
363
+ ```json
364
+ {
365
+ "project_uuid": "project-uuid",
366
+ "secret_version": 1,
367
+ "enabled_services": ["user-service", "order-service"],
368
+ "token_id": "project-token-id",
369
+ "type": "project",
370
+ "iat": 1640908800,
371
+ "exp": 1640995200
372
+ }
373
+ ```
374
+
375
+ ## Headers
376
+
377
+ ### JWT Authentication
378
+ ```
379
+ Authorization: Bearer <jwt-token>
380
+ ```
381
+
382
+ ### Project Authentication
383
+ ```
384
+ x-project-token: Bearer <project-token>
385
+ ```
386
+ or
387
+ ```
388
+ x-project-token: <project-token>
389
+ ```
390
+
391
+ ## Error Handling
392
+
393
+ The library throws descriptive errors for different scenarios:
394
+
395
+ ### JWT Authentication Errors
396
+ - `No authorization header provided`
397
+ - `Invalid JWT token: <reason>`
398
+ - `Token expired`
399
+ - `Token has been revoked`
400
+ - `Invalid issuer`
401
+
402
+ ### Project Authentication Errors
403
+ - `No project token provided`
404
+ - `Service access denied`
405
+ - `Token has been revoked`
406
+ - `Token secret version outdated`
407
+
408
+ ### JWKS Errors
409
+ - `JWKS endpoint not reachable`
410
+ - `Key not found in JWKS`
411
+ - `Mercury service unavailable`
412
+
413
+ ## Performance Considerations
414
+
415
+ ### Caching Strategy
416
+ - **JWKS Cache**: 10 minutes (600 seconds)
417
+ - **Token Cache**: Configurable via `CACHE_EXPIRY_TIME` (default: 1 hour)
418
+ - **Project JWKS Cache**: 5 hours (18000 seconds)
419
+
420
+ ### Redis Usage
421
+ - Validated tokens are cached to avoid re-validation
422
+ - JWKS responses are cached to reduce HTTP requests
423
+ - Revoked tokens are stored for quick lookup
424
+ - Project secret versions are cached
425
+
426
+ ### Memory Usage
427
+ - In-memory JWKS cache with expiration
428
+ - Minimal memory footprint for token caching
429
+ - Automatic cleanup of expired cache entries
430
+
431
+ ## Security Features
432
+
433
+ ### Token Validation
434
+ - RSA signature verification using JWKS
435
+ - Timestamp validation (exp, nbf, iat)
436
+ - Issuer validation
437
+ - Token revocation checking
438
+
439
+ ### Project Security
440
+ - Service-specific access control
441
+ - Secret version validation for token rotation
442
+ - HMAC signature verification for JWKS requests
443
+
444
+ ### Best Practices
445
+ - Tokens are never logged in full
446
+ - Sensitive data is not cached
447
+ - Automatic cleanup of expired cache entries
448
+ - Comprehensive error messages without exposing internals
449
+
450
+ ## 🔗 Service Integration
451
+
452
+ ### Mercury Service Integration
453
+ The JWT authentication library integrates with the Mercury service for:
454
+ - **JWT Token Validation**: Verifies token signatures using Mercury's public keys
455
+ - **JWKS Endpoint**: Fetches public keys from `/api/jwks/{project_uuid}`
456
+ - **Token Revocation**: Checks revoked token lists maintained by Mercury
457
+ - **User Context**: Extracts user information from validated JWT tokens
458
+
459
+ ### Athens Service Integration (Optional)
460
+ When using project authentication, the library can integrate with Athens for:
461
+ - **Project Management**: Validates project existence and configuration
462
+ - **Service Authorization**: Checks if services are enabled for specific projects
463
+ - **Project Metadata**: Caches project information for performance
464
+
465
+ ### Redis Integration
466
+ Redis is used extensively for performance optimization:
467
+ - **Token Cache**: Stores validation results to avoid repeated Mercury calls
468
+ - **JWKS Cache**: Caches public keys with configurable TTL
469
+ - **Revoked Tokens**: Maintains real-time revoked token blacklist
470
+ - **Project Data**: Caches project metadata and service configurations
471
+
472
+ ### Supported Service Types
473
+
474
+ | Service | Environment Example | Usage Pattern |
475
+ |---------|-------------------|---------------|
476
+ | **Helios** | `SERVICE_ID=helios` | API Gateway, routing, load balancing |
477
+ | **Dolos** | `SERVICE_ID=dolos` | Background processing, async tasks |
478
+ | **Coeus** | `SERVICE_ID=coeus` | Analytics, reporting, data processing |
479
+ | **Udjat** | `SERVICE_ID=udjat` | Monitoring, logging, observability |
480
+ | **Nexus** | Special handling via `NEXUS_ID` | Frontend admin dashboard |
481
+
482
+ ## 🛠️ Development
483
+
484
+ ### Local Development Setup
485
+
486
+ 1. **Install Dependencies**
487
+ ```bash
488
+ npm install
489
+ ```
490
+
491
+ 2. **Setup Environment**
492
+ ```bash
493
+ cp .env.example .env
494
+ # Edit .env with your configuration
495
+ ```
496
+
497
+ 3. **Start Required Services**
498
+ ```bash
499
+ # Start Redis
500
+ docker run -d -p 6379:6379 redis:alpine
501
+
502
+ # Start Mercury service (if running locally)
503
+ cd ../../../apps/node-services/mercury
504
+ npm run start:dev
505
+ ```
506
+
507
+ 4. **Run Tests**
508
+ ```bash
509
+ # Unit tests
510
+ npm test
511
+
512
+ # Integration tests (requires Redis + Mercury)
513
+ npm run test:integration
514
+
515
+ # Coverage report
516
+ npm run test:coverage
517
+ ```
518
+
519
+ ### Testing Configuration
520
+
521
+ Create a test environment file `.env.test`:
522
+
523
+ ```bash
524
+ # Test Environment Configuration
525
+ NODE_ENV=test
526
+ MERCURY_BASE_URL=http://localhost:4000
527
+ REDIS_URL=redis://localhost:6380 # Use different Redis DB for tests
528
+ SERVICE_ID=test-service
529
+ SIGNATURE_SHARED_SECRET=test-secret-key-for-testing-only
530
+ CACHE_EXPIRY_TIME=60 # Shorter cache for faster tests
531
+ JWKS_CACHE_TTL=300
532
+ ```
533
+
534
+ ### Docker Development
535
+
536
+ ```dockerfile
537
+ # Dockerfile example for service using jwt-auth
538
+ FROM node:18-alpine
539
+
540
+ WORKDIR /app
541
+ COPY package*.json ./
542
+ RUN npm ci --only=production
543
+
544
+ COPY . .
545
+ EXPOSE 3000
546
+
547
+ # Environment variables will be provided by docker-compose
548
+ CMD ["npm", "start"]
549
+ ```
550
+
551
+ ```yaml
552
+ # docker-compose.yml example
553
+ version: '3.8'
554
+ services:
555
+ your-service:
556
+ build: .
557
+ environment:
558
+ - MERCURY_BASE_URL=http://mercury:4000
559
+ - REDIS_URL=redis://redis:6379
560
+ - SERVICE_ID=your-service
561
+ - SIGNATURE_SHARED_SECRET=${SIGNATURE_SHARED_SECRET}
562
+ depends_on:
563
+ - redis
564
+ - mercury
565
+
566
+ redis:
567
+ image: redis:alpine
568
+ ports:
569
+ - "6379:6379"
570
+ ```
571
+
572
+ ## 🔧 Troubleshooting
573
+
574
+ ### Common Authentication Issues
575
+
576
+ #### JWT Authentication Problems
577
+
578
+ **1. "JWKS endpoint not reachable"**
579
+ - **Cause**: Cannot connect to Mercury service JWKS endpoint
580
+ - **Solutions**:
581
+ ```bash
582
+ # Check Mercury service status
583
+ curl http://localhost:4000/health
584
+
585
+ # Verify JWKS endpoint
586
+ curl http://localhost:4000/api/jwks/{project_uuid}
587
+
588
+ # Check network connectivity
589
+ ping mercury-service-host
590
+ ```
591
+ - **Environment Check**: Ensure `MERCURY_BASE_URL` is correct and accessible
592
+
593
+ **2. "Key not found in JWKS"**
594
+ - **Cause**: JWT token's `kid` header doesn't match any key in JWKS response
595
+ - **Solutions**:
596
+ - Verify token is signed with current Mercury keys
597
+ - Check if Mercury key rotation occurred recently
598
+ - Clear JWKS cache: `redis-cli DEL jwks:*`
599
+ - **Debug**: Examine JWT header: `echo 'token' | cut -d. -f1 | base64 -d`
600
+
601
+ **3. "Invalid JWT token: Token expired"**
602
+ - **Cause**: JWT token `exp` claim is in the past
603
+ - **Solutions**:
604
+ - Check system clock synchronization (NTP)
605
+ - Obtain fresh token from Mercury `/auth/login`
606
+ - Verify Mercury token expiry configuration
607
+
608
+ **4. "Invalid issuer"**
609
+ - **Cause**: JWT `iss` claim doesn't match `MERCURY_BASE_URL`
610
+ - **Solutions**:
611
+ - Ensure `MERCURY_BASE_URL` exactly matches JWT issuer
612
+ - Check for trailing slashes or protocol mismatches
613
+ - Verify Mercury service configuration
614
+
615
+ #### Project Authentication Problems
616
+
617
+ **5. "Service access denied"**
618
+ - **Cause**: `SERVICE_ID` not in project token's `enabled_services` array
619
+ - **Solutions**:
620
+ ```bash
621
+ # Check project configuration in Athens
622
+ curl http://athens:3000/api/projects/{project_uuid}
623
+
624
+ # Verify service is enabled
625
+ # enabled_services should contain your SERVICE_ID
626
+ ```
627
+ - **Debug**: Decode project token payload to check `enabled_services`
628
+
629
+ **6. "No project token provided"**
630
+ - **Cause**: Missing `x-project-token` header
631
+ - **Solutions**:
632
+ - Add header: `x-project-token: Bearer <project-token>`
633
+ - Or: `x-project-token: <project-token>`
634
+ - Verify client is sending correct headers
635
+
636
+ #### Redis Connection Issues
637
+
638
+ **7. Redis connection errors**
639
+ - **Cause**: Cannot connect to Redis server
640
+ - **Solutions**:
641
+ ```bash
642
+ # Test Redis connectivity
643
+ redis-cli -u $REDIS_URL ping
644
+
645
+ # Check Redis server status
646
+ docker ps | grep redis
647
+
648
+ # Verify Redis URL format
649
+ echo $REDIS_URL
650
+ ```
651
+ - **Common Formats**:
652
+ - `redis://localhost:6379`
653
+ - `redis://user:pass@host:port/db`
654
+ - `rediss://host:port` (TLS)
655
+
656
+ #### Performance Issues
657
+
658
+ **8. Slow authentication responses**
659
+ - **Cause**: JWKS or token validation taking too long
660
+ - **Solutions**:
661
+ ```bash
662
+ # Check Redis performance
663
+ redis-cli --latency -h redis-host -p 6379
664
+
665
+ # Monitor cache hit rates
666
+ redis-cli info stats | grep keyspace
667
+
668
+ # Optimize cache TTL values
669
+ CACHE_EXPIRY_TIME=7200 # 2 hours
670
+ JWKS_CACHE_TTL=21600 # 6 hours
671
+ ```
672
+
673
+ **9. Memory usage growing over time**
674
+ - **Cause**: Cache not expiring properly
675
+ - **Solutions**:
676
+ - Monitor Redis memory: `redis-cli info memory`
677
+ - Set appropriate TTL values
678
+ - Clear cache if needed: `redis-cli FLUSHDB`
679
+
680
+ ### Debug Mode & Logging
681
+
682
+ Enable detailed logging for troubleshooting:
683
+
684
+ ```bash
685
+ # Enable all jwt-auth debug logs
686
+ DEBUG=jwt-auth:* npm start
687
+
688
+ # Enable specific component logs
689
+ DEBUG=jwt-auth:jwt,jwt-auth:jwks npm start
690
+
691
+ # Enable with log levels
692
+ NODE_ENV=development DEBUG=jwt-auth:* npm start
693
+ ```
694
+
695
+ ### Health Check Endpoints
696
+
697
+ Add health checks to your service:
698
+
699
+ ```typescript
700
+ import { createClient } from 'redis';
701
+
702
+ app.get('/health', async (req, res) => {
703
+ const health = {
704
+ status: 'ok',
705
+ timestamp: new Date().toISOString(),
706
+ services: {}
707
+ };
708
+
709
+ try {
710
+ // Check Redis connectivity
711
+ const redis = createClient({ url: process.env.REDIS_URL });
712
+ await redis.connect();
713
+ await redis.ping();
714
+ await redis.quit();
715
+ health.services.redis = 'connected';
716
+ } catch (error) {
717
+ health.services.redis = 'disconnected';
718
+ health.status = 'error';
719
+ }
720
+
721
+ try {
722
+ // Check Mercury connectivity
723
+ const response = await fetch(`${process.env.MERCURY_BASE_URL}/health`);
724
+ health.services.mercury = response.ok ? 'connected' : 'error';
725
+ } catch (error) {
726
+ health.services.mercury = 'disconnected';
727
+ health.status = 'error';
728
+ }
729
+
730
+ res.status(health.status === 'ok' ? 200 : 503).json(health);
731
+ });
732
+ ```
733
+
734
+ ### Monitoring & Alerting
735
+
736
+ Set up monitoring for authentication issues:
737
+
738
+ ```typescript
739
+ // Custom middleware for auth metrics
740
+ const authMetricsMiddleware = (req, res, next) => {
741
+ const startTime = Date.now();
742
+
743
+ res.on('finish', () => {
744
+ const duration = Date.now() - startTime;
745
+ const status = res.statusCode;
746
+
747
+ // Log authentication metrics
748
+ console.log({
749
+ type: 'auth_metric',
750
+ path: req.path,
751
+ method: req.method,
752
+ status,
753
+ duration,
754
+ user_id: req.user?.uuid,
755
+ project_id: req.project?.project_uuid
756
+ });
757
+ });
758
+
759
+ next();
760
+ };
761
+ ```
762
+
763
+ ### Migration & Deployment
764
+
765
+ When deploying authentication changes:
766
+
767
+ 1. **Zero-downtime deployment**:
768
+ ```bash
769
+ # Clear caches gradually
770
+ redis-cli --scan --pattern "jwt:*" | xargs redis-cli del
771
+
772
+ # Monitor error rates during deployment
773
+ kubectl logs -f deployment/your-service | grep "auth"
774
+ ```
775
+
776
+ 2. **Rollback procedures**:
777
+ ```bash
778
+ # Restore previous environment variables
779
+ kubectl set env deployment/your-service MERCURY_BASE_URL=old-url
780
+
781
+ # Clear Redis cache to force fresh validation
782
+ redis-cli flushall
783
+ ```
784
+
785
+ ## 📚 API Reference
786
+
787
+ ### Core Middleware
788
+
789
+ #### `projectAuthMiddleware(options?)`
790
+ Express middleware for project service authentication.
791
+
792
+ ### NestJS Guards
793
+
794
+ #### `JwtAuthGuard`
795
+ NestJS guard for JWT authentication.
796
+
797
+ ```typescript
798
+ @Controller('api')
799
+ export class UserController {
800
+ @UseGuards(JwtAuthGuard)
801
+ @Get('profile')
802
+ getProfile(@CurrentUser() user: AuthUser) {
803
+ return user;
804
+ }
805
+ }
806
+ ```
807
+
808
+ #### `ProjectAuthGuard`
809
+ NestJS guard for project authentication.
810
+
811
+ ```typescript
812
+ @UseGuards(ProjectAuthGuard)
813
+ @Get('project-data')
814
+ getProjectData(@Request() req) {
815
+ return req.project;
816
+ }
817
+ ```
818
+
819
+ #### `ProjectAndUserAuth`
820
+ Combined guard for both JWT and project authentication.
821
+
822
+ ```typescript
823
+ @UseGuards(ProjectAndUserAuth)
824
+ @Get('secure-data')
825
+ getSecureData(@CurrentUser() user: AuthUser, @Request() req) {
826
+ return { user, project: req.project };
827
+ }
828
+ ```
829
+
830
+ ### GraphQL Integration
831
+
832
+ #### `GraphQLAuthHelper`
833
+ Helper class for GraphQL resolver authentication.
834
+
835
+ ```typescript
836
+ class GraphQLAuthHelper {
837
+ withJwtAuth<T>(resolver: GraphQLResolver<T>): GraphQLResolver<T>
838
+ withProjectAuth<T>(resolver: GraphQLResolver<T>): GraphQLResolver<T>
839
+ withCombinedAuth<T>(resolver: GraphQLResolver<T>): GraphQLResolver<T>
840
+ }
841
+ ```
842
+
843
+ ### Type Definitions
844
+
845
+ #### `AuthUser`
846
+ User information extracted from JWT token.
847
+
848
+ ```typescript
849
+ interface AuthUser {
850
+ uuid: string;
851
+ email: string;
852
+ name: string;
853
+ project_uuid?: string;
854
+ }
855
+ ```
856
+
857
+ #### `AuthProject`
858
+ Project information from project token.
859
+
860
+ ```typescript
861
+ interface AuthProject {
862
+ project_uuid: string;
863
+ enabled_services: string[];
864
+ secret_version: number;
865
+ token_id: string;
866
+ }
867
+ ```
868
+
869
+ #### `AuthenticatedRequest`
870
+ Extended Express request with authentication context.
871
+
872
+ ```typescript
873
+ interface AuthenticatedRequest extends Request {
874
+ user?: AuthUser;
875
+ project?: AuthProject;
876
+ }
877
+ ```
878
+
879
+ ### Utility Functions
880
+
881
+ #### `verifyJwtToken(token, projectUuid?)`
882
+ Manually verify JWT token.
883
+
884
+ ```typescript
885
+ const user = await verifyJwtToken(bearerToken, projectUuid);
886
+ if (user) {
887
+ console.log('Valid user:', user);
888
+ }
889
+ ```
890
+
891
+ #### `verifyProjectToken(token, serviceId)`
892
+ Manually verify project token.
893
+
894
+ ```typescript
895
+ const project = await verifyProjectToken(projectToken, 'helios');
896
+ if (project) {
897
+ console.log('Valid project:', project);
898
+ }
899
+ ```
900
+
901
+ ## 🤝 Contributing
902
+
903
+ We welcome contributions to improve the JWT authentication library! Please follow these steps:
904
+
905
+ ### Development Setup
906
+
907
+ 1. **Fork and Clone**
908
+ ```bash
909
+ git clone https://github.com/your-username/wazobia-platform.git
910
+ cd nx-msp/libs/node/jwt-auth
911
+ ```
912
+
913
+ 2. **Install Dependencies**
914
+ ```bash
915
+ npm install
916
+ ```
917
+
918
+ 3. **Setup Test Environment**
919
+ ```bash
920
+ cp .env.example .env.test
921
+ # Configure test Redis and Mercury URLs
922
+ ```
923
+
924
+ 4. **Run Tests**
925
+ ```bash
926
+ npm test
927
+ npm run test:integration
928
+ ```
929
+
930
+ ### Contribution Guidelines
931
+
932
+ - **Code Style**: Follow existing TypeScript/ESLint configuration
933
+ - **Testing**: Add comprehensive tests for new functionality
934
+ - **Documentation**: Update README and JSDoc comments
935
+ - **Security**: Follow security best practices, no hardcoded secrets
936
+ - **Performance**: Consider caching and Redis optimization
937
+
938
+ ### Pull Request Process
939
+
940
+ 1. Create feature branch: `git checkout -b feature/your-feature`
941
+ 2. Make changes with tests
942
+ 3. Run test suite: `npm run test:all`
943
+ 4. Update documentation
944
+ 5. Submit pull request with clear description
945
+
946
+ ### Security Issues
947
+
948
+ For security vulnerabilities, please email security@wazobia.com instead of creating public issues.
949
+
950
+ ## 📄 License
951
+
952
+ MIT License - see [LICENSE](LICENSE) file for details.
953
+
954
+ ## 📋 Changelog
955
+
956
+ ### Version 2.1.0 (Latest)
957
+ - ✅ Added comprehensive environment variable documentation
958
+ - ✅ Improved Redis connection management
959
+ - ✅ Enhanced error messages and debugging
960
+ - ✅ Added health check utilities
961
+ - ✅ Performance optimizations for JWKS caching
962
+
963
+ ### Version 2.0.0
964
+ - ✅ Major TypeScript rewrite
965
+ - ✅ Added NestJS guard support
966
+ - ✅ Implemented project authentication
967
+ - ✅ Added GraphQL resolver helpers
968
+ - ✅ Breaking: New environment variable names
969
+
970
+ ### Version 1.x.x
971
+ - ✅ Initial Express middleware implementation
972
+ - ✅ Basic JWT validation with JWKS
973
+ - ✅ Redis caching support
974
+
975
+ See [CHANGELOG.md](CHANGELOG.md) for complete version history.
976
+
977
+ ---
978
+
979
+ ## 🆘 Support
980
+
981
+ - **Documentation**: [Wazobia Platform Docs](https://docs.wazobia.com)
982
+ - **Issues**: [GitHub Issues](https://github.com/wazobia/platform/issues)
983
+ - **Slack**: `#authentication` channel
984
+ - **Email**: developers@wazobia.com
985
+
986
+ Built with ❤️ by the Wazobia Platform Team