@spidy092/auth-client 1.1.0 → 2.0.1

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 (3) hide show
  1. package/core.js +34 -9
  2. package/package.json +1 -1
  3. package/token.js +263 -58
package/core.js CHANGED
@@ -214,31 +214,55 @@ export function resetCallbackState() {
214
214
  console.log('🔄 Callback state reset');
215
215
  }
216
216
 
217
+ // auth-client/core.js
217
218
  export async function refreshToken() {
218
219
  const { clientKey, authBaseUrl } = getConfig();
219
-
220
- console.log('🔄 Refreshing token:', {
221
- clientKey,
222
- mode: isRouterMode() ? 'ROUTER' : 'CLIENT'
220
+ const refreshTokenValue = getRefreshToken(); // ✅ Now checks both cookie & localStorage
221
+
222
+ console.log('🔄 Refreshing token:', {
223
+ clientKey,
224
+ mode: isRouterMode() ? 'ROUTER' : 'CLIENT',
225
+ hasRefreshToken: !!refreshTokenValue
223
226
  });
224
-
227
+
228
+ if (!refreshTokenValue) {
229
+ console.warn('⚠️ No refresh token available for refresh');
230
+ clearToken();
231
+ throw new Error('No refresh token available');
232
+ }
233
+
225
234
  try {
226
235
  const response = await fetch(`${authBaseUrl}/refresh/${clientKey}`, {
227
236
  method: 'POST',
228
- credentials: 'include',
237
+ credentials: 'include', // ✅ Sends cookie if available
238
+ headers: {
239
+ 'Content-Type': 'application/json',
240
+ 'X-Refresh-Token': refreshTokenValue // ✅ Also send in header as fallback
241
+ },
242
+ body: JSON.stringify({
243
+ refreshToken: refreshTokenValue // ✅ Also send in body
244
+ })
229
245
  });
230
246
 
231
247
  if (!response.ok) {
232
248
  throw new Error('Refresh failed');
233
249
  }
234
250
 
235
- const { access_token } = await response.json();
236
- // ✅ This will trigger token listeners
251
+ const { access_token, refresh_token: new_refresh_token } = await response.json();
252
+
253
+ // ✅ Update access token (triggers listeners)
237
254
  setToken(access_token);
255
+
256
+ // ✅ Update refresh token in BOTH storages if backend returned new one
257
+ if (new_refresh_token) {
258
+ setRefreshToken(new_refresh_token);
259
+ }
260
+
238
261
  console.log('✅ Token refresh successful, listeners notified');
239
262
  return access_token;
240
263
  } catch (err) {
241
- // This will trigger token listeners
264
+ console.error('❌ Token refresh failed:', err);
265
+ // ✅ Clear everything on refresh failure
242
266
  clearToken();
243
267
  clearRefreshToken();
244
268
  throw err;
@@ -246,6 +270,7 @@ export async function refreshToken() {
246
270
  }
247
271
 
248
272
 
273
+
249
274
  export async function validateCurrentSession() {
250
275
  try {
251
276
  const { authBaseUrl } = getConfig();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@spidy092/auth-client",
3
- "version": "1.1.0",
3
+ "version": "2.0.1",
4
4
  "description": "Scalable frontend auth SDK for centralized login using Keycloak + Auth Service.",
5
5
  "main": "index.js",
6
6
  "module": "index.js",
package/token.js CHANGED
@@ -1,4 +1,5 @@
1
- // auth-client/token.js
1
+ // auth-client/token.js - CORRECTED VERSION
2
+
2
3
  import { jwtDecode } from 'jwt-decode';
3
4
 
4
5
  let accessToken = null;
@@ -17,6 +18,7 @@ function secureAttribute() {
17
18
  }
18
19
  }
19
20
 
21
+ // ========== ACCESS TOKEN (localStorage - keeps working) ==========
20
22
  function writeAccessToken(token) {
21
23
  if (!token) {
22
24
  try {
@@ -43,6 +45,80 @@ function readAccessToken() {
43
45
  }
44
46
  }
45
47
 
48
+ // ========== REFRESH TOKEN (Cookie + sessionStorage - REVERTED) ==========
49
+
50
+ export function setRefreshToken(token) {
51
+ if (!token) {
52
+ clearRefreshToken();
53
+ return;
54
+ }
55
+
56
+ const expires = new Date(Date.now() + COOKIE_MAX_AGE * 1000);
57
+
58
+ // ✅ REVERT: Use SameSite=Lax (NOT Strict) for SSO to work
59
+ try {
60
+ document.cookie = `${REFRESH_COOKIE}=${encodeURIComponent(token)}; Path=/; SameSite=Lax${secureAttribute()}; Expires=${expires.toUTCString()}`;
61
+ console.log('✅ Refresh token cookie set (SameSite=Lax for SSO)');
62
+ } catch (err) {
63
+ console.warn('Could not persist refresh token cookie:', err);
64
+ }
65
+
66
+ // ✅ REVERT: Keep sessionStorage (NOT localStorage) as fallback
67
+ try {
68
+ sessionStorage.setItem(REFRESH_COOKIE, token);
69
+ console.log('✅ Refresh token sessionStorage backup set');
70
+ } catch (err) {
71
+ console.warn('Could not persist refresh token to sessionStorage:', err);
72
+ }
73
+ }
74
+
75
+ export function getRefreshToken() {
76
+ // Prefer cookie to align with server expectations
77
+ let cookieMatch = null;
78
+ try {
79
+ cookieMatch = document.cookie
80
+ ?.split('; ')
81
+ ?.find((row) => row.startsWith(`${REFRESH_COOKIE}=`));
82
+ } catch (err) {
83
+ cookieMatch = null;
84
+ }
85
+
86
+ if (cookieMatch) {
87
+ console.log('✅ Retrieved refresh token from cookie');
88
+ return decodeURIComponent(cookieMatch.split('=')[1]);
89
+ }
90
+
91
+ // ✅ REVERT: Fallback to sessionStorage (NOT localStorage)
92
+ try {
93
+ const token = sessionStorage.getItem(REFRESH_COOKIE);
94
+ if (token) {
95
+ console.log('✅ Retrieved refresh token from sessionStorage (fallback)');
96
+ }
97
+ return token;
98
+ } catch (err) {
99
+ console.warn('Could not read refresh token from sessionStorage:', err);
100
+ return null;
101
+ }
102
+ }
103
+
104
+ export function clearRefreshToken() {
105
+ // ✅ REVERT: Clear with SameSite=Lax
106
+ try {
107
+ document.cookie = `${REFRESH_COOKIE}=; Path=/; SameSite=Lax${secureAttribute()}; Expires=Thu, 01 Jan 1970 00:00:00 GMT`;
108
+ } catch (err) {
109
+ console.warn('Could not clear refresh token cookie:', err);
110
+ }
111
+
112
+ // ✅ REVERT: Clear sessionStorage (NOT localStorage)
113
+ try {
114
+ sessionStorage.removeItem(REFRESH_COOKIE);
115
+ } catch (err) {
116
+ console.warn('Could not clear refresh token from sessionStorage:', err);
117
+ }
118
+ }
119
+
120
+ // ========== ACCESS TOKEN FUNCTIONS (unchanged) ==========
121
+
46
122
  function decode(token) {
47
123
  try {
48
124
  return jwtDecode(token);
@@ -102,63 +178,6 @@ export function clearToken() {
102
178
  });
103
179
  }
104
180
 
105
- export function setRefreshToken(token) {
106
- if (!token) {
107
- clearRefreshToken();
108
- return;
109
- }
110
-
111
- const expires = new Date(Date.now() + COOKIE_MAX_AGE * 1000);
112
- try {
113
- document.cookie = `${REFRESH_COOKIE}=${encodeURIComponent(token)}; Path=/; SameSite=Strict${secureAttribute()}; Expires=${expires.toUTCString()}`;
114
- } catch (err) {
115
- console.warn('Could not persist refresh token cookie:', err);
116
- }
117
-
118
- try {
119
- sessionStorage.setItem(REFRESH_COOKIE, token);
120
- } catch (err) {
121
- console.warn('Could not persist refresh token to sessionStorage:', err);
122
- }
123
- }
124
-
125
- export function getRefreshToken() {
126
- // Prefer cookie to align with server expectations
127
- let cookieMatch = null;
128
-
129
- try {
130
- cookieMatch = document.cookie
131
- ?.split('; ')
132
- ?.find((row) => row.startsWith(`${REFRESH_COOKIE}=`));
133
- } catch (err) {
134
- cookieMatch = null;
135
- }
136
-
137
- if (cookieMatch) {
138
- return decodeURIComponent(cookieMatch.split('=')[1]);
139
- }
140
-
141
- try {
142
- return sessionStorage.getItem(REFRESH_COOKIE);
143
- } catch (err) {
144
- console.warn('Could not read refresh token from sessionStorage:', err);
145
- return null;
146
- }
147
- }
148
-
149
- export function clearRefreshToken() {
150
- try {
151
- document.cookie = `${REFRESH_COOKIE}=; Path=/; SameSite=Strict${secureAttribute()}; Expires=Thu, 01 Jan 1970 00:00:00 GMT`;
152
- } catch (err) {
153
- console.warn('Could not clear refresh token cookie:', err);
154
- }
155
- try {
156
- sessionStorage.removeItem(REFRESH_COOKIE);
157
- } catch (err) {
158
- console.warn('Could not clear refresh token from sessionStorage:', err);
159
- }
160
- }
161
-
162
181
  export function addTokenListener(listener) {
163
182
  if (typeof listener !== 'function') {
164
183
  throw new Error('Token listener must be a function');
@@ -182,3 +201,189 @@ export function isAuthenticated() {
182
201
  return !!token && !isExpired(token, 15);
183
202
  }
184
203
 
204
+
205
+
206
+ // // auth-client/token.js
207
+ // import { jwtDecode } from 'jwt-decode';
208
+
209
+ // let accessToken = null;
210
+ // const listeners = new Set();
211
+
212
+ // const REFRESH_COOKIE = 'account_refresh_token';
213
+ // const COOKIE_MAX_AGE = 7 * 24 * 60 * 60; // 7 days in seconds
214
+
215
+ // function secureAttribute() {
216
+ // try {
217
+ // return typeof window !== 'undefined' && window.location?.protocol === 'https:'
218
+ // ? '; Secure'
219
+ // : '';
220
+ // } catch (err) {
221
+ // return '';
222
+ // }
223
+ // }
224
+
225
+ // function writeAccessToken(token) {
226
+ // if (!token) {
227
+ // try {
228
+ // localStorage.removeItem('authToken');
229
+ // } catch (err) {
230
+ // console.warn('Could not clear token from localStorage:', err);
231
+ // }
232
+ // return;
233
+ // }
234
+
235
+ // try {
236
+ // localStorage.setItem('authToken', token);
237
+ // } catch (err) {
238
+ // console.warn('Could not persist token to localStorage:', err);
239
+ // }
240
+ // }
241
+
242
+ // function readAccessToken() {
243
+ // try {
244
+ // return localStorage.getItem('authToken');
245
+ // } catch (err) {
246
+ // console.warn('Could not read token from localStorage:', err);
247
+ // return null;
248
+ // }
249
+ // }
250
+
251
+ // function decode(token) {
252
+ // try {
253
+ // return jwtDecode(token);
254
+ // } catch (err) {
255
+ // return null;
256
+ // }
257
+ // }
258
+
259
+ // function isExpired(token, bufferSeconds = 60) {
260
+ // if (!token) return true;
261
+ // const decoded = decode(token);
262
+ // if (!decoded?.exp) return true;
263
+ // const now = Date.now() / 1000;
264
+ // return decoded.exp < now + bufferSeconds;
265
+ // }
266
+
267
+ // export function setToken(token) {
268
+ // const previousToken = accessToken;
269
+ // accessToken = token || null;
270
+ // writeAccessToken(accessToken);
271
+
272
+ // if (previousToken !== accessToken) {
273
+ // listeners.forEach((listener) => {
274
+ // try {
275
+ // listener(accessToken, previousToken);
276
+ // } catch (err) {
277
+ // console.warn('Token listener error:', err);
278
+ // }
279
+ // });
280
+ // }
281
+ // }
282
+
283
+ // export function getToken() {
284
+ // if (accessToken) return accessToken;
285
+ // accessToken = readAccessToken();
286
+ // return accessToken;
287
+ // }
288
+
289
+ // export function clearToken() {
290
+ // if (!accessToken) {
291
+ // writeAccessToken(null);
292
+ // clearRefreshToken();
293
+ // return;
294
+ // }
295
+
296
+ // const previousToken = accessToken;
297
+ // accessToken = null;
298
+ // writeAccessToken(null);
299
+ // clearRefreshToken();
300
+
301
+ // listeners.forEach((listener) => {
302
+ // try {
303
+ // listener(null, previousToken);
304
+ // } catch (err) {
305
+ // console.warn('Token listener error:', err);
306
+ // }
307
+ // });
308
+ // }
309
+
310
+ // export function setRefreshToken(token) {
311
+ // if (!token) {
312
+ // clearRefreshToken();
313
+ // return;
314
+ // }
315
+
316
+ // const expires = new Date(Date.now() + COOKIE_MAX_AGE * 1000);
317
+ // try {
318
+ // document.cookie = `${REFRESH_COOKIE}=${encodeURIComponent(token)}; Path=/; SameSite=Strict${secureAttribute()}; Expires=${expires.toUTCString()}`;
319
+ // } catch (err) {
320
+ // console.warn('Could not persist refresh token cookie:', err);
321
+ // }
322
+
323
+ // try {
324
+ // sessionStorage.setItem(REFRESH_COOKIE, token);
325
+ // } catch (err) {
326
+ // console.warn('Could not persist refresh token to sessionStorage:', err);
327
+ // }
328
+ // }
329
+
330
+ // export function getRefreshToken() {
331
+ // // Prefer cookie to align with server expectations
332
+ // let cookieMatch = null;
333
+
334
+ // try {
335
+ // cookieMatch = document.cookie
336
+ // ?.split('; ')
337
+ // ?.find((row) => row.startsWith(`${REFRESH_COOKIE}=`));
338
+ // } catch (err) {
339
+ // cookieMatch = null;
340
+ // }
341
+
342
+ // if (cookieMatch) {
343
+ // return decodeURIComponent(cookieMatch.split('=')[1]);
344
+ // }
345
+
346
+ // try {
347
+ // return sessionStorage.getItem(REFRESH_COOKIE);
348
+ // } catch (err) {
349
+ // console.warn('Could not read refresh token from sessionStorage:', err);
350
+ // return null;
351
+ // }
352
+ // }
353
+
354
+ // export function clearRefreshToken() {
355
+ // try {
356
+ // document.cookie = `${REFRESH_COOKIE}=; Path=/; SameSite=Strict${secureAttribute()}; Expires=Thu, 01 Jan 1970 00:00:00 GMT`;
357
+ // } catch (err) {
358
+ // console.warn('Could not clear refresh token cookie:', err);
359
+ // }
360
+ // try {
361
+ // sessionStorage.removeItem(REFRESH_COOKIE);
362
+ // } catch (err) {
363
+ // console.warn('Could not clear refresh token from sessionStorage:', err);
364
+ // }
365
+ // }
366
+
367
+ // export function addTokenListener(listener) {
368
+ // if (typeof listener !== 'function') {
369
+ // throw new Error('Token listener must be a function');
370
+ // }
371
+ // listeners.add(listener);
372
+ // return () => {
373
+ // listeners.delete(listener);
374
+ // };
375
+ // }
376
+
377
+ // export function removeTokenListener(listener) {
378
+ // listeners.delete(listener);
379
+ // }
380
+
381
+ // export function getListenerCount() {
382
+ // return listeners.size;
383
+ // }
384
+
385
+ // export function isAuthenticated() {
386
+ // const token = getToken();
387
+ // return !!token && !isExpired(token, 15);
388
+ // }
389
+