@geekmidas/auth 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (116) hide show
  1. package/dist/{cacheTokenStorage-Ca05vf3T.mjs → cacheTokenStorage-16NE8Cd9.mjs} +3 -3
  2. package/dist/cacheTokenStorage-16NE8Cd9.mjs.map +1 -0
  3. package/dist/{cacheTokenStorage-BzBRJfd-.d.mts → cacheTokenStorage-B7sOoysu.d.cts} +8 -6
  4. package/dist/cacheTokenStorage-B7sOoysu.d.cts.map +1 -0
  5. package/dist/{cacheTokenStorage-CvptztkW.cjs → cacheTokenStorage-CEpMniTi.cjs} +3 -3
  6. package/dist/cacheTokenStorage-CEpMniTi.cjs.map +1 -0
  7. package/dist/{cacheTokenStorage-yNUpDD8W.d.cts → cacheTokenStorage-_tq4Kmhc.d.mts} +8 -6
  8. package/dist/cacheTokenStorage-_tq4Kmhc.d.mts.map +1 -0
  9. package/dist/cacheTokenStorage.cjs +1 -1
  10. package/dist/cacheTokenStorage.d.cts +1 -1
  11. package/dist/cacheTokenStorage.d.mts +1 -1
  12. package/dist/cacheTokenStorage.mjs +1 -1
  13. package/dist/{client-DaiUm0UZ.cjs → client-BPl_mMvb.cjs} +14 -8
  14. package/dist/client-BPl_mMvb.cjs.map +1 -0
  15. package/dist/{client-DjNZS6vZ.mjs → client-eidYNJSH.mjs} +14 -8
  16. package/dist/client-eidYNJSH.mjs.map +1 -0
  17. package/dist/client.cjs +2 -2
  18. package/dist/client.d.cts +1 -1
  19. package/dist/client.d.mts +1 -1
  20. package/dist/client.mjs +2 -2
  21. package/dist/hono/jwt.cjs +1 -1
  22. package/dist/hono/jwt.cjs.map +1 -1
  23. package/dist/hono/jwt.d.cts +2 -1
  24. package/dist/hono/jwt.d.cts.map +1 -0
  25. package/dist/hono/jwt.d.mts +2 -1
  26. package/dist/hono/jwt.d.mts.map +1 -0
  27. package/dist/hono/jwt.mjs +1 -1
  28. package/dist/hono/jwt.mjs.map +1 -1
  29. package/dist/hono/oidc.cjs +1 -1
  30. package/dist/hono/oidc.cjs.map +1 -1
  31. package/dist/hono/oidc.d.cts +3 -2
  32. package/dist/hono/oidc.d.cts.map +1 -0
  33. package/dist/hono/oidc.d.mts +3 -2
  34. package/dist/hono/oidc.d.mts.map +1 -0
  35. package/dist/hono/oidc.mjs +1 -1
  36. package/dist/hono/oidc.mjs.map +1 -1
  37. package/dist/index.cjs +3 -3
  38. package/dist/index.d.cts +2 -2
  39. package/dist/index.d.mts +2 -2
  40. package/dist/index.mjs +3 -3
  41. package/dist/{jwt-DF9kFbmh.d.cts → jwt-3eIuY2dg.d.cts} +2 -1
  42. package/dist/jwt-3eIuY2dg.d.cts.map +1 -0
  43. package/dist/jwt-Bo_eACEi.cjs.map +1 -1
  44. package/dist/{jwt-DH8CJ2xC.d.mts → jwt-BqLlRkw-.d.mts} +2 -1
  45. package/dist/jwt-BqLlRkw-.d.mts.map +1 -0
  46. package/dist/jwt-D88cPJyT.mjs.map +1 -1
  47. package/dist/jwt.d.cts +1 -1
  48. package/dist/jwt.d.mts +1 -1
  49. package/dist/lambda/jwt.cjs +2 -2
  50. package/dist/lambda/jwt.cjs.map +1 -1
  51. package/dist/lambda/jwt.d.cts +2 -1
  52. package/dist/lambda/jwt.d.cts.map +1 -0
  53. package/dist/lambda/jwt.d.mts +2 -1
  54. package/dist/lambda/jwt.d.mts.map +1 -0
  55. package/dist/lambda/jwt.mjs +2 -2
  56. package/dist/lambda/jwt.mjs.map +1 -1
  57. package/dist/lambda/oidc.cjs +2 -2
  58. package/dist/lambda/oidc.cjs.map +1 -1
  59. package/dist/lambda/oidc.d.cts +3 -2
  60. package/dist/lambda/oidc.d.cts.map +1 -0
  61. package/dist/lambda/oidc.d.mts +3 -2
  62. package/dist/lambda/oidc.d.mts.map +1 -0
  63. package/dist/lambda/oidc.mjs +2 -2
  64. package/dist/lambda/oidc.mjs.map +1 -1
  65. package/dist/oidc-C0KyYaAK.cjs.map +1 -1
  66. package/dist/{oidc-CKOGLxjV.d.mts → oidc-ChA17wLB.d.cts} +3 -2
  67. package/dist/oidc-ChA17wLB.d.cts.map +1 -0
  68. package/dist/{oidc-DDLIB5gb.d.cts → oidc-DTRgBBl6.d.mts} +3 -2
  69. package/dist/oidc-DTRgBBl6.d.mts.map +1 -0
  70. package/dist/oidc-KA30gMlx.mjs.map +1 -1
  71. package/dist/oidc.d.cts +2 -2
  72. package/dist/oidc.d.mts +2 -2
  73. package/dist/server.cjs +2 -2
  74. package/dist/server.d.cts +2 -2
  75. package/dist/server.d.mts +2 -2
  76. package/dist/server.mjs +2 -2
  77. package/dist/{tokenManager--Q93eNYr.d.mts → tokenManager-CL3yE06D.d.cts} +2 -1
  78. package/dist/tokenManager-CL3yE06D.d.cts.map +1 -0
  79. package/dist/{tokenManager-BVXxfHRa.mjs → tokenManager-Ci2Tgxp8.mjs} +5 -3
  80. package/dist/tokenManager-Ci2Tgxp8.mjs.map +1 -0
  81. package/dist/{tokenManager-EPmwgai2.cjs → tokenManager-CvEMgxOp.cjs} +5 -3
  82. package/dist/tokenManager-CvEMgxOp.cjs.map +1 -0
  83. package/dist/{tokenManager-H6-lWEah.d.cts → tokenManager-RrwjL0y-.d.mts} +2 -1
  84. package/dist/tokenManager-RrwjL0y-.d.mts.map +1 -0
  85. package/dist/tokenManager.cjs +1 -1
  86. package/dist/tokenManager.d.cts +1 -1
  87. package/dist/tokenManager.d.mts +1 -1
  88. package/dist/tokenManager.mjs +1 -1
  89. package/package.json +3 -3
  90. package/src/__tests__/cacheTokenStorage.spec.ts +148 -148
  91. package/src/__tests__/client.spec.ts +339 -339
  92. package/src/__tests__/hono-jwt.spec.ts +219 -219
  93. package/src/__tests__/hono-oidc.spec.ts +560 -560
  94. package/src/__tests__/jwt.spec.ts +150 -127
  95. package/src/__tests__/lambda-jwt.spec.ts +205 -205
  96. package/src/__tests__/lambda-oidc.spec.ts +580 -579
  97. package/src/__tests__/oidc.spec.ts +365 -365
  98. package/src/__tests__/tokenManager.spec.ts +254 -254
  99. package/src/cacheTokenStorage.ts +32 -32
  100. package/src/client.ts +199 -190
  101. package/src/hono/jwt.ts +111 -111
  102. package/src/hono/oidc.ts +131 -131
  103. package/src/index.ts +2 -2
  104. package/src/jwt.ts +57 -57
  105. package/src/lambda/jwt.ts +170 -170
  106. package/src/lambda/oidc.ts +165 -165
  107. package/src/oidc.ts +121 -121
  108. package/src/server.ts +6 -7
  109. package/src/tokenManager.ts +89 -87
  110. package/tsconfig.json +10 -0
  111. package/dist/cacheTokenStorage-Ca05vf3T.mjs.map +0 -1
  112. package/dist/cacheTokenStorage-CvptztkW.cjs.map +0 -1
  113. package/dist/client-DaiUm0UZ.cjs.map +0 -1
  114. package/dist/client-DjNZS6vZ.mjs.map +0 -1
  115. package/dist/tokenManager-BVXxfHRa.mjs.map +0 -1
  116. package/dist/tokenManager-EPmwgai2.cjs.map +0 -1
