@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
|
@@ -0,0 +1,383 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const middlewares_1 = require("../middlewares");
|
|
4
|
+
const jwt = require("jsonwebtoken");
|
|
5
|
+
const axios_1 = require("axios");
|
|
6
|
+
const redis_1 = require("redis");
|
|
7
|
+
// Mock dependencies
|
|
8
|
+
jest.mock('redis');
|
|
9
|
+
jest.mock('axios');
|
|
10
|
+
jest.mock('jsonwebtoken');
|
|
11
|
+
jest.mock('node-jose');
|
|
12
|
+
const mockRedis = {
|
|
13
|
+
sendCommand: jest.fn(),
|
|
14
|
+
connect: jest.fn(),
|
|
15
|
+
on: jest.fn(),
|
|
16
|
+
quit: jest.fn()
|
|
17
|
+
};
|
|
18
|
+
const mockAxios = axios_1.default;
|
|
19
|
+
const mockJwt = jwt;
|
|
20
|
+
const mockCreateClient = redis_1.createClient;
|
|
21
|
+
describe('ProjectAuthMiddleware', () => {
|
|
22
|
+
let middleware;
|
|
23
|
+
let mockReq;
|
|
24
|
+
let mockRes;
|
|
25
|
+
let mockNext;
|
|
26
|
+
beforeEach(() => {
|
|
27
|
+
// Reset mocks
|
|
28
|
+
jest.clearAllMocks();
|
|
29
|
+
// Setup Redis mock
|
|
30
|
+
mockCreateClient.mockReturnValue(mockRedis);
|
|
31
|
+
// Setup Express mocks with proper typing
|
|
32
|
+
mockReq = {
|
|
33
|
+
headers: {},
|
|
34
|
+
project: undefined,
|
|
35
|
+
// Add minimal Express Request properties that might be used
|
|
36
|
+
get: jest.fn(),
|
|
37
|
+
header: jest.fn(),
|
|
38
|
+
params: {},
|
|
39
|
+
query: {},
|
|
40
|
+
body: {},
|
|
41
|
+
url: '/',
|
|
42
|
+
method: 'GET'
|
|
43
|
+
};
|
|
44
|
+
mockRes = {
|
|
45
|
+
status: jest.fn().mockReturnThis(),
|
|
46
|
+
json: jest.fn().mockReturnThis(),
|
|
47
|
+
send: jest.fn().mockReturnThis(),
|
|
48
|
+
end: jest.fn().mockReturnThis()
|
|
49
|
+
};
|
|
50
|
+
mockNext = jest.fn();
|
|
51
|
+
// Environment variables
|
|
52
|
+
process.env.REDIS_URL = 'redis://localhost:6379';
|
|
53
|
+
process.env.MERCURY_BASE_URL = 'http://localhost:4000';
|
|
54
|
+
process.env.SERVICE_ID = 'test-service';
|
|
55
|
+
middleware = new middlewares_1.ProjectAuthMiddleware();
|
|
56
|
+
});
|
|
57
|
+
describe('Unit Tests - authenticate()', () => {
|
|
58
|
+
it('should reject requests without x-project-token header', async () => {
|
|
59
|
+
await middleware.authenticate(mockReq);
|
|
60
|
+
expect(mockRes.status).toHaveBeenCalledWith(401);
|
|
61
|
+
expect(mockRes.json).toHaveBeenCalledWith({
|
|
62
|
+
error: 'No project token provided',
|
|
63
|
+
required_header: 'x-project-token'
|
|
64
|
+
});
|
|
65
|
+
expect(mockNext).not.toHaveBeenCalled();
|
|
66
|
+
});
|
|
67
|
+
it('should reject requests with empty token', async () => {
|
|
68
|
+
mockReq.headers['x-project-token'] = '';
|
|
69
|
+
await middleware.authenticate(mockReq);
|
|
70
|
+
expect(mockRes.status).toHaveBeenCalledWith(401);
|
|
71
|
+
expect(mockRes.json).toHaveBeenCalledWith({
|
|
72
|
+
error: 'Empty project token'
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
it('should extract token from Bearer format', async () => {
|
|
76
|
+
const testToken = 'valid.jwt.token';
|
|
77
|
+
mockReq.headers['x-project-token'] = `Bearer ${testToken}`;
|
|
78
|
+
// Mock successful validation
|
|
79
|
+
const mockPayload = {
|
|
80
|
+
project_uuid: 'test-project',
|
|
81
|
+
enabled_services: ['test-service'],
|
|
82
|
+
secret_version: 1,
|
|
83
|
+
token_id: 'token-123',
|
|
84
|
+
exp: Math.floor(Date.now() / 1000) + 3600
|
|
85
|
+
};
|
|
86
|
+
const mockValidation = jest.spyOn(middleware, 'validateProjectToken');
|
|
87
|
+
mockValidation.mockResolvedValue({
|
|
88
|
+
isValid: true,
|
|
89
|
+
payload: mockPayload
|
|
90
|
+
});
|
|
91
|
+
await middleware.authenticate(mockReq);
|
|
92
|
+
expect(mockValidation).toHaveBeenCalledWith(testToken);
|
|
93
|
+
expect(mockNext).toHaveBeenCalled();
|
|
94
|
+
});
|
|
95
|
+
it('should reject when SERVICE_ID not configured', async () => {
|
|
96
|
+
delete process.env.SERVICE_ID;
|
|
97
|
+
mockReq.headers['x-project-token'] = 'Bearer valid.token';
|
|
98
|
+
await middleware.authenticate(mockReq);
|
|
99
|
+
expect(mockRes.status).toHaveBeenCalledWith(500);
|
|
100
|
+
expect(mockRes.json).toHaveBeenCalledWith({
|
|
101
|
+
error: 'Service ID not configured'
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
it('should reject when service not in enabled_services', async () => {
|
|
105
|
+
mockReq.headers['x-project-token'] = 'Bearer valid.token';
|
|
106
|
+
const mockPayload = {
|
|
107
|
+
project_uuid: 'test-project',
|
|
108
|
+
enabled_services: ['other-service'], // test-service not included
|
|
109
|
+
secret_version: 1,
|
|
110
|
+
token_id: 'token-123',
|
|
111
|
+
exp: Math.floor(Date.now() / 1000) + 3600
|
|
112
|
+
};
|
|
113
|
+
const mockValidation = jest.spyOn(middleware, 'validateProjectToken');
|
|
114
|
+
mockValidation.mockResolvedValue({
|
|
115
|
+
isValid: true,
|
|
116
|
+
payload: mockPayload
|
|
117
|
+
});
|
|
118
|
+
await middleware.authenticate(mockReq);
|
|
119
|
+
expect(mockRes.status).toHaveBeenCalledWith(403);
|
|
120
|
+
expect(mockRes.json).toHaveBeenCalledWith({
|
|
121
|
+
error: 'Service access denied',
|
|
122
|
+
service_id: 'test-service',
|
|
123
|
+
project: 'test-project',
|
|
124
|
+
enabled_services: ['other-service']
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
it('should inject project context on successful validation', async () => {
|
|
128
|
+
mockReq.headers['x-project-token'] = 'Bearer valid.token';
|
|
129
|
+
const mockPayload = {
|
|
130
|
+
project_uuid: 'test-project',
|
|
131
|
+
enabled_services: ['test-service'],
|
|
132
|
+
secret_version: 1,
|
|
133
|
+
token_id: 'token-123',
|
|
134
|
+
exp: Math.floor(Date.now() / 1000) + 3600
|
|
135
|
+
};
|
|
136
|
+
const mockValidation = jest.spyOn(middleware, 'validateProjectToken');
|
|
137
|
+
mockValidation.mockResolvedValue({
|
|
138
|
+
isValid: true,
|
|
139
|
+
payload: mockPayload
|
|
140
|
+
});
|
|
141
|
+
await middleware.authenticate(mockReq);
|
|
142
|
+
expect(mockReq.project).toEqual({
|
|
143
|
+
project_uuid: 'test-project',
|
|
144
|
+
enabled_services: ['test-service'],
|
|
145
|
+
secret_version: 1,
|
|
146
|
+
token_id: 'token-123',
|
|
147
|
+
expires_at: mockPayload.exp
|
|
148
|
+
});
|
|
149
|
+
expect(mockNext).toHaveBeenCalled();
|
|
150
|
+
});
|
|
151
|
+
});
|
|
152
|
+
describe('Unit Tests - validateProjectToken()', () => {
|
|
153
|
+
it('should validate JWT structure and check Redis cache', async () => {
|
|
154
|
+
const testToken = 'valid.jwt.token';
|
|
155
|
+
const mockPayload = {
|
|
156
|
+
project_uuid: 'test-project',
|
|
157
|
+
token_id: 'token-123',
|
|
158
|
+
enabled_services: ['test-service']
|
|
159
|
+
};
|
|
160
|
+
// Mock JWT verification
|
|
161
|
+
mockJwt.verify.mockReturnValue(mockPayload);
|
|
162
|
+
// Mock Redis EXISTS check
|
|
163
|
+
mockRedis.sendCommand.mockResolvedValue(1); // Token exists
|
|
164
|
+
// Mock getPublicKeyFromCache
|
|
165
|
+
const mockGetPublicKey = jest.spyOn(middleware, 'getPublicKeyFromCache');
|
|
166
|
+
mockGetPublicKey.mockResolvedValue('mock-public-key');
|
|
167
|
+
const result = await middleware.validateProjectToken(testToken);
|
|
168
|
+
expect(result.isValid).toBe(true);
|
|
169
|
+
expect(result.payload).toEqual(mockPayload);
|
|
170
|
+
expect(mockJwt.verify).toHaveBeenCalledWith(testToken, 'mock-public-key', { algorithms: ['RS256', 'RS512'], ignoreExpiration: false });
|
|
171
|
+
});
|
|
172
|
+
it('should return invalid when token revoked', async () => {
|
|
173
|
+
const testToken = 'revoked.jwt.token';
|
|
174
|
+
const mockPayload = {
|
|
175
|
+
project_uuid: 'test-project',
|
|
176
|
+
token_id: 'token-123',
|
|
177
|
+
enabled_services: ['test-service']
|
|
178
|
+
};
|
|
179
|
+
mockJwt.verify.mockReturnValue(mockPayload);
|
|
180
|
+
mockRedis.sendCommand.mockResolvedValue(0); // Token doesn't exist (revoked)
|
|
181
|
+
const mockGetPublicKey = jest.spyOn(middleware, 'getPublicKeyFromCache');
|
|
182
|
+
mockGetPublicKey.mockResolvedValue('mock-public-key');
|
|
183
|
+
const result = await middleware.validateProjectToken(testToken);
|
|
184
|
+
expect(result.isValid).toBe(false);
|
|
185
|
+
expect(result.error).toBe('Token has been revoked');
|
|
186
|
+
});
|
|
187
|
+
});
|
|
188
|
+
describe('Unit Tests - JWKS Caching', () => {
|
|
189
|
+
it('should fetch and cache JWKS on cache miss', async () => {
|
|
190
|
+
const mockJwksResponse = {
|
|
191
|
+
data: {
|
|
192
|
+
keys: [
|
|
193
|
+
{ kid: 'key-1', kty: 'RSA', use: 'sig' }
|
|
194
|
+
]
|
|
195
|
+
}
|
|
196
|
+
};
|
|
197
|
+
// Mock Redis cache miss
|
|
198
|
+
mockRedis.sendCommand.mockResolvedValueOnce(null); // GET returns null
|
|
199
|
+
// Mock axios response
|
|
200
|
+
mockAxios.get.mockResolvedValue(mockJwksResponse);
|
|
201
|
+
// Mock jose keystore
|
|
202
|
+
const mockKeyStore = {
|
|
203
|
+
get: jest.fn().mockReturnValue({
|
|
204
|
+
toPEM: jest.fn().mockReturnValue('mock-pem-key')
|
|
205
|
+
})
|
|
206
|
+
};
|
|
207
|
+
const jose = require('node-jose');
|
|
208
|
+
jose.JWK.asKeyStore = jest.fn().mockResolvedValue(mockKeyStore);
|
|
209
|
+
const testToken = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6ImtleS0xIn0.payload.signature';
|
|
210
|
+
const result = await middleware.getPublicKeyFromCache(testToken);
|
|
211
|
+
expect(mockAxios.get).toHaveBeenCalledWith('http://localhost:4000/auth/projects/auth/project/.well-known/jwks.json', expect.any(Object));
|
|
212
|
+
expect(mockRedis.sendCommand).toHaveBeenCalledWith([
|
|
213
|
+
'SETEX',
|
|
214
|
+
'project_jwks_cache',
|
|
215
|
+
'18000',
|
|
216
|
+
JSON.stringify(mockJwksResponse.data)
|
|
217
|
+
]);
|
|
218
|
+
expect(result).toBe('mock-pem-key');
|
|
219
|
+
});
|
|
220
|
+
it('should use cached JWKS on cache hit', async () => {
|
|
221
|
+
const mockCachedJwks = JSON.stringify({
|
|
222
|
+
keys: [{ kid: 'key-1', kty: 'RSA', use: 'sig' }]
|
|
223
|
+
});
|
|
224
|
+
// Mock Redis cache hit
|
|
225
|
+
mockRedis.sendCommand.mockResolvedValueOnce(mockCachedJwks);
|
|
226
|
+
const mockKeyStore = {
|
|
227
|
+
get: jest.fn().mockReturnValue({
|
|
228
|
+
toPEM: jest.fn().mockReturnValue('cached-pem-key')
|
|
229
|
+
})
|
|
230
|
+
};
|
|
231
|
+
const jose = require('node-jose');
|
|
232
|
+
jose.JWK.asKeyStore = jest.fn().mockResolvedValue(mockKeyStore);
|
|
233
|
+
const testToken = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6ImtleS0xIn0.payload.signature';
|
|
234
|
+
const result = await middleware.getPublicKeyFromCache(testToken);
|
|
235
|
+
expect(mockAxios.get).not.toHaveBeenCalled(); // No HTTP call
|
|
236
|
+
expect(result).toBe('cached-pem-key');
|
|
237
|
+
});
|
|
238
|
+
});
|
|
239
|
+
});
|
|
240
|
+
// Integration Tests
|
|
241
|
+
describe('ProjectAuthMiddleware Integration Tests', () => {
|
|
242
|
+
let middleware;
|
|
243
|
+
let realRedis;
|
|
244
|
+
beforeAll(async () => {
|
|
245
|
+
// Use real Redis for integration tests (or Redis test container)
|
|
246
|
+
process.env.REDIS_URL = process.env.TEST_REDIS_URL || 'redis://localhost:6380';
|
|
247
|
+
process.env.MERCURY_BASE_URL = 'http://localhost:4000';
|
|
248
|
+
process.env.SERVICE_ID = 'integration-test-service';
|
|
249
|
+
});
|
|
250
|
+
beforeEach(async () => {
|
|
251
|
+
jest.restoreAllMocks();
|
|
252
|
+
middleware = new middlewares_1.ProjectAuthMiddleware();
|
|
253
|
+
// Clear Redis cache
|
|
254
|
+
const { createClient } = require('redis');
|
|
255
|
+
realRedis = createClient({ url: process.env.REDIS_URL });
|
|
256
|
+
await realRedis.connect();
|
|
257
|
+
await realRedis.flushAll();
|
|
258
|
+
});
|
|
259
|
+
afterEach(async () => {
|
|
260
|
+
if (realRedis) {
|
|
261
|
+
await realRedis.quit();
|
|
262
|
+
}
|
|
263
|
+
await middleware.cleanup();
|
|
264
|
+
});
|
|
265
|
+
it('should perform end-to-end authentication with real token', async () => {
|
|
266
|
+
// This test requires:
|
|
267
|
+
// 1. Mercury service running
|
|
268
|
+
// 2. Valid project token generated
|
|
269
|
+
// 3. Real Redis instance
|
|
270
|
+
const realProjectToken = process.env.TEST_PROJECT_TOKEN;
|
|
271
|
+
if (!realProjectToken) {
|
|
272
|
+
console.warn('Skipping integration test - TEST_PROJECT_TOKEN not provided');
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
const mockReq = {
|
|
276
|
+
headers: {
|
|
277
|
+
'x-project-token': `Bearer ${realProjectToken}`
|
|
278
|
+
},
|
|
279
|
+
project: undefined,
|
|
280
|
+
get: jest.fn(),
|
|
281
|
+
header: jest.fn(),
|
|
282
|
+
params: {},
|
|
283
|
+
query: {},
|
|
284
|
+
body: {},
|
|
285
|
+
url: '/',
|
|
286
|
+
method: 'GET'
|
|
287
|
+
};
|
|
288
|
+
const mockRes = {
|
|
289
|
+
status: jest.fn().mockReturnThis(),
|
|
290
|
+
json: jest.fn().mockReturnThis(),
|
|
291
|
+
send: jest.fn().mockReturnThis(),
|
|
292
|
+
end: jest.fn().mockReturnThis()
|
|
293
|
+
};
|
|
294
|
+
const mockNext = jest.fn();
|
|
295
|
+
await middleware.authenticate(mockReq);
|
|
296
|
+
if (mockNext.mock.calls.length > 0) {
|
|
297
|
+
// Authentication successful
|
|
298
|
+
expect(mockReq.project).toBeDefined();
|
|
299
|
+
expect(mockReq.project.project_uuid).toBeDefined();
|
|
300
|
+
expect(mockReq.project.enabled_services).toBeInstanceOf(Array);
|
|
301
|
+
}
|
|
302
|
+
else {
|
|
303
|
+
// Authentication failed - check response
|
|
304
|
+
expect(mockRes.status).toHaveBeenCalledWith(expect.any(Number));
|
|
305
|
+
}
|
|
306
|
+
});
|
|
307
|
+
it('should cache JWKS and reuse for subsequent requests', async () => {
|
|
308
|
+
// Mock successful JWKS response
|
|
309
|
+
const mockJwksResponse = {
|
|
310
|
+
data: {
|
|
311
|
+
keys: [
|
|
312
|
+
{
|
|
313
|
+
kid: 'test-key-1',
|
|
314
|
+
kty: 'RSA',
|
|
315
|
+
use: 'sig',
|
|
316
|
+
n: 'mock-modulus',
|
|
317
|
+
e: 'AQAB'
|
|
318
|
+
}
|
|
319
|
+
]
|
|
320
|
+
}
|
|
321
|
+
};
|
|
322
|
+
mockAxios.get.mockResolvedValue(mockJwksResponse);
|
|
323
|
+
// First request should fetch JWKS
|
|
324
|
+
const testToken = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6InRlc3Qta2V5LTEifQ.payload.signature';
|
|
325
|
+
try {
|
|
326
|
+
await middleware.getPublicKeyFromCache(testToken);
|
|
327
|
+
}
|
|
328
|
+
catch (error) {
|
|
329
|
+
// Expected to fail due to mocked JWT, but JWKS should be cached
|
|
330
|
+
}
|
|
331
|
+
// Verify JWKS was cached
|
|
332
|
+
const cachedJwks = await realRedis.get('project_jwks_cache');
|
|
333
|
+
expect(cachedJwks).toBeDefined();
|
|
334
|
+
expect(JSON.parse(cachedJwks)).toEqual(mockJwksResponse.data);
|
|
335
|
+
// Second request should use cache
|
|
336
|
+
mockAxios.get.mockClear();
|
|
337
|
+
try {
|
|
338
|
+
await middleware.getPublicKeyFromCache(testToken);
|
|
339
|
+
}
|
|
340
|
+
catch (error) {
|
|
341
|
+
// Expected to fail due to mocked JWT
|
|
342
|
+
}
|
|
343
|
+
// Should not have made another HTTP call
|
|
344
|
+
expect(mockAxios.get).not.toHaveBeenCalled();
|
|
345
|
+
});
|
|
346
|
+
it('should handle Mercury service unavailable', async () => {
|
|
347
|
+
mockAxios.get.mockRejectedValue({
|
|
348
|
+
code: 'ECONNREFUSED',
|
|
349
|
+
message: 'Connection refused'
|
|
350
|
+
});
|
|
351
|
+
const testToken = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6InRlc3Qta2V5LTEifQ.payload.signature';
|
|
352
|
+
await expect(middleware.getPublicKeyFromCache(testToken))
|
|
353
|
+
.rejects
|
|
354
|
+
.toThrow('Mercury service unavailable');
|
|
355
|
+
});
|
|
356
|
+
});
|
|
357
|
+
// Performance Tests
|
|
358
|
+
describe('ProjectAuthMiddleware Performance Tests', () => {
|
|
359
|
+
let middleware;
|
|
360
|
+
beforeAll(() => {
|
|
361
|
+
middleware = new middlewares_1.ProjectAuthMiddleware();
|
|
362
|
+
});
|
|
363
|
+
it('should validate tokens within performance threshold', async () => {
|
|
364
|
+
// Mock fast Redis responses
|
|
365
|
+
mockRedis.sendCommand
|
|
366
|
+
.mockResolvedValueOnce('cached-jwks') // JWKS cache hit
|
|
367
|
+
.mockResolvedValueOnce(1); // Token exists
|
|
368
|
+
const mockPayload = {
|
|
369
|
+
project_uuid: 'perf-test',
|
|
370
|
+
token_id: 'perf-token',
|
|
371
|
+
enabled_services: ['test-service']
|
|
372
|
+
};
|
|
373
|
+
mockJwt.verify.mockReturnValue(mockPayload);
|
|
374
|
+
const mockGetPublicKey = jest.spyOn(middleware, 'getPublicKeyFromCache');
|
|
375
|
+
mockGetPublicKey.mockResolvedValue('mock-key');
|
|
376
|
+
const startTime = Date.now();
|
|
377
|
+
await middleware.validateProjectToken('test.token.here');
|
|
378
|
+
const duration = Date.now() - startTime;
|
|
379
|
+
// Should complete validation in under 50ms for cached scenarios
|
|
380
|
+
expect(duration).toBeLessThan(50);
|
|
381
|
+
});
|
|
382
|
+
});
|
|
383
|
+
//# sourceMappingURL=middleware.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"middleware.test.js","sourceRoot":"","sources":["../../src/test/middleware.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { Request } from 'express';
|
|
2
|
+
export interface AuthenticatedRequest extends Request {
|
|
3
|
+
project?: ProjectContext;
|
|
4
|
+
user?: {
|
|
5
|
+
uuid: string;
|
|
6
|
+
email: string;
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
export interface GqlContext {
|
|
10
|
+
req: AuthenticatedRequest;
|
|
11
|
+
}
|
|
12
|
+
export interface JwtPayload {
|
|
13
|
+
sub?: {
|
|
14
|
+
uuid: string;
|
|
15
|
+
email: string;
|
|
16
|
+
name: string;
|
|
17
|
+
};
|
|
18
|
+
project_uuid?: string;
|
|
19
|
+
type: string;
|
|
20
|
+
iss: string;
|
|
21
|
+
aud: string;
|
|
22
|
+
exp: number;
|
|
23
|
+
nbf: number;
|
|
24
|
+
iat: number;
|
|
25
|
+
jti?: string;
|
|
26
|
+
}
|
|
27
|
+
export interface AuthUser {
|
|
28
|
+
uuid: string;
|
|
29
|
+
email: string;
|
|
30
|
+
name: string;
|
|
31
|
+
}
|
|
32
|
+
export interface ProjectContext {
|
|
33
|
+
project_uuid: string;
|
|
34
|
+
enabled_services: string[];
|
|
35
|
+
secret_version: number;
|
|
36
|
+
token_id: string;
|
|
37
|
+
expires_at: number;
|
|
38
|
+
}
|
|
39
|
+
export interface ProjectTokenPayload {
|
|
40
|
+
project_uuid: string;
|
|
41
|
+
secret_version: number;
|
|
42
|
+
enabled_services: string[];
|
|
43
|
+
token_id: string;
|
|
44
|
+
iat: number;
|
|
45
|
+
exp: number;
|
|
46
|
+
type: 'project';
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=jwt-payload.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jwt-payload.d.ts","sourceRoot":"","sources":["../../src/types/jwt-payload.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,MAAM,WAAW,oBAAqB,SAAQ,OAAO;IACnD,OAAO,CAAC,EAAE,cAAc,CAAC;IACzB,IAAI,CAAC,EAAE;QACL,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,EAAE,MAAM,CAAC;KACf,CAAC;CACH;AACD,MAAM,WAAW,UAAU;IACzB,GAAG,EAAE,oBAAoB,CAAC;CAC3B;AAED,MAAM,WAAW,UAAU;IACzB,GAAG,CAAC,EAAE;QACJ,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,EAAE,MAAM,CAAC;QACd,IAAI,EAAE,MAAM,CAAC;KACd,CAAC;IACF,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,cAAc;IAC7B,YAAY,EAAE,MAAM,CAAC;IACrB,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,cAAc,EAAE,MAAM,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,mBAAmB;IAClC,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,SAAS,CAAC;CACjB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jwt-payload.js","sourceRoot":"","sources":["../../src/types/jwt-payload.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { RedisClientType } from 'redis';
|
|
2
|
+
declare class RedisConnectionManager {
|
|
3
|
+
private static instance;
|
|
4
|
+
private constructor();
|
|
5
|
+
static getInstance(): Promise<RedisClientType>;
|
|
6
|
+
static closeConnection(): Promise<void>;
|
|
7
|
+
}
|
|
8
|
+
export default RedisConnectionManager;
|
|
9
|
+
//# sourceMappingURL=redis.connection.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redis.connection.d.ts","sourceRoot":"","sources":["../../src/utils/redis.connection.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAgB,MAAM,OAAO,CAAC;AAEtD,cAAM,sBAAsB;IAC1B,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAgC;IAEvD,OAAO;WAEa,WAAW,IAAI,OAAO,CAAC,eAAe,CAAC;WAgBvC,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC;CAMrD;AAED,eAAe,sBAAsB,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const redis_1 = require("redis");
|
|
4
|
+
class RedisConnectionManager {
|
|
5
|
+
constructor() { }
|
|
6
|
+
static async getInstance() {
|
|
7
|
+
if (!RedisConnectionManager.instance) {
|
|
8
|
+
RedisConnectionManager.instance = (0, redis_1.createClient)({
|
|
9
|
+
url: process.env.REDIS_URL,
|
|
10
|
+
});
|
|
11
|
+
RedisConnectionManager.instance.on('error', (error) => {
|
|
12
|
+
throw Error(`Redis connection error: ${error}`);
|
|
13
|
+
});
|
|
14
|
+
await RedisConnectionManager.instance.connect();
|
|
15
|
+
}
|
|
16
|
+
return RedisConnectionManager.instance;
|
|
17
|
+
}
|
|
18
|
+
static async closeConnection() {
|
|
19
|
+
if (RedisConnectionManager.instance) {
|
|
20
|
+
await RedisConnectionManager.instance.quit();
|
|
21
|
+
RedisConnectionManager.instance = null;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
RedisConnectionManager.instance = null;
|
|
26
|
+
exports.default = RedisConnectionManager;
|
|
27
|
+
//# sourceMappingURL=redis.connection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redis.connection.js","sourceRoot":"","sources":["../../src/utils/redis.connection.ts"],"names":[],"mappings":";;AAAA,iCAAsD;AAEtD,MAAM,sBAAsB;IAG1B,gBAAuB,CAAC;IAEjB,MAAM,CAAC,KAAK,CAAC,WAAW;QAC7B,IAAI,CAAC,sBAAsB,CAAC,QAAQ,EAAE,CAAC;YACrC,sBAAsB,CAAC,QAAQ,GAAG,IAAA,oBAAY,EAAC;gBAC7C,GAAG,EAAU,OAAO,CAAC,GAAG,CAAC,SAAS;aACnC,CAAC,CAAC;YAEH,sBAAsB,CAAC,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,KAAY,EAAE,EAAE;gBAC3D,MAAM,KAAK,CAAC,2BAA2B,KAAK,EAAE,CAAC,CAAC;YAClD,CAAC,CAAC,CAAC;YAEH,MAAM,sBAAsB,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC;QAClD,CAAC;QAED,OAAO,sBAAsB,CAAC,QAAQ,CAAC;IACzC,CAAC;IAEM,MAAM,CAAC,KAAK,CAAC,eAAe;QACjC,IAAI,sBAAsB,CAAC,QAAQ,EAAE,CAAC;YACpC,MAAM,sBAAsB,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;YAC7C,sBAAsB,CAAC,QAAQ,GAAG,IAAI,CAAC;QACzC,CAAC;IACH,CAAC;;AAzBc,+BAAQ,GAA2B,IAAI,CAAC;AA4BzD,kBAAe,sBAAsB,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@wazobiatech/auth-middleware",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Framework-agnostic JWT authentication library for Wazobia microservices platform",
|
|
5
|
+
"main": "dist/src/index.js",
|
|
6
|
+
"types": "dist/src/index.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist/**/*"
|
|
9
|
+
],
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "tsc",
|
|
12
|
+
"test": "jest",
|
|
13
|
+
"prepublishOnly": "npm run build"
|
|
14
|
+
},
|
|
15
|
+
"keywords": [
|
|
16
|
+
"jwt",
|
|
17
|
+
"authentication",
|
|
18
|
+
"express",
|
|
19
|
+
"nestjs",
|
|
20
|
+
"microservices"
|
|
21
|
+
],
|
|
22
|
+
"author": "Platform Team",
|
|
23
|
+
"license": "MIT",
|
|
24
|
+
"peerDependencies": {
|
|
25
|
+
"@nestjs/common": "^10.0.0",
|
|
26
|
+
"@nestjs/passport": "^10.0.0",
|
|
27
|
+
"@nestjs/graphql": "^12.0.8",
|
|
28
|
+
"express": "^4.18.0",
|
|
29
|
+
"fastify": "^4.0.0",
|
|
30
|
+
"ioredis": "^5.0.0",
|
|
31
|
+
"passport-jwt": "^4.0.0"
|
|
32
|
+
},
|
|
33
|
+
"peerDependenciesMeta": {
|
|
34
|
+
"express": {
|
|
35
|
+
"optional": true
|
|
36
|
+
},
|
|
37
|
+
"fastify": {
|
|
38
|
+
"optional": true
|
|
39
|
+
},
|
|
40
|
+
"@nestjs/common": {
|
|
41
|
+
"optional": true
|
|
42
|
+
},
|
|
43
|
+
"@nestjs/passport": {
|
|
44
|
+
"optional": true
|
|
45
|
+
},
|
|
46
|
+
"@nestjs/graphql": {
|
|
47
|
+
"optional": true
|
|
48
|
+
},
|
|
49
|
+
"passport-jwt": {
|
|
50
|
+
"optional": true
|
|
51
|
+
},
|
|
52
|
+
"ioredis": {
|
|
53
|
+
"optional": true
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
"exports": {
|
|
57
|
+
".": {
|
|
58
|
+
"types": "./dist/src/index.d.ts",
|
|
59
|
+
"default": "./dist/src/index.js"
|
|
60
|
+
},
|
|
61
|
+
"./nestjs": {
|
|
62
|
+
"types": "./dist/src/nestjs/index.d.ts",
|
|
63
|
+
"default": "./dist/src/nestjs/index.js"
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
"typesVersions": {
|
|
67
|
+
"*": {
|
|
68
|
+
"nestjs": ["dist/src/nestjs/index.d.ts"]
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
"dependencies": {
|
|
72
|
+
"@nestjs/common": "^11.1.5",
|
|
73
|
+
"@nestjs/passport": "^11.0.5",
|
|
74
|
+
"axios": "^1.6.0",
|
|
75
|
+
"express": "^5.1.0",
|
|
76
|
+
"fastify": "^5.4.0",
|
|
77
|
+
"fastify-plugin": "^5.0.1",
|
|
78
|
+
"redis": "^5.1.1",
|
|
79
|
+
"jsonwebtoken": "^9.0.0",
|
|
80
|
+
"node-jose": "^2.2.0",
|
|
81
|
+
"passport-jwt": "^4.0.1",
|
|
82
|
+
"passport": "^0.7.0",
|
|
83
|
+
"graphql": "^16.11.0",
|
|
84
|
+
"dotenv": "^16.3.1"
|
|
85
|
+
},
|
|
86
|
+
"devDependencies": {
|
|
87
|
+
"@types/express": "^5.0.3",
|
|
88
|
+
"@types/jest": "^29.0.0",
|
|
89
|
+
"@types/jsonwebtoken": "^9.0.0",
|
|
90
|
+
"@types/node": "^20.0.0",
|
|
91
|
+
"@types/node-jose": "^1.1.13",
|
|
92
|
+
"@types/passport-jwt": "^4.0.1",
|
|
93
|
+
"@nestjs/testing": "^11.1.5",
|
|
94
|
+
"@nestjs/graphql": "^12.0.8",
|
|
95
|
+
"jest": "^29.0.0",
|
|
96
|
+
"ts-jest": "^29.0.0",
|
|
97
|
+
"typescript": "^5.0.0"
|
|
98
|
+
}
|
|
99
|
+
}
|