@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.
- package/core.js +34 -9
- package/package.json +1 -1
- 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
|
-
|
|
221
|
-
|
|
222
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
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
|
+
|