@@ -1,465 +1,465 @@
1
1
  import { InMemoryCache } from '@geekmidas/cache/memory';
2
- import { http, HttpResponse } from 'msw';
2
+ import { HttpResponse, http } from 'msw';
3
3
  import { setupServer } from 'msw/node';
4
4
  import {
5
- afterAll,
6
- afterEach,
7
- beforeAll,
8
- beforeEach,
9
- describe,
10
- expect,
11
- it,
5
+ afterAll,
6
+ afterEach,
7
+ beforeAll,
8
+ beforeEach,
9
+ describe,
10
+ expect,
11
+ it,
12
12
  } from 'vitest';
13
13
  import {
14
- CacheTokenStorage,
15
- LocalStorageTokenStorage,
16
- MemoryTokenStorage,
17
- TokenClient,
18
- type TokenStorage,
14
+ CacheTokenStorage,
15
+ LocalStorageTokenStorage,
16
+ MemoryTokenStorage,
17
+ TokenClient,
18
+ type TokenStorage,
19
19
  } from '../client.ts';
20
20
 
21
21
  // Mock localStorage for browser environment simulation
22
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
- },
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
36
  };
37
37
 
38
38
  Object.defineProperty(global, 'localStorage', {
39
- value: mockLocalStorage,
39
+ value: mockLocalStorage,
40
40
  });
