@spidy092/auth-client 3.1.3 → 3.1.5
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/dist/api.cjs +34 -0
- package/dist/api.cjs.map +1 -1
- package/dist/api.js +34 -0
- package/dist/api.js.map +1 -1
- package/dist/index.cjs +194 -31
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +194 -31
- package/dist/index.js.map +1 -1
- package/dist/preferences.cjs +34 -0
- package/dist/preferences.cjs.map +1 -1
- package/dist/preferences.js +34 -0
- package/dist/preferences.js.map +1 -1
- package/dist/react/AuthProvider.cjs +188 -31
- package/dist/react/AuthProvider.cjs.map +1 -1
- package/dist/react/AuthProvider.js +188 -31
- package/dist/react/AuthProvider.js.map +1 -1
- package/dist/react/PreferencesProvider.cjs +34 -0
- package/dist/react/PreferencesProvider.cjs.map +1 -1
- package/dist/react/PreferencesProvider.js +34 -0
- package/dist/react/PreferencesProvider.js.map +1 -1
- package/dist/react/useAuth.cjs.map +1 -1
- package/dist/react/useAuth.js.map +1 -1
- package/dist/react/useSessionMonitor.cjs +61 -1
- package/dist/react/useSessionMonitor.cjs.map +1 -1
- package/dist/react/useSessionMonitor.js +61 -1
- package/dist/react/useSessionMonitor.js.map +1 -1
- package/dist/utils/jwt.cjs.map +1 -1
- package/dist/utils/jwt.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
// token.js
|
|
2
2
|
import { jwtDecode } from "jwt-decode";
|
|
3
3
|
var accessToken = null;
|
|
4
|
+
var idToken = null;
|
|
4
5
|
var listeners = /* @__PURE__ */ new Set();
|
|
5
6
|
var REFRESH_COOKIE = "account_refresh_token";
|
|
7
|
+
var ID_TOKEN_KEY = "auth_id_token";
|
|
6
8
|
var COOKIE_MAX_AGE = 7 * 24 * 60 * 60;
|
|
7
9
|
function secureAttribute() {
|
|
8
10
|
var _a;
|
|
@@ -81,12 +83,14 @@ function getToken() {
|
|
|
81
83
|
function clearToken() {
|
|
82
84
|
if (!accessToken) {
|
|
83
85
|
writeAccessToken(null);
|
|
86
|
+
clearIdToken();
|
|
84
87
|
clearRefreshToken();
|
|
85
88
|
return;
|
|
86
89
|
}
|
|
87
90
|
const previousToken = accessToken;
|
|
88
91
|
accessToken = null;
|
|
89
92
|
writeAccessToken(null);
|
|
93
|
+
clearIdToken();
|
|
90
94
|
clearRefreshToken();
|
|
91
95
|
listeners.forEach((listener) => {
|
|
92
96
|
try {
|
|
@@ -96,6 +100,30 @@ function clearToken() {
|
|
|
96
100
|
}
|
|
97
101
|
});
|
|
98
102
|
}
|
|
103
|
+
function setIdToken(token) {
|
|
104
|
+
idToken = token || null;
|
|
105
|
+
try {
|
|
106
|
+
if (idToken) sessionStorage.setItem(ID_TOKEN_KEY, idToken);
|
|
107
|
+
else sessionStorage.removeItem(ID_TOKEN_KEY);
|
|
108
|
+
} catch {
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
function getIdToken() {
|
|
112
|
+
if (idToken) return idToken;
|
|
113
|
+
try {
|
|
114
|
+
idToken = sessionStorage.getItem(ID_TOKEN_KEY) || null;
|
|
115
|
+
} catch {
|
|
116
|
+
idToken = null;
|
|
117
|
+
}
|
|
118
|
+
return idToken;
|
|
119
|
+
}
|
|
120
|
+
function clearIdToken() {
|
|
121
|
+
idToken = null;
|
|
122
|
+
try {
|
|
123
|
+
sessionStorage.removeItem(ID_TOKEN_KEY);
|
|
124
|
+
} catch {
|
|
125
|
+
}
|
|
126
|
+
}
|
|
99
127
|
var REFRESH_TOKEN_KEY = "auth_refresh_token";
|
|
100
128
|
var _persistRefreshToken = false;
|
|
101
129
|
function enableRefreshTokenPersistence(enabled) {
|
|
@@ -340,6 +368,28 @@ function clearLoginLock() {
|
|
|
340
368
|
} catch {
|
|
341
369
|
}
|
|
342
370
|
}
|
|
371
|
+
async function reportClientDiagnostic(safe) {
|
|
372
|
+
if (typeof fetch !== "function" || typeof getToken !== "function") return;
|
|
373
|
+
if (safe.outcome === "SUCCESS" && !safe.event.startsWith("PROFILE_") && !safe.event.startsWith("SESSION_")) return;
|
|
374
|
+
const { authBaseUrl } = getConfig();
|
|
375
|
+
const token = getToken();
|
|
376
|
+
if (!authBaseUrl || !token) return;
|
|
377
|
+
try {
|
|
378
|
+
await fetch(`${authBaseUrl.replace(/\/+$/, "")}/client-telemetry`, {
|
|
379
|
+
method: "POST",
|
|
380
|
+
credentials: "include",
|
|
381
|
+
keepalive: true,
|
|
382
|
+
headers: {
|
|
383
|
+
"Content-Type": "application/json",
|
|
384
|
+
Authorization: `Bearer ${token}`,
|
|
385
|
+
"X-Correlation-ID": safe.correlationId,
|
|
386
|
+
"X-Request-ID": safe.correlationId
|
|
387
|
+
},
|
|
388
|
+
body: JSON.stringify(safe)
|
|
389
|
+
});
|
|
390
|
+
} catch {
|
|
391
|
+
}
|
|
392
|
+
}
|
|
343
393
|
async function emitAuthDiagnostic(event, outcome, reasonCode, details = {}) {
|
|
344
394
|
const context = getDiagnosticContext();
|
|
345
395
|
const safe = {
|
|
@@ -356,6 +406,7 @@ async function emitAuthDiagnostic(event, outcome, reasonCode, details = {}) {
|
|
|
356
406
|
};
|
|
357
407
|
const method = outcome === "FAILURE" ? "error" : outcome === "WARNING" ? "warn" : "info";
|
|
358
408
|
console[method]("[auth-client]", safe);
|
|
409
|
+
void reportClientDiagnostic(safe);
|
|
359
410
|
return safe;
|
|
360
411
|
}
|
|
361
412
|
|
|
@@ -418,6 +469,7 @@ async function logout(options = {}) {
|
|
|
418
469
|
const { clientKey, authBaseUrl, accountUiUrl } = getConfig();
|
|
419
470
|
const scope = options.scope === "client" ? "client" : "sso";
|
|
420
471
|
const token = getToken();
|
|
472
|
+
const idToken2 = getIdToken();
|
|
421
473
|
const refreshToken2 = getRefreshToken();
|
|
422
474
|
console.log("\u{1F6AA} Smart Logout initiated", {
|
|
423
475
|
mode: isRouterMode() ? "ROUTER" : "CLIENT",
|
|
@@ -426,6 +478,7 @@ async function logout(options = {}) {
|
|
|
426
478
|
});
|
|
427
479
|
emitAuthDiagnostic("LOGOUT_INITIATED", "PENDING", "NONE", { clientKey });
|
|
428
480
|
clearToken();
|
|
481
|
+
clearIdToken();
|
|
429
482
|
clearRefreshToken();
|
|
430
483
|
sessionStorage.removeItem("originalApp");
|
|
431
484
|
sessionStorage.removeItem("returnUrl");
|
|
@@ -438,7 +491,7 @@ async function logout(options = {}) {
|
|
|
438
491
|
"Authorization": token ? `Bearer ${token}` : "",
|
|
439
492
|
"Content-Type": "application/json"
|
|
440
493
|
},
|
|
441
|
-
body: JSON.stringify({ refreshToken: refreshToken2, scope })
|
|
494
|
+
body: JSON.stringify({ refreshToken: refreshToken2, idToken: idToken2, scope })
|
|
442
495
|
});
|
|
443
496
|
if (!response.ok) {
|
|
444
497
|
throw new Error(`Logout failed: ${response.status}`);
|
|
@@ -472,9 +525,11 @@ async function logout(options = {}) {
|
|
|
472
525
|
function handleCallback() {
|
|
473
526
|
const params = new URLSearchParams(window.location.search);
|
|
474
527
|
const accessToken2 = params.get("access_token");
|
|
528
|
+
const idToken2 = params.get("id_token");
|
|
475
529
|
const error = params.get("error");
|
|
476
530
|
console.log("\u{1F504} Callback handling:", {
|
|
477
531
|
hasAccessToken: !!accessToken2,
|
|
532
|
+
hasIdToken: !!idToken2,
|
|
478
533
|
error
|
|
479
534
|
});
|
|
480
535
|
if (callbackProcessed) {
|
|
@@ -502,6 +557,7 @@ function handleCallback() {
|
|
|
502
557
|
}
|
|
503
558
|
if (accessToken2) {
|
|
504
559
|
setToken(accessToken2);
|
|
560
|
+
if (idToken2) setIdToken(idToken2);
|
|
505
561
|
const refreshTokenInUrl = params.get("refresh_token");
|
|
506
562
|
if (refreshTokenInUrl) {
|
|
507
563
|
emitAuthDiagnostic("CALLBACK_REFRESH_TOKEN_IGNORED", "WARNING", "REFRESH_TOKEN_IN_URL", {
|
|
@@ -510,6 +566,7 @@ function handleCallback() {
|
|
|
510
566
|
}
|
|
511
567
|
const url = new URL(window.location);
|
|
512
568
|
url.searchParams.delete("access_token");
|
|
569
|
+
url.searchParams.delete("id_token");
|
|
513
570
|
url.searchParams.delete("refresh_token");
|
|
514
571
|
url.searchParams.delete("state");
|
|
515
572
|
url.searchParams.delete("error");
|
|
@@ -1185,23 +1242,72 @@ var preferences = {
|
|
|
1185
1242
|
// react/AuthProvider.jsx
|
|
1186
1243
|
import React, { createContext, useState, useEffect, useRef } from "react";
|
|
1187
1244
|
var AuthContext = createContext();
|
|
1188
|
-
function AuthProvider({ children, onSessionExpired }) {
|
|
1245
|
+
function AuthProvider({ children, onSessionExpired, manageSessionSecurity = true }) {
|
|
1189
1246
|
const [token, setTokenState] = useState(getToken());
|
|
1190
1247
|
const [user, setUser] = useState(null);
|
|
1191
1248
|
const [loading, setLoading] = useState(!!token);
|
|
1192
1249
|
const [sessionValid, setSessionValid] = useState(true);
|
|
1193
1250
|
const sessionSecurityRef = useRef(null);
|
|
1251
|
+
const onSessionExpiredRef = useRef(onSessionExpired);
|
|
1252
|
+
const recoveryInFlightRef = useRef(null);
|
|
1253
|
+
const profileRecoveryTokensRef = useRef(/* @__PURE__ */ new Set());
|
|
1254
|
+
useEffect(() => {
|
|
1255
|
+
onSessionExpiredRef.current = onSessionExpired;
|
|
1256
|
+
}, [onSessionExpired]);
|
|
1257
|
+
useEffect(() => {
|
|
1258
|
+
const unsubscribe = addTokenListener((nextToken, previousToken) => {
|
|
1259
|
+
if (nextToken === previousToken) return;
|
|
1260
|
+
setTokenState(nextToken);
|
|
1261
|
+
if (nextToken) {
|
|
1262
|
+
setSessionValid(true);
|
|
1263
|
+
setLoading(true);
|
|
1264
|
+
} else {
|
|
1265
|
+
setSessionValid(false);
|
|
1266
|
+
setUser(null);
|
|
1267
|
+
setLoading(false);
|
|
1268
|
+
}
|
|
1269
|
+
});
|
|
1270
|
+
return unsubscribe;
|
|
1271
|
+
}, []);
|
|
1272
|
+
const invalidateLocalSession = () => {
|
|
1273
|
+
clearToken();
|
|
1274
|
+
setTokenState(null);
|
|
1275
|
+
setUser(null);
|
|
1276
|
+
setSessionValid(false);
|
|
1277
|
+
setLoading(false);
|
|
1278
|
+
};
|
|
1194
1279
|
const handleSessionInvalid = (reason) => {
|
|
1195
1280
|
console.log("\u{1F6A8} AuthProvider: Session invalidated -", reason);
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1281
|
+
if (recoveryInFlightRef.current) return recoveryInFlightRef.current;
|
|
1282
|
+
const recover = async () => {
|
|
1283
|
+
const callback = onSessionExpiredRef.current;
|
|
1284
|
+
if (typeof callback === "function") {
|
|
1285
|
+
try {
|
|
1286
|
+
await callback(reason);
|
|
1287
|
+
const recoveredToken = getToken();
|
|
1288
|
+
if (recoveredToken) {
|
|
1289
|
+
setTokenState(recoveredToken);
|
|
1290
|
+
setSessionValid(true);
|
|
1291
|
+
setLoading(true);
|
|
1292
|
+
return true;
|
|
1293
|
+
}
|
|
1294
|
+
} catch (error) {
|
|
1295
|
+
await emitAuthDiagnostic("SESSION_RECOVERY_FAILED", "FAILURE", reason, {
|
|
1296
|
+
status: (error == null ? void 0 : error.status) || null,
|
|
1297
|
+
errorCode: (error == null ? void 0 : error.code) || null
|
|
1298
|
+
});
|
|
1299
|
+
}
|
|
1300
|
+
}
|
|
1301
|
+
invalidateLocalSession();
|
|
1302
|
+
return false;
|
|
1303
|
+
};
|
|
1304
|
+
recoveryInFlightRef.current = recover().finally(() => {
|
|
1305
|
+
recoveryInFlightRef.current = null;
|
|
1306
|
+
});
|
|
1307
|
+
return recoveryInFlightRef.current;
|
|
1202
1308
|
};
|
|
1203
1309
|
useEffect(() => {
|
|
1204
|
-
if (token && !sessionSecurityRef.current) {
|
|
1310
|
+
if (manageSessionSecurity && token && !sessionSecurityRef.current) {
|
|
1205
1311
|
console.log("\u{1F510} AuthProvider: Starting session security");
|
|
1206
1312
|
const unsubscribe = onSessionInvalid(handleSessionInvalid);
|
|
1207
1313
|
sessionSecurityRef.current = startSessionSecurity(handleSessionInvalid);
|
|
@@ -1213,11 +1319,11 @@ function AuthProvider({ children, onSessionExpired }) {
|
|
|
1213
1319
|
}
|
|
1214
1320
|
};
|
|
1215
1321
|
}
|
|
1216
|
-
if (!token && sessionSecurityRef.current) {
|
|
1322
|
+
if ((!manageSessionSecurity || !token) && sessionSecurityRef.current) {
|
|
1217
1323
|
sessionSecurityRef.current.stopAll();
|
|
1218
1324
|
sessionSecurityRef.current = null;
|
|
1219
1325
|
}
|
|
1220
|
-
}, [token]);
|
|
1326
|
+
}, [manageSessionSecurity, token]);
|
|
1221
1327
|
useEffect(() => {
|
|
1222
1328
|
console.log("\u{1F50D} AuthProvider useEffect triggered:", {
|
|
1223
1329
|
hasToken: !!token,
|
|
@@ -1238,26 +1344,79 @@ function AuthProvider({ children, onSessionExpired }) {
|
|
|
1238
1344
|
authBaseUrl,
|
|
1239
1345
|
tokenPreview: token.slice(0, 50) + "..."
|
|
1240
1346
|
});
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
}
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1347
|
+
let cancelled = false;
|
|
1348
|
+
const fetchProfile = async (accessToken2) => {
|
|
1349
|
+
const response = await fetch(`${authBaseUrl}/account/profile`, {
|
|
1350
|
+
headers: { Authorization: `Bearer ${accessToken2}` },
|
|
1351
|
+
credentials: "include"
|
|
1352
|
+
});
|
|
1353
|
+
console.log("\u{1F4E5} Profile response status:", response.status);
|
|
1354
|
+
if (!response.ok) {
|
|
1355
|
+
const error = new Error(`Profile request failed: ${response.status}`);
|
|
1356
|
+
error.status = response.status;
|
|
1357
|
+
throw error;
|
|
1358
|
+
}
|
|
1359
|
+
return response.json();
|
|
1360
|
+
};
|
|
1361
|
+
const loadProfile = async () => {
|
|
1362
|
+
try {
|
|
1363
|
+
const responseBody = await fetchProfile(token);
|
|
1364
|
+
if (cancelled) return;
|
|
1365
|
+
const userData = (responseBody == null ? void 0 : responseBody.data) ?? responseBody;
|
|
1366
|
+
console.log("\u2705 Profile fetched successfully:", userData.email);
|
|
1367
|
+
setUser(userData);
|
|
1368
|
+
setSessionValid(true);
|
|
1369
|
+
setLoading(false);
|
|
1370
|
+
} catch (error) {
|
|
1371
|
+
if (cancelled) return;
|
|
1372
|
+
const status = Number((error == null ? void 0 : error.status) || 0);
|
|
1373
|
+
const isUnauthorized = status === 401;
|
|
1374
|
+
const callback = onSessionExpiredRef.current;
|
|
1375
|
+
await emitAuthDiagnostic(
|
|
1376
|
+
"PROFILE_REQUEST_FAILED",
|
|
1377
|
+
isUnauthorized ? "FAILURE" : "WARNING",
|
|
1378
|
+
isUnauthorized ? "PROFILE_UNAUTHORIZED" : status ? `PROFILE_HTTP_${status}` : "PROFILE_NETWORK_ERROR",
|
|
1379
|
+
{ status, errorName: error == null ? void 0 : error.name, errorCode: error == null ? void 0 : error.code }
|
|
1380
|
+
);
|
|
1381
|
+
if (!isUnauthorized) {
|
|
1382
|
+
console.warn("\u26A0\uFE0F Profile unavailable; retaining the current auth session", error);
|
|
1383
|
+
setLoading(false);
|
|
1384
|
+
return;
|
|
1385
|
+
}
|
|
1386
|
+
if (typeof callback === "function" && !profileRecoveryTokensRef.current.has(token)) {
|
|
1387
|
+
profileRecoveryTokensRef.current.add(token);
|
|
1388
|
+
try {
|
|
1389
|
+
await callback("profile_unauthorized");
|
|
1390
|
+
const recoveredToken = getToken();
|
|
1391
|
+
if (recoveredToken && recoveredToken !== token) {
|
|
1392
|
+
setTokenState(recoveredToken);
|
|
1393
|
+
setSessionValid(true);
|
|
1394
|
+
setLoading(true);
|
|
1395
|
+
return;
|
|
1396
|
+
}
|
|
1397
|
+
if (recoveredToken) {
|
|
1398
|
+
const responseBody = await fetchProfile(recoveredToken);
|
|
1399
|
+
if (cancelled) return;
|
|
1400
|
+
const userData = (responseBody == null ? void 0 : responseBody.data) ?? responseBody;
|
|
1401
|
+
setUser(userData);
|
|
1402
|
+
setSessionValid(true);
|
|
1403
|
+
setLoading(false);
|
|
1404
|
+
return;
|
|
1405
|
+
}
|
|
1406
|
+
} catch (recoveryError) {
|
|
1407
|
+
await emitAuthDiagnostic("PROFILE_RECOVERY_FAILED", "FAILURE", "PROFILE_REFRESH_FAILED", {
|
|
1408
|
+
status: (recoveryError == null ? void 0 : recoveryError.status) || null,
|
|
1409
|
+
errorCode: (recoveryError == null ? void 0 : recoveryError.code) || null
|
|
1410
|
+
});
|
|
1411
|
+
}
|
|
1412
|
+
}
|
|
1413
|
+
invalidateLocalSession();
|
|
1414
|
+
}
|
|
1415
|
+
};
|
|
1416
|
+
void loadProfile();
|
|
1417
|
+
return () => {
|
|
1418
|
+
cancelled = true;
|
|
1419
|
+
};
|
|
1261
1420
|
}, [token]);
|
|
1262
1421
|
const login2 = (clientKey, redirectUri, state) => {
|
|
1263
1422
|
login(clientKey, redirectUri, state);
|
|
@@ -1286,6 +1445,7 @@ function AuthProvider({ children, onSessionExpired }) {
|
|
|
1286
1445
|
setToken(newToken);
|
|
1287
1446
|
setTokenState(newToken);
|
|
1288
1447
|
setSessionValid(true);
|
|
1448
|
+
if (newToken) setLoading(true);
|
|
1289
1449
|
},
|
|
1290
1450
|
clearToken: () => {
|
|
1291
1451
|
stopSessionSecurity();
|
|
@@ -1470,6 +1630,9 @@ var auth = {
|
|
|
1470
1630
|
getToken,
|
|
1471
1631
|
setToken,
|
|
1472
1632
|
clearToken,
|
|
1633
|
+
setIdToken,
|
|
1634
|
+
getIdToken,
|
|
1635
|
+
clearIdToken,
|
|
1473
1636
|
setRefreshToken,
|
|
1474
1637
|
// ✅ Refresh token for HTTP dev
|
|
1475
1638
|
getRefreshToken,
|