@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.
- package/README.md +986 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +25 -0
- package/dist/index.js.map +1 -0
- package/dist/middlewares/express.helper.d.ts +4 -0
- package/dist/middlewares/express.helper.d.ts.map +1 -0
- package/dist/middlewares/express.helper.js +31 -0
- package/dist/middlewares/express.helper.js.map +1 -0
- package/dist/middlewares/gql.helper.d.ts +14 -0
- package/dist/middlewares/gql.helper.d.ts.map +1 -0
- package/dist/middlewares/gql.helper.js +82 -0
- package/dist/middlewares/gql.helper.js.map +1 -0
- package/dist/middlewares/index.d.ts +5 -0
- package/dist/middlewares/index.d.ts.map +1 -0
- package/dist/middlewares/index.js +13 -0
- package/dist/middlewares/index.js.map +1 -0
- package/dist/middlewares/jwt.guard.d.ts +16 -0
- package/dist/middlewares/jwt.guard.d.ts.map +1 -0
- package/dist/middlewares/jwt.guard.js +336 -0
- package/dist/middlewares/jwt.guard.js.map +1 -0
- package/dist/middlewares/project.guard.d.ts +49 -0
- package/dist/middlewares/project.guard.d.ts.map +1 -0
- package/dist/middlewares/project.guard.js +310 -0
- package/dist/middlewares/project.guard.js.map +1 -0
- package/dist/nestjs/decorators/auth.decorator.d.ts +2 -0
- package/dist/nestjs/decorators/auth.decorator.d.ts.map +1 -0
- package/dist/nestjs/decorators/auth.decorator.js +10 -0
- package/dist/nestjs/decorators/auth.decorator.js.map +1 -0
- package/dist/nestjs/decorators/current-user.decorator.d.ts +2 -0
- package/dist/nestjs/decorators/current-user.decorator.d.ts.map +1 -0
- package/dist/nestjs/decorators/current-user.decorator.js +18 -0
- package/dist/nestjs/decorators/current-user.decorator.js.map +1 -0
- package/dist/nestjs/guards/jwt-guard.d.ts +8 -0
- package/dist/nestjs/guards/jwt-guard.d.ts.map +1 -0
- package/dist/nestjs/guards/jwt-guard.js +23 -0
- package/dist/nestjs/guards/jwt-guard.js.map +1 -0
- package/dist/nestjs/guards/project.guard.d.ts +45 -0
- package/dist/nestjs/guards/project.guard.d.ts.map +1 -0
- package/dist/nestjs/guards/project.guard.js +352 -0
- package/dist/nestjs/guards/project.guard.js.map +1 -0
- package/dist/nestjs/index.d.ts +6 -0
- package/dist/nestjs/index.d.ts.map +1 -0
- package/dist/nestjs/index.js +14 -0
- package/dist/nestjs/index.js.map +1 -0
- package/dist/nestjs/jwt-auth.module.d.ts +3 -0
- package/dist/nestjs/jwt-auth.module.d.ts.map +1 -0
- package/dist/nestjs/jwt-auth.module.js +25 -0
- package/dist/nestjs/jwt-auth.module.js.map +1 -0
- package/dist/nestjs/strategies/jwt-strategy.d.ts +23 -0
- package/dist/nestjs/strategies/jwt-strategy.d.ts.map +1 -0
- package/dist/nestjs/strategies/jwt-strategy.js +381 -0
- package/dist/nestjs/strategies/jwt-strategy.js.map +1 -0
- package/dist/test/middleware.test.d.ts +2 -0
- package/dist/test/middleware.test.d.ts.map +1 -0
- package/dist/test/middleware.test.js +383 -0
- package/dist/test/middleware.test.js.map +1 -0
- package/dist/types/jwt-payload.d.ts +48 -0
- package/dist/types/jwt-payload.d.ts.map +1 -0
- package/dist/types/jwt-payload.js +3 -0
- package/dist/types/jwt-payload.js.map +1 -0
- package/dist/utils/redis.connection.d.ts +9 -0
- package/dist/utils/redis.connection.d.ts.map +1 -0
- package/dist/utils/redis.connection.js +27 -0
- package/dist/utils/redis.connection.js.map +1 -0
- 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
|