41
41
 
42
42
  // Setup MSW server for API testing
43
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
- }),
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
50
  );
51
51
 
52
52
  describe('LocalStorageTokenStorage', () => {
53
- let storage: LocalStorageTokenStorage;
53
+ let storage: LocalStorageTokenStorage;
54
54
 
55
- beforeEach(() => {
56
- mockLocalStorage._reset();
57
- storage = new LocalStorageTokenStorage();
58
- });
55
+ beforeEach(() => {
56
+ mockLocalStorage._reset();
57
+ storage = new LocalStorageTokenStorage();
58
+ });
59
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
- });
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
65
 
66
- it('should clear both tokens', () => {
67
- storage.setAccessToken('access-token');
68
- storage.setRefreshToken('refresh-token');
66
+ it('should clear both tokens', () => {
67
+ storage.setAccessToken('access-token');
68
+ storage.setRefreshToken('refresh-token');
69
69
 
70
- storage.clearTokens();
70
+ storage.clearTokens();
71
71
 
72
- expect(storage.getAccessToken()).toBeNull();
73
- expect(storage.getRefreshToken()).toBeNull();
74
- });
75
- });
72
+ expect(storage.getAccessToken()).toBeNull();
73
+ expect(storage.getRefreshToken()).toBeNull();
74
+ });
75
+ });
76
76
  });
77
77
 
78
78
  describe('MemoryTokenStorage', () => {
79
- let storage: MemoryTokenStorage;
79
+ let storage: MemoryTokenStorage;
80
80
 
81
- beforeEach(() => {
82
- storage = new MemoryTokenStorage();
83
- });
81
+ beforeEach(() => {
82
+ storage = new MemoryTokenStorage();
83
+ });
84
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');
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
89
 
90
- expect(storage.getAccessToken()).toBe('memory-access-token');
91
- expect(storage.getRefreshToken()).toBe('memory-refresh-token');
92
- });
90
+ expect(storage.getAccessToken()).toBe('memory-access-token');
91
+ expect(storage.getRefreshToken()).toBe('memory-refresh-token');
92
+ });
93
93
 
94
- it('should return null for unset tokens', () => {
95
- expect(storage.getAccessToken()).toBeNull();
96
- expect(storage.getRefreshToken()).toBeNull();
97
- });
94
+ it('should return null for unset tokens', () => {
95
+ expect(storage.getAccessToken()).toBeNull();
96
+ expect(storage.getRefreshToken()).toBeNull();
97
+ });
98
98
 
99
- it('should clear all tokens', () => {
100
- storage.setAccessToken('access-token');
101
- storage.setRefreshToken('refresh-token');
99
+ it('should clear all tokens', () => {
100
+ storage.setAccessToken('access-token');
101
+ storage.setRefreshToken('refresh-token');
102
102
 
103
- storage.clearTokens();
103
+ storage.clearTokens();
104
104
 
105
- expect(storage.getAccessToken()).toBeNull();
106
- expect(storage.getRefreshToken()).toBeNull();
107
- });
105
+ expect(storage.getAccessToken()).toBeNull();
106
+ expect(storage.getRefreshToken()).toBeNull();
107
+ });
108
108
 
