@geekmidas/auth 9.0.2 → 10.0.0-alpha.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 (101) hide show
  1. package/dist/cacheTokenStorage-B7sOoysu.d.cts.map +1 -1
  2. package/dist/{cacheTokenStorage-_tq4Kmhc.d.mts → cacheTokenStorage-DaqxdNxI.d.mts} +1 -1
  3. package/dist/cacheTokenStorage-DaqxdNxI.d.mts.map +1 -0
  4. package/dist/cacheTokenStorage.d.mts +1 -1
  5. package/dist/client.d.mts +1 -1
  6. package/dist/cookies-Bc6gUjb6.cjs +30 -0
  7. package/dist/cookies-Bc6gUjb6.cjs.map +1 -0
  8. package/dist/cookies-C80f8JtE.mjs +24 -0
  9. package/dist/cookies-C80f8JtE.mjs.map +1 -0
  10. package/dist/cookies.cjs +3 -0
  11. package/dist/cookies.d.cts +14 -0
  12. package/dist/cookies.d.cts.map +1 -0
  13. package/dist/cookies.d.mts +14 -0
  14. package/dist/cookies.d.mts.map +1 -0
  15. package/dist/cookies.mjs +3 -0
  16. package/dist/hono/jwt.cjs +4 -7
  17. package/dist/hono/jwt.cjs.map +1 -1
  18. package/dist/hono/jwt.d.cts.map +1 -1
  19. package/dist/hono/jwt.d.mts +1 -1
  20. package/dist/hono/jwt.d.mts.map +1 -1
  21. package/dist/hono/jwt.mjs +5 -7
  22. package/dist/hono/jwt.mjs.map +1 -1
  23. package/dist/hono/oidc.cjs +4 -7
  24. package/dist/hono/oidc.cjs.map +1 -1
  25. package/dist/hono/oidc.d.cts.map +1 -1
  26. package/dist/hono/oidc.d.mts +2 -2
  27. package/dist/hono/oidc.d.mts.map +1 -1
  28. package/dist/hono/oidc.mjs +5 -7
  29. package/dist/hono/oidc.mjs.map +1 -1
  30. package/dist/index.cjs +1 -1
  31. package/dist/index.d.mts +2 -2
  32. package/dist/index.mjs +1 -1
  33. package/dist/{jwt-D88cPJyT.mjs → jwt-bZR2_t8F.mjs} +1 -1
  34. package/dist/{jwt-D88cPJyT.mjs.map → jwt-bZR2_t8F.mjs.map} +1 -1
  35. package/dist/{jwt-Bo_eACEi.cjs → jwt-clq6I6vG.cjs} +1 -1
  36. package/dist/{jwt-Bo_eACEi.cjs.map → jwt-clq6I6vG.cjs.map} +1 -1
  37. package/dist/{jwt-BqLlRkw-.d.mts → jwt-kejix7rd.d.mts} +1 -1
  38. package/dist/{jwt-BqLlRkw-.d.mts.map → jwt-kejix7rd.d.mts.map} +1 -1
  39. package/dist/jwt.cjs +1 -1
  40. package/dist/jwt.d.mts +1 -1
  41. package/dist/jwt.mjs +1 -1
  42. package/dist/lambda/jwt.cjs +4 -5
  43. package/dist/lambda/jwt.cjs.map +1 -1
  44. package/dist/lambda/jwt.d.cts.map +1 -1
  45. package/dist/lambda/jwt.d.mts +1 -1
  46. package/dist/lambda/jwt.d.mts.map +1 -1
  47. package/dist/lambda/jwt.mjs +5 -5
  48. package/dist/lambda/jwt.mjs.map +1 -1
  49. package/dist/lambda/oidc.cjs +4 -5
  50. package/dist/lambda/oidc.cjs.map +1 -1
  51. package/dist/lambda/oidc.d.cts.map +1 -1
  52. package/dist/lambda/oidc.d.mts +2 -2
  53. package/dist/lambda/oidc.d.mts.map +1 -1
  54. package/dist/lambda/oidc.mjs +5 -5
  55. package/dist/lambda/oidc.mjs.map +1 -1
  56. package/dist/{oidc-KA30gMlx.mjs → oidc-BYHREHir.mjs} +1 -1
  57. package/dist/{oidc-KA30gMlx.mjs.map → oidc-BYHREHir.mjs.map} +1 -1
  58. package/dist/{oidc-DTRgBBl6.d.mts → oidc-Ca7GYwmM.d.mts} +2 -2
  59. package/dist/{oidc-DTRgBBl6.d.mts.map → oidc-Ca7GYwmM.d.mts.map} +1 -1
  60. package/dist/{oidc-C0KyYaAK.cjs → oidc-jdMfVyyC.cjs} +1 -1
  61. package/dist/{oidc-C0KyYaAK.cjs.map → oidc-jdMfVyyC.cjs.map} +1 -1
  62. package/dist/oidc.cjs +1 -1
  63. package/dist/oidc.d.mts +2 -2
  64. package/dist/oidc.mjs +1 -1
  65. package/dist/server.cjs +1 -1
  66. package/dist/server.d.mts +2 -2
  67. package/dist/server.mjs +1 -1
  68. package/dist/{tokenManager-Ci2Tgxp8.mjs → tokenManager-BbylTW7F.mjs} +1 -1
  69. package/dist/{tokenManager-Ci2Tgxp8.mjs.map → tokenManager-BbylTW7F.mjs.map} +1 -1
  70. package/dist/{tokenManager-RrwjL0y-.d.mts → tokenManager-CosB7J0i.d.mts} +1 -1
  71. package/dist/{tokenManager-RrwjL0y-.d.mts.map → tokenManager-CosB7J0i.d.mts.map} +1 -1
  72. package/dist/{tokenManager-CvEMgxOp.cjs → tokenManager-PQ-OI_NU.cjs} +1 -1
  73. package/dist/{tokenManager-CvEMgxOp.cjs.map → tokenManager-PQ-OI_NU.cjs.map} +1 -1
  74. package/dist/tokenManager.cjs +1 -1
  75. package/dist/tokenManager.d.mts +1 -1
  76. package/dist/tokenManager.mjs +1 -1
  77. package/package.json +6 -3
  78. package/CHANGELOG.md +0 -60
  79. package/dist/cacheTokenStorage-_tq4Kmhc.d.mts.map +0 -1
  80. package/src/__tests__/cacheTokenStorage.spec.ts +0 -213
  81. package/src/__tests__/client.spec.ts +0 -465
  82. package/src/__tests__/hono-jwt.spec.ts +0 -232
  83. package/src/__tests__/hono-oidc.spec.ts +0 -605
  84. package/src/__tests__/jwt.spec.ts +0 -197
  85. package/src/__tests__/lambda-jwt.spec.ts +0 -278
  86. package/src/__tests__/lambda-oidc.spec.ts +0 -624
  87. package/src/__tests__/oidc.spec.ts +0 -405
  88. package/src/__tests__/tokenManager.spec.ts +0 -259
  89. package/src/cacheTokenStorage.ts +0 -43
  90. package/src/client.ts +0 -220
  91. package/src/hono/jwt.ts +0 -142
  92. package/src/hono/oidc.ts +0 -170
  93. package/src/index.ts +0 -3
  94. package/src/jwt.ts +0 -106
  95. package/src/lambda/jwt.ts +0 -210
  96. package/src/lambda/oidc.ts +0 -203
  97. package/src/oidc.ts +0 -156
  98. package/src/server.ts +0 -8
  99. package/src/tokenManager.ts +0 -106
  100. package/tsconfig.json +0 -10
  101. package/tsdown.config.ts +0 -3
