antaeus.keycloak.react 2.0.0 → 2.1.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/dist/index.js +82 -26
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +82 -26
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -14,7 +14,7 @@ var defaultConfig = {
|
|
|
14
14
|
scope: "openid profile email offline_access",
|
|
15
15
|
features: {
|
|
16
16
|
deviceFlow: false,
|
|
17
|
-
sessionMonitor:
|
|
17
|
+
sessionMonitor: true,
|
|
18
18
|
autoRefresh: true
|
|
19
19
|
},
|
|
20
20
|
silentRenew: {
|
|
@@ -59,7 +59,11 @@ var KeycloakConfigBuilder = class {
|
|
|
59
59
|
scope: config.scope,
|
|
60
60
|
automaticSilentRenew: config.silentRenew.enabled,
|
|
61
61
|
loadUserInfo: config.advanced.loadUserInfo,
|
|
62
|
-
silent_redirect_uri: config.silentRenew.silentRedirectUri
|
|
62
|
+
silent_redirect_uri: config.silentRenew.silentRedirectUri,
|
|
63
|
+
// Add PKCE support (required for public clients)
|
|
64
|
+
...config.advanced.codeChallengeMethod && {
|
|
65
|
+
response_mode: "query"
|
|
66
|
+
}
|
|
63
67
|
};
|
|
64
68
|
return oidcSettings;
|
|
65
69
|
}
|
|
@@ -197,14 +201,14 @@ function useTokenLifecycle(options) {
|
|
|
197
201
|
log("Refresh already in progress, skipping");
|
|
198
202
|
return;
|
|
199
203
|
}
|
|
200
|
-
|
|
201
|
-
log("Refresh token exceeded max lifetime, cannot refresh");
|
|
202
|
-
setIsRefreshTokenExpired(true);
|
|
203
|
-
onRefreshTokenExpired?.();
|
|
204
|
-
return;
|
|
205
|
-
}
|
|
204
|
+
setIsRefreshing(true);
|
|
206
205
|
try {
|
|
207
|
-
|
|
206
|
+
if (checkRefreshTokenLifetime()) {
|
|
207
|
+
log("Refresh token exceeded max lifetime, cannot refresh");
|
|
208
|
+
setIsRefreshTokenExpired(true);
|
|
209
|
+
onRefreshTokenExpired?.();
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
208
212
|
onRefreshStart?.();
|
|
209
213
|
log("Starting token refresh");
|
|
210
214
|
await auth.signinSilent();
|
|
@@ -239,7 +243,11 @@ function useTokenLifecycle(options) {
|
|
|
239
243
|
onRefreshTokenExpired?.();
|
|
240
244
|
const key = getStorageKey();
|
|
241
245
|
localStorage.removeItem(key);
|
|
242
|
-
|
|
246
|
+
try {
|
|
247
|
+
await auth.removeUser();
|
|
248
|
+
} catch (error) {
|
|
249
|
+
log("Error removing user after max lifetime:", error);
|
|
250
|
+
}
|
|
243
251
|
return false;
|
|
244
252
|
}
|
|
245
253
|
const expiresAt = auth.user.expires_at;
|
|
@@ -318,7 +326,9 @@ function useTokenLifecycle(options) {
|
|
|
318
326
|
onRefreshTokenExpired?.();
|
|
319
327
|
const key = getStorageKey();
|
|
320
328
|
localStorage.removeItem(key);
|
|
321
|
-
auth.removeUser()
|
|
329
|
+
auth.removeUser().catch((error) => {
|
|
330
|
+
log("Error removing user during periodic check:", error);
|
|
331
|
+
});
|
|
322
332
|
}
|
|
323
333
|
}, 5 * 60 * 1e3);
|
|
324
334
|
return () => clearInterval(intervalId);
|
|
@@ -495,22 +505,28 @@ var SessionMonitor = ({
|
|
|
495
505
|
}) => {
|
|
496
506
|
const auth = useAuth();
|
|
497
507
|
const [timeRemaining, setTimeRemaining] = useState(null);
|
|
508
|
+
const [initialTimeRemaining, setInitialTimeRemaining] = useState(null);
|
|
498
509
|
const [minimized, setMinimized] = useState(startMinimized);
|
|
499
510
|
const [warningTriggered, setWarningTriggered] = useState(false);
|
|
500
511
|
const [criticalTriggered, setCriticalTriggered] = useState(false);
|
|
501
512
|
useEffect(() => {
|
|
502
513
|
if (!auth.isAuthenticated || !auth.user?.expires_at) {
|
|
503
514
|
setTimeRemaining(null);
|
|
515
|
+
setInitialTimeRemaining(null);
|
|
504
516
|
return;
|
|
505
517
|
}
|
|
518
|
+
let logoutTimeoutId = null;
|
|
506
519
|
const updateTimeRemaining = () => {
|
|
507
520
|
const expiresAt = auth.user.expires_at;
|
|
508
521
|
const now = Math.floor(Date.now() / 1e3);
|
|
509
522
|
const remaining = expiresAt - now;
|
|
523
|
+
if (initialTimeRemaining === null && remaining > 0) {
|
|
524
|
+
setInitialTimeRemaining(remaining);
|
|
525
|
+
}
|
|
510
526
|
if (remaining <= 0) {
|
|
511
527
|
setTimeRemaining(0);
|
|
512
528
|
onExpired?.();
|
|
513
|
-
setTimeout(() => {
|
|
529
|
+
logoutTimeoutId = setTimeout(() => {
|
|
514
530
|
auth.signoutRedirect();
|
|
515
531
|
}, 2e3);
|
|
516
532
|
} else {
|
|
@@ -526,13 +542,19 @@ var SessionMonitor = ({
|
|
|
526
542
|
};
|
|
527
543
|
updateTimeRemaining();
|
|
528
544
|
const interval = setInterval(updateTimeRemaining, 1e3);
|
|
529
|
-
return () =>
|
|
545
|
+
return () => {
|
|
546
|
+
clearInterval(interval);
|
|
547
|
+
if (logoutTimeoutId) {
|
|
548
|
+
clearTimeout(logoutTimeoutId);
|
|
549
|
+
}
|
|
550
|
+
};
|
|
530
551
|
}, [
|
|
531
552
|
auth,
|
|
532
553
|
warningThreshold,
|
|
533
554
|
criticalThreshold,
|
|
534
555
|
warningTriggered,
|
|
535
556
|
criticalTriggered,
|
|
557
|
+
initialTimeRemaining,
|
|
536
558
|
onWarning,
|
|
537
559
|
onCritical,
|
|
538
560
|
onExpired
|
|
@@ -555,9 +577,9 @@ var SessionMonitor = ({
|
|
|
555
577
|
return "normal";
|
|
556
578
|
}, [timeRemaining, warningThreshold, criticalThreshold]);
|
|
557
579
|
const getProgress = useCallback(() => {
|
|
558
|
-
if (!timeRemaining || !
|
|
559
|
-
return timeRemaining /
|
|
560
|
-
}, [timeRemaining,
|
|
580
|
+
if (!timeRemaining || !initialTimeRemaining) return 100;
|
|
581
|
+
return Math.max(0, Math.min(100, timeRemaining / initialTimeRemaining * 100));
|
|
582
|
+
}, [timeRemaining, initialTimeRemaining]);
|
|
561
583
|
if (!auth.isAuthenticated || timeRemaining === null) {
|
|
562
584
|
return null;
|
|
563
585
|
}
|
|
@@ -870,12 +892,27 @@ function buildZeroConfig(props) {
|
|
|
870
892
|
const { authority, clientId, preset = "default", config: overrides = {} } = props;
|
|
871
893
|
const presetConfig = mergeWithPreset(preset, overrides);
|
|
872
894
|
const fullConfig = {
|
|
873
|
-
...defaultConfig,
|
|
874
|
-
...presetConfig,
|
|
875
895
|
authority,
|
|
876
896
|
clientId,
|
|
877
|
-
redirectUri: presetConfig.redirectUri || (typeof window !== "undefined" ? window.location.origin + "/" : "/"),
|
|
878
|
-
postLogoutRedirectUri: presetConfig.postLogoutRedirectUri || (typeof window !== "undefined" ? window.location.origin + "/" : "/")
|
|
897
|
+
redirectUri: presetConfig.redirectUri || defaultConfig.redirectUri || (typeof window !== "undefined" ? window.location.origin + "/" : "/"),
|
|
898
|
+
postLogoutRedirectUri: presetConfig.postLogoutRedirectUri || defaultConfig.postLogoutRedirectUri || (typeof window !== "undefined" ? window.location.origin + "/" : "/"),
|
|
899
|
+
scope: presetConfig.scope || defaultConfig.scope,
|
|
900
|
+
features: {
|
|
901
|
+
...defaultConfig.features,
|
|
902
|
+
...presetConfig.features
|
|
903
|
+
},
|
|
904
|
+
silentRenew: {
|
|
905
|
+
...defaultConfig.silentRenew,
|
|
906
|
+
...presetConfig.silentRenew
|
|
907
|
+
},
|
|
908
|
+
advanced: {
|
|
909
|
+
...defaultConfig.advanced,
|
|
910
|
+
...presetConfig.advanced
|
|
911
|
+
},
|
|
912
|
+
events: {
|
|
913
|
+
...defaultConfig.events,
|
|
914
|
+
...presetConfig.events
|
|
915
|
+
}
|
|
879
916
|
};
|
|
880
917
|
return fullConfig;
|
|
881
918
|
}
|
|
@@ -970,6 +1007,7 @@ var ProtectedRoute = ({
|
|
|
970
1007
|
const { hasAnyRole, hasAllRoles } = useRoles();
|
|
971
1008
|
const { hasAnyScope, hasAllScopes } = useScopes();
|
|
972
1009
|
const location = useLocation();
|
|
1010
|
+
const hasRedirected = useRef(false);
|
|
973
1011
|
const isAuthenticated = !auth.isLoading && auth.isAuthenticated;
|
|
974
1012
|
const policyAccess = policy && auth.user ? policy(auth.user, { location }) : null;
|
|
975
1013
|
const roleAccess = requiredRoles.length > 0 ? requireAllRoles ? hasAllRoles(requiredRoles) : hasAnyRole(requiredRoles) : null;
|
|
@@ -981,12 +1019,21 @@ var ProtectedRoute = ({
|
|
|
981
1019
|
}
|
|
982
1020
|
}, [unauthorizedReason, onUnauthorized]);
|
|
983
1021
|
useEffect(() => {
|
|
984
|
-
if (!auth.isLoading && !auth.isAuthenticated) {
|
|
1022
|
+
if (!auth.isLoading && !auth.isAuthenticated && !hasRedirected.current) {
|
|
1023
|
+
hasRedirected.current = true;
|
|
985
1024
|
auth.signinRedirect({
|
|
986
1025
|
redirect_uri: window.location.origin + location.pathname + location.search
|
|
1026
|
+
}).catch((error) => {
|
|
1027
|
+
hasRedirected.current = false;
|
|
1028
|
+
console.error("[ProtectedRoute] Signin redirect failed:", error);
|
|
987
1029
|
});
|
|
988
1030
|
}
|
|
989
|
-
}, [auth.isLoading, auth.isAuthenticated,
|
|
1031
|
+
}, [auth.isLoading, auth.isAuthenticated, location.pathname, location.search]);
|
|
1032
|
+
useEffect(() => {
|
|
1033
|
+
if (auth.isAuthenticated) {
|
|
1034
|
+
hasRedirected.current = false;
|
|
1035
|
+
}
|
|
1036
|
+
}, [auth.isAuthenticated]);
|
|
990
1037
|
if (auth.isLoading) {
|
|
991
1038
|
return /* @__PURE__ */ jsx(Fragment, { children: loadingComponent || /* @__PURE__ */ jsx(DefaultLoadingComponent, {}) });
|
|
992
1039
|
}
|
|
@@ -1354,8 +1401,17 @@ var DeviceLogin = ({
|
|
|
1354
1401
|
});
|
|
1355
1402
|
if (userManagerRef.current) {
|
|
1356
1403
|
await userManagerRef.current.storeUser(user);
|
|
1404
|
+
const events = userManagerRef.current.events;
|
|
1405
|
+
if (events && events._userLoaded) {
|
|
1406
|
+
events._userLoaded.raise(user);
|
|
1407
|
+
}
|
|
1408
|
+
}
|
|
1409
|
+
if (onSuccess) {
|
|
1410
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
1411
|
+
onSuccess(user);
|
|
1412
|
+
} else {
|
|
1413
|
+
window.location.reload();
|
|
1357
1414
|
}
|
|
1358
|
-
onSuccess?.(user);
|
|
1359
1415
|
}
|
|
1360
1416
|
} catch (err) {
|
|
1361
1417
|
if (!err.message.includes("authorization_pending")) {
|
|
@@ -1442,14 +1498,14 @@ function useProtectedFetch(options = {}) {
|
|
|
1442
1498
|
},
|
|
1443
1499
|
[baseUrl]
|
|
1444
1500
|
);
|
|
1445
|
-
const getAuthHeader =
|
|
1501
|
+
const getAuthHeader = () => {
|
|
1446
1502
|
if (!auth.user?.access_token) {
|
|
1447
1503
|
return {};
|
|
1448
1504
|
}
|
|
1449
1505
|
return {
|
|
1450
1506
|
Authorization: `Bearer ${auth.user.access_token}`
|
|
1451
1507
|
};
|
|
1452
|
-
}
|
|
1508
|
+
};
|
|
1453
1509
|
const buildHeaders = useCallback(
|
|
1454
1510
|
(requestHeaders) => {
|
|
1455
1511
|
const headers = new Headers(requestHeaders);
|
|
@@ -1462,7 +1518,7 @@ function useProtectedFetch(options = {}) {
|
|
|
1462
1518
|
});
|
|
1463
1519
|
return headers;
|
|
1464
1520
|
},
|
|
1465
|
-
[
|
|
1521
|
+
[customHeaders]
|
|
1466
1522
|
);
|
|
1467
1523
|
const protectedFetch = useCallback(
|
|
1468
1524
|
async (url, init) => {
|