109
- it('should maintain separate instances', () => {
110
- const storage1 = new MemoryTokenStorage();
111
- const storage2 = new MemoryTokenStorage();
109
+ it('should maintain separate instances', () => {
110
+ const storage1 = new MemoryTokenStorage();
111
+ const storage2 = new MemoryTokenStorage();
112
112
 
113
- storage1.setAccessToken('token1');
114
- storage2.setAccessToken('token2');
113
+ storage1.setAccessToken('token1');
114
+ storage2.setAccessToken('token2');
115
115
 
116
- expect(storage1.getAccessToken()).toBe('token1');
117
- expect(storage2.getAccessToken()).toBe('token2');
118
- });
119
- });
116
+ expect(storage1.getAccessToken()).toBe('token1');
117
+ expect(storage2.getAccessToken()).toBe('token2');
118
+ });
119
+ });
120
120
  });
121
121
 
122
122
  describe('CacheTokenStorage', () => {
123
- let storage: CacheTokenStorage;
124
- let cache: InMemoryCache<string>;
123
+ let storage: CacheTokenStorage;
124
+ let cache: InMemoryCache<string>;
125
125
 
126
- beforeEach(() => {
127
- cache = new InMemoryCache<string>();
128
- storage = new CacheTokenStorage(cache);
129
- });
126
+ beforeEach(() => {
127
+ cache = new InMemoryCache<string>();
128
+ storage = new CacheTokenStorage(cache);
129
+ });
130
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');
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
135
 
136
- const accessToken = await storage.getAccessToken();
137
- const refreshToken = await storage.getRefreshToken();
136
+ const accessToken = await storage.getAccessToken();
137
+ const refreshToken = await storage.getRefreshToken();
138
138
 
139
- expect(accessToken).toBe('cache-access-token');
140
- expect(refreshToken).toBe('cache-refresh-token');
141
- });
139
+ expect(accessToken).toBe('cache-access-token');
140
+ expect(refreshToken).toBe('cache-refresh-token');
141
+ });
142
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);
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
146
 
147
- const accessToken = await storage.getAccessToken();
148
- const refreshToken = await storage.getRefreshToken();
147
+ const accessToken = await storage.getAccessToken();
148
+ const refreshToken = await storage.getRefreshToken();
149
149
 
150
- expect(accessToken).toBe('ttl-access-token');
151
- expect(refreshToken).toBe('ttl-refresh-token');
152
- });
150
+ expect(accessToken).toBe('ttl-access-token');
151
+ expect(refreshToken).toBe('ttl-refresh-token');
152
+ });
153
153
 
154
- it('should clear both tokens from cache', async () => {
155
- await storage.setAccessToken('access-token');
156
- await storage.setRefreshToken('refresh-token');
154
+ it('should clear both tokens from cache', async () => {
155
+ await storage.setAccessToken('access-token');
156
+ await storage.setRefreshToken('refresh-token');
157
157
 
158
- await storage.clearTokens();
158
+ await storage.clearTokens();
159
159
 
160
- const accessToken = await storage.getAccessToken();
161
- const refreshToken = await storage.getRefreshToken();
160
+ const accessToken = await storage.getAccessToken();
161
+ const refreshToken = await storage.getRefreshToken();
162
162
 
163
- expect(accessToken).toBeNull();
164
- expect(refreshToken).toBeNull();
165
- });
166
- });
163
+ expect(accessToken).toBeNull();
164
+ expect(refreshToken).toBeNull();
165
+ });
166
+ });
167
167
  });
168
168
 