@@ -1,465 +0,0 @@
1
- import { InMemoryCache } from '@geekmidas/cache/memory';
2
- import { HttpResponse, http } from 'msw';
3
- import { setupServer } from 'msw/node';
4
- import {
5
- afterAll,
6
- afterEach,
7
- beforeAll,
8
- beforeEach,
9
- describe,
10
- expect,
11
- it,
12
- } from 'vitest';
13
- import {
14
- CacheTokenStorage,
15
- LocalStorageTokenStorage,
16
- MemoryTokenStorage,
17
- TokenClient,
18
- type TokenStorage,
19
- } from '../client.ts';
20
-
21
- // Mock localStorage for browser environment simulation
22
- const mockLocalStorage = {
23
- getItem: (key: string) => {
24
- return mockLocalStorage._storage[key] || null;
25
- },
26
- setItem: (key: string, value: string) => {
27
- mockLocalStorage._storage[key] = value;
28
- },
29
- removeItem: (key: string) => {
30
- delete mockLocalStorage._storage[key];
31
- },
32
- _storage: {} as Record<string, string>,
33
- _reset: () => {
34
- mockLocalStorage._storage = {};
35
- },
36
- };
37
-
38
- Object.defineProperty(global, 'localStorage', {
39
- value: mockLocalStorage,
40
- });
41
-
42
- // Setup MSW server for API testing
43
- const server = setupServer(
44
- http.post('https://auth.toolbox.dev/auth/refresh', () => {
45
- return HttpResponse.json({
46
- accessToken: 'new-access-token',
47
- refreshToken: 'new-refresh-token',
48
- });
49
- }),
50
- );
51
-
52
- describe('LocalStorageTokenStorage', () => {
53
- let storage: LocalStorageTokenStorage;
54
-
55
- beforeEach(() => {
56
- mockLocalStorage._reset();
57
- storage = new LocalStorageTokenStorage();
58
- });
59
-
60
- describe('token lifecycle', () => {
61
- it('should return null when tokens do not exist', () => {
62
- expect(storage.getAccessToken()).toBeNull();
63
- expect(storage.getRefreshToken()).toBeNull();
64
- });
65
-
66
- it('should clear both tokens', () => {
67
- storage.setAccessToken('access-token');
68
- storage.setRefreshToken('refresh-token');
69
-
70
- storage.clearTokens();
71
-
72
- expect(storage.getAccessToken()).toBeNull();
73
- expect(storage.getRefreshToken()).toBeNull();
74
- });
75
- });
76
- });
77
-
78
- describe('MemoryTokenStorage', () => {
79
- let storage: MemoryTokenStorage;
80
-
81
- beforeEach(() => {
82
- storage = new MemoryTokenStorage();
83
- });
84
-
85
- describe('token lifecycle', () => {
86
- it('should store and retrieve tokens in memory', () => {
87
- storage.setAccessToken('memory-access-token');
88
- storage.setRefreshToken('memory-refresh-token');
89
-
90
- expect(storage.getAccessToken()).toBe('memory-access-token');
91
- expect(storage.getRefreshToken()).toBe('memory-refresh-token');
92
- });
93
-
94
- it('should return null for unset tokens', () => {
95
- expect(storage.getAccessToken()).toBeNull();
96
- expect(storage.getRefreshToken()).toBeNull();
97
- });
98
-
99
- it('should clear all tokens', () => {
100
- storage.setAccessToken('access-token');
101
- storage.setRefreshToken('refresh-token');
102
-
103
- storage.clearTokens();
104
-
105
- expect(storage.getAccessToken()).toBeNull();
106
- expect(storage.getRefreshToken()).toBeNull();
107
- });
108
-
109
- it('should maintain separate instances', () => {
110
- const storage1 = new MemoryTokenStorage();
111
- const storage2 = new MemoryTokenStorage();
112
-
113
- storage1.setAccessToken('token1');
114
- storage2.setAccessToken('token2');
115
-
116
- expect(storage1.getAccessToken()).toBe('token1');
117
- expect(storage2.getAccessToken()).toBe('token2');
118
- });
119
- });
120
- });
121
-
122
- describe('CacheTokenStorage', () => {
123
- let storage: CacheTokenStorage;
124
- let cache: InMemoryCache<string>;
125
-
126
- beforeEach(() => {
127
- cache = new InMemoryCache<string>();
128
- storage = new CacheTokenStorage(cache);
129
- });
130
-
131
- describe('token lifecycle with cache', () => {
132
- it('should store and retrieve tokens via cache', async () => {
133
- await storage.setAccessToken('cache-access-token');
134
- await storage.setRefreshToken('cache-refresh-token');
135
-
136
- const accessToken = await storage.getAccessToken();
137
- const refreshToken = await storage.getRefreshToken();
138
-
139
- expect(accessToken).toBe('cache-access-token');
140
- expect(refreshToken).toBe('cache-refresh-token');
141
- });
142
-
143
- it('should handle TTL for tokens', async () => {
144
- await storage.setAccessToken('ttl-access-token', 3600);
145
- await storage.setRefreshToken('ttl-refresh-token', 7200);
146
-
147
- const accessToken = await storage.getAccessToken();
148
- const refreshToken = await storage.getRefreshToken();
149
-
150
- expect(accessToken).toBe('ttl-access-token');
151
- expect(refreshToken).toBe('ttl-refresh-token');
152
- });
153
-
154
- it('should clear both tokens from cache', async () => {
155
- await storage.setAccessToken('access-token');
156
- await storage.setRefreshToken('refresh-token');
157
-
158
- await storage.clearTokens();
159
-
160
- const accessToken = await storage.getAccessToken();
161
- const refreshToken = await storage.getRefreshToken();
162
-
163
- expect(accessToken).toBeNull();
164
- expect(refreshToken).toBeNull();
165
- });
166
- });
167
- });
168
-
169
- describe('TokenClient', () => {
170
- let client: TokenClient;
171
- let storage: TokenStorage;
172
-
173
- beforeAll(() => server.listen());
174
- afterEach(() => server.resetHandlers());
175
- afterAll(() => server.close());
176
-
177
- beforeEach(() => {
178
- storage = new MemoryTokenStorage();
179
- client = new TokenClient({
180
- storage,
181
- refreshEndpoint: 'https://auth.toolbox.dev/auth/refresh',
182
- });
183
- });
184
-
185
- describe('token management', () => {
186
- it('should store and retrieve tokens', async () => {
187
- await client.setTokens('access-token', 'refresh-token');
188
-
189
- const accessToken = await client.getAccessToken();
190
- const refreshToken = await client.getRefreshToken();
191
-
192
- expect(accessToken).toBe('access-token');
193
- expect(refreshToken).toBe('refresh-token');
194
- });
195
-
196
- it('should store tokens with TTL', async () => {
197
- await client.setTokens('access-token', 'refresh-token', 900, 7200);
198
-
199
- const accessToken = await client.getAccessToken();
200
- const refreshToken = await client.getRefreshToken();
201
-
202
- expect(accessToken).toBe('access-token');
203
- expect(refreshToken).toBe('refresh-token');
204
- });
205
-
206
- it('should store only access token when refresh not provided', async () => {
207
- await client.setTokens('access-only-token');
208
-
209
- const accessToken = await client.getAccessToken();
210
- const refreshToken = await client.getRefreshToken();
211
-
212
- expect(accessToken).toBe('access-only-token');
213
- expect(refreshToken).toBeNull();
214
- });
215
-
216
- it('should clear all tokens', async () => {
217
- await client.setTokens('access-token', 'refresh-token');
218
- await client.clearTokens();
219
-
220
- const accessToken = await client.getAccessToken();
221
- const refreshToken = await client.getRefreshToken();
222
-
223
- expect(accessToken).toBeNull();
224
- expect(refreshToken).toBeNull();
225
- });
226
- });
227
-
228
- describe('token validation', () => {
229
- it('should identify valid tokens correctly', () => {
230
- const validPayload = { exp: Math.floor(Date.now() / 1000) + 3600 };
231
- const validToken = `header.${btoa(JSON.stringify(validPayload))}.signature`;
232
-
233
- expect(client.isTokenExpired(validToken)).toBe(false);
234
-
235
- const expiration = client.getTokenExpiration(validToken);
236
- expect(expiration).toBeInstanceOf(Date);
237
- expect(expiration?.getTime()).toBe(validPayload.exp * 1000);
238
- });
239
-
240
- it('should identify expired tokens correctly', () => {
241
- const expiredPayload = { exp: Math.floor(Date.now() / 1000) - 3600 };
242
- const expiredToken = `header.${btoa(JSON.stringify(expiredPayload))}.signature`;
243
-
244
- expect(client.isTokenExpired(expiredToken)).toBe(true);
245
-
246
- const expiration = client.getTokenExpiration(expiredToken);
247
- expect(expiration).toBeInstanceOf(Date);
248
- expect(expiration?.getTime()).toBe(expiredPayload.exp * 1000);
249
- });
250
-
251
- it('should handle malformed tokens gracefully', () => {
252
- expect(client.isTokenExpired('malformed-token')).toBe(true);
253
- expect(client.isTokenExpired('')).toBe(true);
254
- expect(client.isTokenExpired('not.a.token')).toBe(true);
255
-
256
- expect(client.getTokenExpiration('malformed-token')).toBeNull();
257
- expect(client.getTokenExpiration('')).toBeNull();
258
- expect(client.getTokenExpiration('not.a.token')).toBeNull();
259
- });
260
- });
261
-
262
- describe('API integration with MSW', () => {
263
- it('should refresh tokens via API successfully', async () => {
264
- await storage.setRefreshToken('valid-refresh-token');
265
-
266
- const success = await client.refreshTokens();
267
-
268
- expect(success).toBe(true);
269
- expect(await storage.getAccessToken()).toBe('new-access-token');
270
- expect(await storage.getRefreshToken()).toBe('new-refresh-token');
271
- });
272
-
273
- it('should handle API errors gracefully', async () => {
274
- server.use(
275
- http.post('https://auth.toolbox.dev/auth/refresh', () => {
276
- return new HttpResponse(null, { status: 401 });
277
- }),
278
- );
279
-
280
- await storage.setRefreshToken('invalid-refresh-token');
281
-
282
- const success = await client.refreshTokens();
283
-
284
- expect(success).toBe(false);
285
- expect(await storage.getAccessToken()).toBeNull();
286
- expect(await storage.getRefreshToken()).toBeNull();
287
- });
288
-
289
- it('should handle network errors gracefully', async () => {
290
- server.use(
291
- http.post('https://auth.toolbox.dev/auth/refresh', () => {
292
- return HttpResponse.error();
293
- }),
294
- );
295
-
296
- await storage.setRefreshToken('valid-refresh-token');
297
-
298
- const success = await client.refreshTokens();
299
-
300
- expect(success).toBe(false);
301
- expect(await storage.getAccessToken()).toBeNull();
302
- expect(await storage.getRefreshToken()).toBeNull();
303
- });
304
-
305
- it('should fail when no refresh token available', async () => {
306
- const success = await client.refreshTokens();
307
-
308
- expect(success).toBe(false);
309
- });
310
-
311
- it('should fail when refresh endpoint not configured', async () => {
312
- const clientWithoutEndpoint = new TokenClient({ storage });
313
- await storage.setRefreshToken('valid-refresh-token');
314
-
315
- const success = await clientWithoutEndpoint.refreshTokens();
316
-
317
- expect(success).toBe(false);
318
- });
319
- });
320
-
321
- describe('callback handling', () => {
322
- it('should call onTokenRefresh callback on success', async () => {
323
- let callbackData: any = null;
324
- const clientWithCallback = new TokenClient({
325
- storage,
326
- refreshEndpoint: 'https://auth.toolbox.dev/auth/refresh',
327
- onTokenRefresh: (data) => {
328
- callbackData = data;
329
- },
330
- });
331
-
332
- await storage.setRefreshToken('valid-refresh-token');
333
-
334
- await clientWithCallback.refreshTokens();
335
-
336
- expect(callbackData).toEqual({
337
- accessToken: 'new-access-token',
338
- refreshToken: 'new-refresh-token',
339
- });
340
- });
341
-
342
- it('should call onTokenExpired callback on failure', async () => {
343
- let callbackCalled = false;
344
- const clientWithCallback = new TokenClient({
345
- storage,
346
- refreshEndpoint: 'https://auth.toolbox.dev/auth/refresh',
347
- onTokenExpired: () => {
348
- callbackCalled = true;
349
- },
350
- });
351
-
352
- server.use(
353
- http.post('https://auth.toolbox.dev/auth/refresh', () => {
354
- return new HttpResponse(null, { status: 401 });
355
- }),
356
- );
357
-
358
- await storage.setRefreshToken('invalid-refresh-token');
359
-
360
- await clientWithCallback.refreshTokens();
361
-
362
- expect(callbackCalled).toBe(true);
363
- });
364
- });
365
-
366
- describe('getValidAccessToken workflow', () => {
367
- it('should return valid token without refresh', async () => {
368
- const validPayload = { exp: Math.floor(Date.now() / 1000) + 3600 };
369
- const validToken = `header.${btoa(JSON.stringify(validPayload))}.signature`;
370
-
371
- await storage.setAccessToken(validToken);
372
-
373
- const token = await client.getValidAccessToken();
374
-
375
- expect(token).toBe(validToken);
376
- });
377
-
378
- it('should return null when no token available', async () => {
379
- const token = await client.getValidAccessToken();
380
-
381
- expect(token).toBeNull();
382
- });
383
-
384
- it('should refresh expired token automatically', async () => {
385
- const expiredPayload = { exp: Math.floor(Date.now() / 1000) - 3600 };
386
- const expiredToken = `header.${btoa(JSON.stringify(expiredPayload))}.signature`;
387
-
388
- await storage.setAccessToken(expiredToken);
389
- await storage.setRefreshToken('valid-refresh-token');
390
-
391
- const token = await client.getValidAccessToken();
392
-
393
- expect(token).toBe('new-access-token');
394
- });
395
-
396
- it('should return null when refresh fails', async () => {
397
- server.use(
398
- http.post('https://auth.toolbox.dev/auth/refresh', () => {
399
- return new HttpResponse(null, { status: 401 });
400
- }),
401
- );
402
-
403
- const expiredPayload = { exp: Math.floor(Date.now() / 1000) - 3600 };
404
- const expiredToken = `header.${btoa(JSON.stringify(expiredPayload))}.signature`;
405
-
406
- await storage.setAccessToken(expiredToken);
407
- await storage.setRefreshToken('invalid-refresh-token');
408
-
409
- const token = await client.getValidAccessToken();
410
-
411
- expect(token).toBeNull();
412
- });
413
- });
414
-
415
- describe('authorization headers', () => {
416
- it('should create headers with current token', async () => {
417
- await storage.setAccessToken('current-token');
418
-
419
- const headers = await client.createAuthHeaders();
420
-
421
- expect(headers).toEqual({
422
- Authorization: 'Bearer current-token',
423
- });
424
- });
425
-
426
- it('should return empty headers when no token', async () => {
427
- const headers = await client.createAuthHeaders();
428
-
429
- expect(headers).toEqual({});
430
- });
431
-
432
- it('should create headers with valid token', async () => {
433
- const validPayload = { exp: Math.floor(Date.now() / 1000) + 3600 };
434
- const validToken = `header.${btoa(JSON.stringify(validPayload))}.signature`;
435
-
436
- await storage.setAccessToken(validToken);
437
-
438
- const headers = await client.createValidAuthHeaders();
439
-
440
- expect(headers).toEqual({
441
- Authorization: `Bearer ${validToken}`,
442
- });
443
- });
444
-
445
- it('should create headers with refreshed token', async () => {
446
- const expiredPayload = { exp: Math.floor(Date.now() / 1000) - 3600 };
447
- const expiredToken = `header.${btoa(JSON.stringify(expiredPayload))}.signature`;
448
-
449
- await storage.setAccessToken(expiredToken);
450
- await storage.setRefreshToken('valid-refresh-token');
451
-
452
- const headers = await client.createValidAuthHeaders();
453
-
454
- expect(headers).toEqual({
455
- Authorization: 'Bearer new-access-token',
456
- });
457
- });
458
-
459
- it('should return empty headers when no valid token available', async () => {
460
- const headers = await client.createValidAuthHeaders();
461
-
462
- expect(headers).toEqual({});
463
- });
464
- });
465
- });
@@ -1,232 +0,0 @@
1
- import { Hono } from 'hono';
2
- import * as jose from 'jose';
3
- import { describe, expect, it } from 'vitest';
4
- import { JwtMiddleware } from '../hono/jwt';
5
-
6
- const TEST_SECRET = 'super-secret-key-for-testing-only-32chars';
7
-
8
- async function createTestToken(
9
- claims: Record<string, unknown> = {},
10
- secret = TEST_SECRET,
11
- ) {
12
- const secretKey = new TextEncoder().encode(secret);
13
- return await new jose.SignJWT({ sub: 'user-123', ...claims })
14
- .setProtectedHeader({ alg: 'HS256' })
15
- .setIssuedAt()
16
- .setExpirationTime('1h')
17
- .sign(secretKey);
18
- }
19
-
20
- describe('JwtMiddleware', () => {
21
- describe('handler()', () => {
22
- it('should allow request with valid token', async () => {
23
- const app = new Hono();
24
- const jwt = new JwtMiddleware({ config: { secret: TEST_SECRET } });
25
-
26
- app.use('/*', jwt.handler());
27
- app.get('/test', (c) => {
28
- const claims = c.get('jwtClaims');
29
- return c.json({ userId: claims.sub });
30
- });
31
-
32
- const token = await createTestToken();
33
- const res = await app.request('/test', {
34
- headers: { Authorization: `Bearer ${token}` },
35
- });
36
-
37
- expect(res.status).toBe(200);
38
- const body = await res.json();
39
- expect(body.userId).toBe('user-123');
40
- });
41
-
42
- it('should reject request without token', async () => {
43
- const app = new Hono();
44
- const jwt = new JwtMiddleware({ config: { secret: TEST_SECRET } });
45
-
46
- app.use('/*', jwt.handler());
47
- app.get('/test', (c) => c.json({ ok: true }));
48
-
49
- const res = await app.request('/test');
50
-
51
- expect(res.status).toBe(401);
52
- });
53
-
54
- it('should reject request with invalid token', async () => {
55
- const app = new Hono();
56
- const jwt = new JwtMiddleware({ config: { secret: TEST_SECRET } });
57
-
58
- app.use('/*', jwt.handler());
59
- app.get('/test', (c) => c.json({ ok: true }));
60
-
61
- const res = await app.request('/test', {
62
- headers: { Authorization: 'Bearer invalid-token' },
63
- });
64
-
65
- expect(res.status).toBe(401);
66
- });
67
-
68
- it('should extract token from cookie when configured', async () => {
69
- const app = new Hono();
70
- const jwt = new JwtMiddleware({
71
- config: { secret: TEST_SECRET },
72
- extraction: { cookieName: 'auth_token' },
73
- });
74
-
75
- app.use('/*', jwt.handler());
76
- app.get('/test', (c) => {
77
- const claims = c.get('jwtClaims');
78
- return c.json({ userId: claims.sub });
79
- });
80
-
81
- const token = await createTestToken();
82
- const res = await app.request('/test', {
83
- headers: { Cookie: `auth_token=${token}` },
84
- });
85
-
86
- expect(res.status).toBe(200);
87
- });
88
-
89
- it('should use custom context key', async () => {
90
- const app = new Hono();
91
- const jwt = new JwtMiddleware({
92
- config: { secret: TEST_SECRET },
93
- contextKey: 'user',
94
- });
95
-
96
- app.use('/*', jwt.handler());
97
- app.get('/test', (c) => {
98
- const claims = c.get('user');
99
- return c.json({ userId: claims.sub });
100
- });
101
-
102
- const token = await createTestToken();
103
- const res = await app.request('/test', {
104
- headers: { Authorization: `Bearer ${token}` },
105
- });
106
-
107
- expect(res.status).toBe(200);
108
- });
109
-
110
- it('should use custom error handler', async () => {
111
- const app = new Hono();
112
- const jwt = new JwtMiddleware({
113
- config: { secret: TEST_SECRET },
114
- onError: (c) => c.json({ custom: 'error' }, 403),
115
- });
116
-
117
- app.use('/*', jwt.handler());
118
- app.get('/test', (c) => c.json({ ok: true }));
119
-
120
- const res = await app.request('/test');
121
-
122
- expect(res.status).toBe(403);
123
- const body = await res.json();
124
- expect(body.custom).toBe('error');
125
- });
126
-
127
- it('should transform claims', async () => {
128
- const app = new Hono();
129
- const jwt = new JwtMiddleware({
130
- config: { secret: TEST_SECRET },
131
- transformClaims: (claims) => ({
132
- ...claims,
133
- transformed: true,
134
- }),
135
- });
136
-
137
- app.use('/*', jwt.handler());
138
- app.get('/test', (c) => {
139
- const claims = c.get('jwtClaims');
140
- return c.json({ transformed: claims.transformed });
141
- });
142
-
143
- const token = await createTestToken();
144
- const res = await app.request('/test', {
145
- headers: { Authorization: `Bearer ${token}` },
146
- });
147
-
148
- expect(res.status).toBe(200);
149
- const body = await res.json();
150
- expect(body.transformed).toBe(true);
151
- });
152
-
153
- it('should set jwtToken in context', async () => {
154
- const app = new Hono();
155
- const jwt = new JwtMiddleware({ config: { secret: TEST_SECRET } });
156
-
157
- app.use('/*', jwt.handler());
158
- app.get('/test', (c) => {
159
- const token = c.get('jwtToken');
160
- return c.json({ hasToken: !!token });
161
- });
162
-
163
- const token = await createTestToken();
164
- const res = await app.request('/test', {
165
- headers: { Authorization: `Bearer ${token}` },
166
- });
167
-
168
- expect(res.status).toBe(200);
169
- const body = await res.json();
170
- expect(body.hasToken).toBe(true);
171
- });
172
- });
173
-
174
- describe('optional()', () => {
175
- it('should allow request without token', async () => {
176
- const app = new Hono();
177
- const jwt = new JwtMiddleware({ config: { secret: TEST_SECRET } });
178
-
179
- app.use('/*', jwt.optional());
180
- app.get('/test', (c) => {
181
- const claims = c.get('jwtClaims');
182
- return c.json({ authenticated: !!claims });
183
- });
184
-
185
- const res = await app.request('/test');
186
-
187
- expect(res.status).toBe(200);
188
- const body = await res.json();
189
- expect(body.authenticated).toBe(false);
190
- });
191
-
192
- it('should set claims when valid token provided', async () => {
193
- const app = new Hono();
194
- const jwt = new JwtMiddleware({ config: { secret: TEST_SECRET } });
195
-
196
- app.use('/*', jwt.optional());
197
- app.get('/test', (c) => {
198
- const claims = c.get('jwtClaims');
199
- return c.json({ authenticated: !!claims, userId: claims?.sub });
200
- });
201
-
202
- const token = await createTestToken();
203
- const res = await app.request('/test', {
204
- headers: { Authorization: `Bearer ${token}` },
205
- });
206
-
207
- expect(res.status).toBe(200);
208
- const body = await res.json();
209
- expect(body.authenticated).toBe(true);
210
- expect(body.userId).toBe('user-123');
211
- });
212
-
213
- it('should not set claims for invalid token', async () => {
214
- const app = new Hono();
215
- const jwt = new JwtMiddleware({ config: { secret: TEST_SECRET } });
216
-
217
- app.use('/*', jwt.optional());
218
- app.get('/test', (c) => {
219
- const claims = c.get('jwtClaims');
220
- return c.json({ authenticated: !!claims });
221
- });
222
-
223
- const res = await app.request('/test', {
224
- headers: { Authorization: 'Bearer invalid-token' },
225
- });
226
-
227
- expect(res.status).toBe(200);
228
- const body = await res.json();
229
- expect(body.authenticated).toBe(false);
230
- });
231
- });
232
- });