@spidy092/auth-client 3.1.2 → 3.1.4
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 +117 -61
- package/dist/api.cjs.map +1 -1
- package/dist/api.js +117 -61
- package/dist/api.js.map +1 -1
- package/dist/index.cjs +290 -96
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +290 -96
- package/dist/index.js.map +1 -1
- package/dist/preferences.cjs +117 -61
- package/dist/preferences.cjs.map +1 -1
- package/dist/preferences.js +117 -61
- package/dist/preferences.js.map +1 -1
- package/dist/react/AuthProvider.cjs +266 -96
- package/dist/react/AuthProvider.cjs.map +1 -1
- package/dist/react/AuthProvider.js +266 -96
- package/dist/react/AuthProvider.js.map +1 -1
- package/dist/react/PreferencesProvider.cjs +117 -61
- package/dist/react/PreferencesProvider.cjs.map +1 -1
- package/dist/react/PreferencesProvider.js +117 -61
- package/dist/react/PreferencesProvider.js.map +1 -1
- package/dist/react/useAuth.cjs +7 -0
- package/dist/react/useAuth.cjs.map +1 -1
- package/dist/react/useAuth.js +7 -0
- package/dist/react/useAuth.js.map +1 -1
- package/dist/react/useSessionMonitor.cjs +157 -66
- package/dist/react/useSessionMonitor.cjs.map +1 -1
- package/dist/react/useSessionMonitor.js +157 -66
- package/dist/react/useSessionMonitor.js.map +1 -1
- package/package.json +1 -1
|
@@ -221,6 +221,44 @@ var config = {
|
|
|
221
221
|
// ⚠️ In true production, set to false and rely on httpOnly cookies
|
|
222
222
|
persistRefreshToken: false
|
|
223
223
|
};
|
|
224
|
+
var RUNTIME_POLICY_DEFAULTS = {
|
|
225
|
+
tokenRefreshBuffer: 60,
|
|
226
|
+
sessionValidationInterval: 15 * 60 * 1e3,
|
|
227
|
+
enableSessionValidation: true,
|
|
228
|
+
enableProactiveRefresh: true,
|
|
229
|
+
validateOnVisibility: true
|
|
230
|
+
};
|
|
231
|
+
function validateRuntimePolicy(policy = {}) {
|
|
232
|
+
const numberInRange = (value, min, max) => Number.isInteger(value) && value >= min && value <= max;
|
|
233
|
+
const result = { ...RUNTIME_POLICY_DEFAULTS };
|
|
234
|
+
if (numberInRange(policy.tokenRefreshBuffer, 10, 300)) result.tokenRefreshBuffer = policy.tokenRefreshBuffer;
|
|
235
|
+
if (numberInRange(policy.sessionValidationInterval, 6e4, 864e5)) result.sessionValidationInterval = policy.sessionValidationInterval;
|
|
236
|
+
for (const key of ["enableSessionValidation", "enableProactiveRefresh", "validateOnVisibility"]) {
|
|
237
|
+
if (typeof policy[key] === "boolean") result[key] = policy[key];
|
|
238
|
+
}
|
|
239
|
+
return result;
|
|
240
|
+
}
|
|
241
|
+
function applyRuntimePolicy(policy = {}) {
|
|
242
|
+
config = { ...config, ...validateRuntimePolicy(policy) };
|
|
243
|
+
return getConfig();
|
|
244
|
+
}
|
|
245
|
+
async function loadRuntimePolicy() {
|
|
246
|
+
const { authBaseUrl, clientKey } = config;
|
|
247
|
+
if (!authBaseUrl || !clientKey || typeof fetch !== "function") return getConfig();
|
|
248
|
+
try {
|
|
249
|
+
const response = await fetch(`${authBaseUrl.replace(/\/+$/, "")}/clients/${encodeURIComponent(clientKey)}/config`, {
|
|
250
|
+
method: "GET",
|
|
251
|
+
credentials: "include",
|
|
252
|
+
headers: { Accept: "application/json" }
|
|
253
|
+
});
|
|
254
|
+
if (!response.ok) throw new Error(`runtime policy HTTP ${response.status}`);
|
|
255
|
+
const payload = await response.json();
|
|
256
|
+
return applyRuntimePolicy(payload.authentication_policy || {});
|
|
257
|
+
} catch (error) {
|
|
258
|
+
console.warn("[auth-client] Runtime policy unavailable; using safe defaults", error.message);
|
|
259
|
+
return applyRuntimePolicy({});
|
|
260
|
+
}
|
|
261
|
+
}
|
|
224
262
|
function setConfig(customConfig = {}) {
|
|
225
263
|
if (!customConfig.clientKey || !customConfig.authBaseUrl) {
|
|
226
264
|
throw new Error("Missing required config: clientKey and authBaseUrl are required");
|
|
@@ -306,6 +344,28 @@ function clearLoginLock() {
|
|
|
306
344
|
} catch {
|
|
307
345
|
}
|
|
308
346
|
}
|
|
347
|
+
async function reportClientDiagnostic(safe) {
|
|
348
|
+
if (typeof fetch !== "function" || typeof getToken !== "function") return;
|
|
349
|
+
if (safe.outcome === "SUCCESS" && !safe.event.startsWith("PROFILE_") && !safe.event.startsWith("SESSION_")) return;
|
|
350
|
+
const { authBaseUrl } = getConfig();
|
|
351
|
+
const token = getToken();
|
|
352
|
+
if (!authBaseUrl || !token) return;
|
|
353
|
+
try {
|
|
354
|
+
await fetch(`${authBaseUrl.replace(/\/+$/, "")}/client-telemetry`, {
|
|
355
|
+
method: "POST",
|
|
356
|
+
credentials: "include",
|
|
357
|
+
keepalive: true,
|
|
358
|
+
headers: {
|
|
359
|
+
"Content-Type": "application/json",
|
|
360
|
+
Authorization: `Bearer ${token}`,
|
|
361
|
+
"X-Correlation-ID": safe.correlationId,
|
|
362
|
+
"X-Request-ID": safe.correlationId
|
|
363
|
+
},
|
|
364
|
+
body: JSON.stringify(safe)
|
|
365
|
+
});
|
|
366
|
+
} catch {
|
|
367
|
+
}
|
|
368
|
+
}
|
|
309
369
|
async function emitAuthDiagnostic(event, outcome, reasonCode, details = {}) {
|
|
310
370
|
const context = getDiagnosticContext();
|
|
311
371
|
const safe = {
|
|
@@ -322,12 +382,13 @@ async function emitAuthDiagnostic(event, outcome, reasonCode, details = {}) {
|
|
|
322
382
|
};
|
|
323
383
|
const method = outcome === "FAILURE" ? "error" : outcome === "WARNING" ? "warn" : "info";
|
|
324
384
|
console[method]("[auth-client]", safe);
|
|
385
|
+
void reportClientDiagnostic(safe);
|
|
325
386
|
return safe;
|
|
326
387
|
}
|
|
327
388
|
|
|
328
389
|
// core.js
|
|
329
390
|
var callbackProcessed = false;
|
|
330
|
-
function login(clientKeyArg, redirectUriArg) {
|
|
391
|
+
function login(clientKeyArg, redirectUriArg, options = {}) {
|
|
331
392
|
resetCallbackState();
|
|
332
393
|
const {
|
|
333
394
|
clientKey: defaultClientKey,
|
|
@@ -350,23 +411,24 @@ function login(clientKeyArg, redirectUriArg) {
|
|
|
350
411
|
sessionStorage.setItem("originalApp", clientKey);
|
|
351
412
|
sessionStorage.setItem("returnUrl", redirectUri);
|
|
352
413
|
if (isRouterMode()) {
|
|
353
|
-
return routerLogin(clientKey, redirectUri);
|
|
414
|
+
return routerLogin(clientKey, redirectUri, options);
|
|
354
415
|
} else {
|
|
355
|
-
return clientLogin(clientKey, redirectUri);
|
|
416
|
+
return clientLogin(clientKey, redirectUri, options);
|
|
356
417
|
}
|
|
357
418
|
}
|
|
358
|
-
function routerLogin(clientKey, redirectUri) {
|
|
419
|
+
function routerLogin(clientKey, redirectUri, options = {}) {
|
|
359
420
|
const { authBaseUrl } = getConfig();
|
|
360
421
|
const params = new URLSearchParams();
|
|
361
422
|
if (redirectUri) {
|
|
362
423
|
params.append("redirect_uri", redirectUri);
|
|
363
424
|
}
|
|
425
|
+
if (options.switchAccount || options.switch_account) params.append("switch_account", "true");
|
|
364
426
|
params.append("correlation_id", getDiagnosticContext().correlationId);
|
|
365
427
|
const query = params.toString();
|
|
366
428
|
const backendLoginUrl = `${authBaseUrl}/login/${clientKey}${query ? `?${query}` : ""}`;
|
|
367
429
|
window.location.href = backendLoginUrl;
|
|
368
430
|
}
|
|
369
|
-
function clientLogin(clientKey, redirectUri) {
|
|
431
|
+
function clientLogin(clientKey, redirectUri, options = {}) {
|
|
370
432
|
const { accountUiUrl } = getConfig();
|
|
371
433
|
const params = new URLSearchParams({
|
|
372
434
|
client: clientKey
|
|
@@ -374,6 +436,7 @@ function clientLogin(clientKey, redirectUri) {
|
|
|
374
436
|
if (redirectUri) {
|
|
375
437
|
params.append("redirect_uri", redirectUri);
|
|
376
438
|
}
|
|
439
|
+
if (options.switchAccount || options.switch_account) params.append("switch_account", "true");
|
|
377
440
|
const centralizedLoginUrl = `${accountUiUrl}/login?${params.toString()}`;
|
|
378
441
|
window.location.href = centralizedLoginUrl;
|
|
379
442
|
}
|
|
@@ -499,6 +562,28 @@ function resetCallbackState() {
|
|
|
499
562
|
}
|
|
500
563
|
var refreshInProgress = false;
|
|
501
564
|
var refreshPromise = null;
|
|
565
|
+
async function withCrossTabRefreshLock(clientKey, tokenBeforeRefresh, refreshRequest) {
|
|
566
|
+
var _a;
|
|
567
|
+
const lockName = `auth-refresh-${clientKey}`;
|
|
568
|
+
const run = async () => {
|
|
569
|
+
try {
|
|
570
|
+
const persistedToken = localStorage.getItem("authToken");
|
|
571
|
+
if (tokenBeforeRefresh && persistedToken && persistedToken !== tokenBeforeRefresh) {
|
|
572
|
+
setToken(persistedToken);
|
|
573
|
+
emitAuthDiagnostic("TOKEN_REFRESH_REUSED_CROSS_TAB", "SUCCESS", "CROSS_TAB_ROTATION", {
|
|
574
|
+
clientKey
|
|
575
|
+
});
|
|
576
|
+
return persistedToken;
|
|
577
|
+
}
|
|
578
|
+
} catch {
|
|
579
|
+
}
|
|
580
|
+
return refreshRequest();
|
|
581
|
+
};
|
|
582
|
+
if (typeof navigator !== "undefined" && ((_a = navigator.locks) == null ? void 0 : _a.request)) {
|
|
583
|
+
return navigator.locks.request(lockName, run);
|
|
584
|
+
}
|
|
585
|
+
return run();
|
|
586
|
+
}
|
|
502
587
|
async function refreshToken() {
|
|
503
588
|
const { clientKey, authBaseUrl } = getConfig();
|
|
504
589
|
if (refreshInProgress && refreshPromise) {
|
|
@@ -507,70 +592,74 @@ async function refreshToken() {
|
|
|
507
592
|
}
|
|
508
593
|
refreshInProgress = true;
|
|
509
594
|
refreshPromise = (async () => {
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
hasStoredRefreshToken: !!storedRefreshToken
|
|
517
|
-
});
|
|
518
|
-
const requestOptions = {
|
|
519
|
-
method: "POST",
|
|
520
|
-
credentials: "include",
|
|
521
|
-
// ✅ Include httpOnly cookies (for HTTPS)
|
|
522
|
-
headers: {
|
|
523
|
-
...diagnosticHeaders(),
|
|
524
|
-
"Content-Type": "application/json"
|
|
525
|
-
}
|
|
526
|
-
};
|
|
527
|
-
if (storedRefreshToken) {
|
|
528
|
-
requestOptions.body = JSON.stringify({ refreshToken: storedRefreshToken });
|
|
529
|
-
console.log("\u{1F4E6} Sending refresh token in body only (Header skipped) v3.0.2");
|
|
530
|
-
}
|
|
531
|
-
const response = await fetch(`${authBaseUrl}/refresh/${clientKey}`, requestOptions);
|
|
532
|
-
if (!response.ok) {
|
|
533
|
-
const errorText = await response.text();
|
|
534
|
-
let serverCode = null;
|
|
535
|
-
try {
|
|
536
|
-
serverCode = ((_a = JSON.parse(errorText)) == null ? void 0 : _a.error) || ((_b = JSON.parse(errorText)) == null ? void 0 : _b.code);
|
|
537
|
-
} catch {
|
|
538
|
-
}
|
|
539
|
-
emitAuthDiagnostic("TOKEN_REFRESH_REJECTED", "FAILURE", serverCode || `HTTP_${response.status}`, {
|
|
595
|
+
const tokenBeforeRefresh = getToken();
|
|
596
|
+
const refreshRequest = async () => {
|
|
597
|
+
var _a, _b, _c, _d, _e, _f;
|
|
598
|
+
try {
|
|
599
|
+
const storedRefreshToken = getRefreshToken();
|
|
600
|
+
console.log("\u{1F504} Refreshing token:", {
|
|
540
601
|
clientKey,
|
|
541
|
-
|
|
602
|
+
mode: isRouterMode() ? "ROUTER" : "CLIENT",
|
|
603
|
+
hasStoredRefreshToken: !!storedRefreshToken
|
|
542
604
|
});
|
|
543
|
-
const
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
605
|
+
const requestOptions = {
|
|
606
|
+
method: "POST",
|
|
607
|
+
credentials: "include",
|
|
608
|
+
// ✅ Include httpOnly cookies (for HTTPS)
|
|
609
|
+
headers: {
|
|
610
|
+
...diagnosticHeaders(),
|
|
611
|
+
"Content-Type": "application/json"
|
|
612
|
+
}
|
|
613
|
+
};
|
|
614
|
+
if (storedRefreshToken) {
|
|
615
|
+
requestOptions.body = JSON.stringify({ refreshToken: storedRefreshToken });
|
|
616
|
+
console.log("\u{1F4E6} Sending refresh token in body only (Header skipped) v3.0.2");
|
|
617
|
+
}
|
|
618
|
+
const response = await fetch(`${authBaseUrl}/refresh/${clientKey}`, requestOptions);
|
|
619
|
+
if (!response.ok) {
|
|
620
|
+
const errorText = await response.text();
|
|
621
|
+
let serverCode = null;
|
|
622
|
+
try {
|
|
623
|
+
serverCode = ((_a = JSON.parse(errorText)) == null ? void 0 : _a.error) || ((_b = JSON.parse(errorText)) == null ? void 0 : _b.code);
|
|
624
|
+
} catch {
|
|
625
|
+
}
|
|
626
|
+
emitAuthDiagnostic("TOKEN_REFRESH_REJECTED", "FAILURE", serverCode || `HTTP_${response.status}`, {
|
|
627
|
+
clientKey,
|
|
628
|
+
status: response.status
|
|
629
|
+
});
|
|
630
|
+
const refreshError = new Error(`Refresh failed: ${response.status}`);
|
|
631
|
+
refreshError.code = serverCode || `HTTP_${response.status}`;
|
|
632
|
+
refreshError.status = response.status;
|
|
633
|
+
throw refreshError;
|
|
634
|
+
}
|
|
635
|
+
const data = await response.json();
|
|
636
|
+
const { access_token, refresh_token: new_refresh_token } = data;
|
|
637
|
+
if (!access_token) {
|
|
638
|
+
throw new Error("No access token in refresh response");
|
|
639
|
+
}
|
|
640
|
+
setToken(access_token);
|
|
641
|
+
if (new_refresh_token) {
|
|
642
|
+
setRefreshToken(new_refresh_token);
|
|
643
|
+
console.log("\u{1F504} New refresh token stored from rotation");
|
|
644
|
+
}
|
|
645
|
+
console.log("\u2705 Token refresh successful, listeners notified");
|
|
646
|
+
emitAuthDiagnostic("TOKEN_REFRESH_COMPLETED", "SUCCESS", "NONE", { clientKey });
|
|
647
|
+
return access_token;
|
|
648
|
+
} catch (err) {
|
|
649
|
+
console.error("\u274C Token refresh error:", err);
|
|
650
|
+
const isAuthRejection = ((_c = err.message) == null ? void 0 : _c.includes("401")) || ((_d = err.message) == null ? void 0 : _d.includes("403")) || ((_e = err.message) == null ? void 0 : _e.includes("invalid_grant")) || ((_f = err.message) == null ? void 0 : _f.includes("Refresh failed: 4"));
|
|
651
|
+
if (isAuthRejection) {
|
|
652
|
+
clearToken();
|
|
653
|
+
clearRefreshToken();
|
|
654
|
+
}
|
|
655
|
+
throw err;
|
|
567
656
|
}
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
})
|
|
657
|
+
};
|
|
658
|
+
return withCrossTabRefreshLock(clientKey, tokenBeforeRefresh, refreshRequest);
|
|
659
|
+
})().finally(() => {
|
|
660
|
+
refreshInProgress = false;
|
|
661
|
+
refreshPromise = null;
|
|
662
|
+
});
|
|
574
663
|
return refreshPromise;
|
|
575
664
|
}
|
|
576
665
|
async function validateCurrentSession() {
|
|
@@ -1135,6 +1224,8 @@ var PreferencesContext = createContext2(null);
|
|
|
1135
1224
|
var auth = {
|
|
1136
1225
|
// 🔧 Config
|
|
1137
1226
|
setConfig,
|
|
1227
|
+
applyRuntimePolicy,
|
|
1228
|
+
loadRuntimePolicy,
|
|
1138
1229
|
getConfig,
|
|
1139
1230
|
isRouterMode,
|
|
1140
1231
|
// 🔐 Core flows
|