169
169
  describe('TokenClient', () => {
170
- let client: TokenClient;
171
- let storage: TokenStorage;
170
+ let client: TokenClient;
171
+ let storage: TokenStorage;
172
172
 
173
- beforeAll(() => server.listen());
174
- afterEach(() => server.resetHandlers());
175
- afterAll(() => server.close());
173
+ beforeAll(() => server.listen());
174
+ afterEach(() => server.resetHandlers());
175
+ afterAll(() => server.close());
176
176
 
177
- beforeEach(() => {
178
- storage = new MemoryTokenStorage();
179
- client = new TokenClient({
180
- storage,
181
- refreshEndpoint: 'https://auth.toolbox.dev/auth/refresh',
182
- });
183
- });
177
+ beforeEach(() => {
178
+ storage = new MemoryTokenStorage();
179
+ client = new TokenClient({
180
+ storage,
181
+ refreshEndpoint: 'https://auth.toolbox.dev/auth/refresh',
182
+ });
183
+ });
184
184
 
185
- describe('token management', () => {
186
- it('should store and retrieve tokens', async () => {
187
- await client.setTokens('access-token', 'refresh-token');
185
+ describe('token management', () => {
186
+ it('should store and retrieve tokens', async () => {
187
+ await client.setTokens('access-token', 'refresh-token');
188
188
 
189
- const accessToken = await client.getAccessToken();
190
- const refreshToken = await client.getRefreshToken();
189
+ const accessToken = await client.getAccessToken();
190
+ const refreshToken = await client.getRefreshToken();
191
191
 
192
- expect(accessToken).toBe('access-token');
193
- expect(refreshToken).toBe('refresh-token');
194
- });
192
+ expect(accessToken).toBe('access-token');
193
+ expect(refreshToken).toBe('refresh-token');
194
+ });
195
195
 
196
- it('should store tokens with TTL', async () => {
197
- await client.setTokens('access-token', 'refresh-token', 900, 7200);
196
+ it('should store tokens with TTL', async () => {
197
+ await client.setTokens('access-token', 'refresh-token', 900, 7200);
198
198
 
199
- const accessToken = await client.getAccessToken();
200
- const refreshToken = await client.getRefreshToken();
199
+ const accessToken = await client.getAccessToken();
200
+ const refreshToken = await client.getRefreshToken();
201
201
 
202
- expect(accessToken).toBe('access-token');
203
- expect(refreshToken).toBe('refresh-token');
204
- });
202
+ expect(accessToken).toBe('access-token');
203
+ expect(refreshToken).toBe('refresh-token');
204
+ });
205
205
 
206
- it('should store only access token when refresh not provided', async () => {
207
- await client.setTokens('access-only-token');
206
+ it('should store only access token when refresh not provided', async () => {
207
+ await client.setTokens('access-only-token');
208
208
 
209
- const accessToken = await client.getAccessToken();
210
- const refreshToken = await client.getRefreshToken();
209
+ const accessToken = await client.getAccessToken();
210
+ const refreshToken = await client.getRefreshToken();
211
211
 
212
- expect(accessToken).toBe('access-only-token');
213
- expect(refreshToken).toBeNull();
214
- });
212
+ expect(accessToken).toBe('access-only-token');
213
+ expect(refreshToken).toBeNull();
214
+ });
215
215
 
216
- it('should clear all tokens', async () => {
217
- await client.setTokens('access-token', 'refresh-token');
218
- await client.clearTokens();
216
+ it('should clear all tokens', async () => {
217
+ await client.setTokens('access-token', 'refresh-token');
218
+ await client.clearTokens();
219
219
 
220
- const accessToken = await client.getAccessToken();
221
- const refreshToken = await client.getRefreshToken();
220
+ const accessToken = await client.getAccessToken();
221
+ const refreshToken = await client.getRefreshToken();
222
222
 
223
- expect(accessToken).toBeNull();
224
- expect(refreshToken).toBeNull();
225
- });
226
- });
223
+ expect(accessToken).toBeNull();
224
+ expect(refreshToken).toBeNull();
225
+ });
226
+ });
227
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`;
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
232
 
233
- expect(client.isTokenExpired(validToken)).toBe(false);
233
+ expect(client.isTokenExpired(validToken)).toBe(false);
234
234
 
235
- const expiration = client.getTokenExpiration(validToken);
236
- expect(expiration).toBeInstanceOf(Date);
237
- expect(expiration!.getTime()).toBe(validPayload.exp * 1000);
238
- });
235
+ const expiration = client.getTokenExpiration(validToken);
236
+ expect(expiration).toBeInstanceOf(Date);
237
+ expect(expiration?.getTime()).toBe(validPayload.exp * 1000);
238
+ });
239
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`;
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
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
- });
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
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
- );
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
279
 
280
- await storage.setRefreshToken('invalid-refresh-token');
280
+ await storage.setRefreshToken('invalid-refresh-token');
281
281
 
282
- const success = await client.refreshTokens();
282
+ const success = await client.refreshTokens();
283
283
 
284
- expect(success).toBe(false);
285
- expect(await storage.getAccessToken()).toBeNull();
286
- expect(await storage.getRefreshToken()).toBeNull();
287
- });
284
+ expect(success).toBe(false);
285
+ expect(await storage.getAccessToken()).toBeNull();
286
+ expect(await storage.getRefreshToken()).toBeNull();
287
+ });
288
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
- );
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
295
 
296
- await storage.setRefreshToken('valid-refresh-token');
296
+ await storage.setRefreshToken('valid-refresh-token');
297
297
 
298
- const success = await client.refreshTokens();
298
+ const success = await client.refreshTokens();
299
299
 
300
- expect(success).toBe(false);
301
- expect(await storage.getAccessToken()).toBeNull();
302
- expect(await storage.getRefreshToken()).toBeNull();
303
- });
300
+ expect(success).toBe(false);
301
+ expect(await storage.getAccessToken()).toBeNull();
302
+ expect(await storage.getRefreshToken()).toBeNull();
303
+ });
304
304
 
305
- it('should fail when no refresh token available', async () => {
306
- const success = await client.refreshTokens();
305
+ it('should fail when no refresh token available', async () => {
306
+ const success = await client.refreshTokens();
307
307
 
308
- expect(success).toBe(false);
309
- });
308
+ expect(success).toBe(false);
309
+ });
310
310
 
311
- it('should fail when refresh endpoint not configured', async () => {
312
- const clientWithoutEndpoint = new TokenClient({ storage });
313
- await storage.setRefreshToken('valid-refresh-token');
311
+ it('should fail when refresh endpoint not configured', async () => {
312
+ const clientWithoutEndpoint = new TokenClient({ storage });
313
+ await storage.setRefreshToken('valid-refresh-token');
314
314
 
315
- const success = await clientWithoutEndpoint.refreshTokens();
315
+ const success = await clientWithoutEndpoint.refreshTokens();
316
316
 
317
- expect(success).toBe(false);
318
- });
319
- });
317
+ expect(success).toBe(false);
318
+ });
319
+ });
320
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
- });
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
331
 
332
- await storage.setRefreshToken('valid-refresh-token');
332
+ await storage.setRefreshToken('valid-refresh-token');
333
333
 
334
- await clientWithCallback.refreshTokens();
334
+ await clientWithCallback.refreshTokens();
335
335
 
336
- expect(callbackData).toEqual({
337
- accessToken: 'new-access-token',
338
- refreshToken: 'new-refresh-token',
339
- });
340
- });
336
+ expect(callbackData).toEqual({
337
+ accessToken: 'new-access-token',
338
+ refreshToken: 'new-refresh-token',
339
+ });
340
+ });
341
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
- });
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
351
 
352
- server.use(
353
- http.post('https://auth.toolbox.dev/auth/refresh', () => {
354
- return new HttpResponse(null, { status: 401 });
355
- }),
356
- );
352
+ server.use(
353
+ http.post('https://auth.toolbox.dev/auth/refresh', () => {
354
+ return new HttpResponse(null, { status: 401 });
355
+ }),
356
+ );
357
357
 
358
- await storage.setRefreshToken('invalid-refresh-token');
358
+ await storage.setRefreshToken('invalid-refresh-token');
359
359
 
360
- await clientWithCallback.refreshTokens();
360
+ await clientWithCallback.refreshTokens();
361
361
 
362
- expect(callbackCalled).toBe(true);
363
- });
364
- });
362
+ expect(callbackCalled).toBe(true);
363
+ });
364
+ });
365
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`;
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
370
 
371
- await storage.setAccessToken(validToken);
371
+ await storage.setAccessToken(validToken);
372
372
 
373
- const token = await client.getValidAccessToken();
373
+ const token = await client.getValidAccessToken();
374
374
 
375
- expect(token).toBe(validToken);
376
- });
375
+ expect(token).toBe(validToken);
376
+ });
377
377
 
378
- it('should return null when no token available', async () => {
379
- const token = await client.getValidAccessToken();
378
+ it('should return null when no token available', async () => {
379
+ const token = await client.getValidAccessToken();
380
380
 
381
- expect(token).toBeNull();
382
- });
381
+ expect(token).toBeNull();
382
+ });
383
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`;
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
387
 
388
- await storage.setAccessToken(expiredToken);
389
- await storage.setRefreshToken('valid-refresh-token');
388
+ await storage.setAccessToken(expiredToken);
389
+ await storage.setRefreshToken('valid-refresh-token');
390
390
 
391
- const token = await client.getValidAccessToken();
391
+ const token = await client.getValidAccessToken();
392
392
 
393
- expect(token).toBe('new-access-token');
394
- });
393
+ expect(token).toBe('new-access-token');
394
+ });
395
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
- );
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
402
 
403
- const expiredPayload = { exp: Math.floor(Date.now() / 1000) - 3600 };
404
- const expiredToken = `header.${btoa(JSON.stringify(expiredPayload))}.signature`;
403
+ const expiredPayload = { exp: Math.floor(Date.now() / 1000) - 3600 };
404
+ const expiredToken = `header.${btoa(JSON.stringify(expiredPayload))}.signature`;
405
405
 
406
- await storage.setAccessToken(expiredToken);
407
- await storage.setRefreshToken('invalid-refresh-token');
406
+ await storage.setAccessToken(expiredToken);
407
+ await storage.setRefreshToken('invalid-refresh-token');
408
408
 
409
- const token = await client.getValidAccessToken();
409
+ const token = await client.getValidAccessToken();
410
410
 
411
- expect(token).toBeNull();
412
- });
413
- });
411
+ expect(token).toBeNull();
412
+ });
413
+ });
414
414
 
415
- describe('authorization headers', () => {
416
- it('should create headers with current token', async () => {
417
- await storage.setAccessToken('current-token');
415
+ describe('authorization headers', () => {
416
+ it('should create headers with current token', async () => {
417
+ await storage.setAccessToken('current-token');
418
418
 
419
- const headers = await client.createAuthHeaders();
419
+ const headers = await client.createAuthHeaders();
420
420
 
421
- expect(headers).toEqual({
422
- Authorization: 'Bearer current-token',
423
- });
424
- });
421
+ expect(headers).toEqual({
422
+ Authorization: 'Bearer current-token',
423
+ });
424
+ });
425
425
 
426
- it('should return empty headers when no token', async () => {
427
- const headers = await client.createAuthHeaders();
426
+ it('should return empty headers when no token', async () => {
427
+ const headers = await client.createAuthHeaders();
428
428
 
429
- expect(headers).toEqual({});
430
- });
429
+ expect(headers).toEqual({});
430
+ });
431
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`;
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
435
 
436
- await storage.setAccessToken(validToken);
436
+ await storage.setAccessToken(validToken);
437
437
 
438
- const headers = await client.createValidAuthHeaders();
438
+ const headers = await client.createValidAuthHeaders();
439
439
 
440
- expect(headers).toEqual({
441
- Authorization: `Bearer ${validToken}`,
442
- });
443
- });
440
+ expect(headers).toEqual({
441
+ Authorization: `Bearer ${validToken}`,
442
+ });
443
+ });
444
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`;
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
448
 
449
- await storage.setAccessToken(expiredToken);
450
- await storage.setRefreshToken('valid-refresh-token');
449
+ await storage.setAccessToken(expiredToken);
450
+ await storage.setRefreshToken('valid-refresh-token');
451
451
 
452
- const headers = await client.createValidAuthHeaders();
452
+ const headers = await client.createValidAuthHeaders();
453
453
 
454
- expect(headers).toEqual({
455
- Authorization: 'Bearer new-access-token',
456
- });
457
- });
454
+ expect(headers).toEqual({
455
+ Authorization: 'Bearer new-access-token',
456
+ });
457
+ });
458
458
 
459
- it('should return empty headers when no valid token available', async () => {
460
- const headers = await client.createValidAuthHeaders();
459
+ it('should return empty headers when no valid token available', async () => {
460
+ const headers = await client.createValidAuthHeaders();
461
461
 
462
- expect(headers).toEqual({});
463
- });
464
- });
462
+ expect(headers).toEqual({});
463
+ });
464
+ });
465
465
  });