oidc-spa 8.1.4 → 8.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/README.md +5 -7
- package/core/createOidc.js +85 -35
- package/core/createOidc.js.map +1 -1
- package/core/diagnostic.d.ts +1 -0
- package/core/diagnostic.js +5 -4
- package/core/diagnostic.js.map +1 -1
- package/core/isNewBrowserSession.d.ts +1 -1
- package/core/isNewBrowserSession.js +2 -2
- package/core/isNewBrowserSession.js.map +1 -1
- package/core/loginOrGoToAuthServer.d.ts +3 -2
- package/core/loginOrGoToAuthServer.js +45 -29
- package/core/loginOrGoToAuthServer.js.map +1 -1
- package/core/loginSilent.d.ts +1 -0
- package/core/loginSilent.js +10 -1
- package/core/loginSilent.js.map +1 -1
- package/core/ongoingLoginOrRefreshProcesses.js.map +1 -1
- package/esm/core/createOidc.js +86 -36
- package/esm/core/createOidc.js.map +1 -1
- package/esm/core/diagnostic.d.ts +1 -0
- package/esm/core/diagnostic.js +1 -1
- package/esm/core/diagnostic.js.map +1 -1
- package/esm/core/isNewBrowserSession.d.ts +1 -1
- package/esm/core/isNewBrowserSession.js +2 -2
- package/esm/core/isNewBrowserSession.js.map +1 -1
- package/esm/core/loginOrGoToAuthServer.d.ts +3 -2
- package/esm/core/loginOrGoToAuthServer.js +44 -28
- package/esm/core/loginOrGoToAuthServer.js.map +1 -1
- package/esm/core/loginSilent.d.ts +1 -0
- package/esm/core/loginSilent.js +10 -1
- package/esm/core/loginSilent.js.map +1 -1
- package/esm/core/ongoingLoginOrRefreshProcesses.js.map +1 -1
- package/package.json +1 -1
- package/src/core/createOidc.ts +110 -38
- package/src/core/diagnostic.ts +2 -2
- package/src/core/isNewBrowserSession.ts +3 -3
- package/src/core/loginOrGoToAuthServer.ts +59 -31
- package/src/core/loginSilent.ts +13 -1
- package/src/core/ongoingLoginOrRefreshProcesses.ts +8 -0
- package/vendor/backend/tsafe.js +1 -1
package/src/core/createOidc.ts
CHANGED
|
@@ -38,7 +38,7 @@ import { createEvt } from "../tools/Evt";
|
|
|
38
38
|
import { getHaveSharedParentDomain } from "../tools/haveSharedParentDomain";
|
|
39
39
|
import {
|
|
40
40
|
createLoginOrGoToAuthServer,
|
|
41
|
-
|
|
41
|
+
getPrSafelyRestoredFromBfCacheAfterLoginBackNavigationOrInitializationError
|
|
42
42
|
} from "./loginOrGoToAuthServer";
|
|
43
43
|
import { createEphemeralSessionStorage } from "../tools/EphemeralSessionStorage";
|
|
44
44
|
import {
|
|
@@ -49,6 +49,8 @@ import { createGetIsNewBrowserSession } from "./isNewBrowserSession";
|
|
|
49
49
|
import { getIsOnline } from "../tools/getIsOnline";
|
|
50
50
|
import { isKeycloak } from "../keycloak/isKeycloak";
|
|
51
51
|
import { INFINITY_TIME } from "../tools/INFINITY_TIME";
|
|
52
|
+
import type { WELL_KNOWN_PATH } from "./diagnostic";
|
|
53
|
+
import { getIsValidRemoteJson } from "../tools/getIsValidRemoteJson";
|
|
52
54
|
|
|
53
55
|
// NOTE: Replaced at build time
|
|
54
56
|
const VERSION = "{{OIDC_SPA_VERSION}}";
|
|
@@ -454,7 +456,7 @@ export async function createOidc_nonMemoized<
|
|
|
454
456
|
metadata: __metadata
|
|
455
457
|
});
|
|
456
458
|
|
|
457
|
-
const
|
|
459
|
+
const evtInitializationOutcomeUserNotLoggedIn = createEvt<void>();
|
|
458
460
|
|
|
459
461
|
const { loginOrGoToAuthServer } = createLoginOrGoToAuthServer({
|
|
460
462
|
configId,
|
|
@@ -463,23 +465,13 @@ export async function createOidc_nonMemoized<
|
|
|
463
465
|
getExtraQueryParams,
|
|
464
466
|
getExtraTokenParams,
|
|
465
467
|
homeUrl: homeUrlAndRedirectUri,
|
|
466
|
-
|
|
468
|
+
evtInitializationOutcomeUserNotLoggedIn,
|
|
467
469
|
log
|
|
468
470
|
});
|
|
469
471
|
|
|
470
472
|
const { getIsNewBrowserSession } = createGetIsNewBrowserSession({
|
|
471
473
|
configId,
|
|
472
|
-
|
|
473
|
-
const evt = createEvt<void>();
|
|
474
|
-
|
|
475
|
-
evtIsUserLoggedIn.subscribe(isUserLoggedIn => {
|
|
476
|
-
if (!isUserLoggedIn) {
|
|
477
|
-
evt.post();
|
|
478
|
-
}
|
|
479
|
-
});
|
|
480
|
-
|
|
481
|
-
return evt;
|
|
482
|
-
})()
|
|
474
|
+
evtInitializationOutcomeUserNotLoggedIn
|
|
483
475
|
});
|
|
484
476
|
|
|
485
477
|
const { completeLoginOrRefreshProcess } = await startLoginOrRefreshProcess();
|
|
@@ -673,6 +665,8 @@ export async function createOidc_nonMemoized<
|
|
|
673
665
|
}
|
|
674
666
|
}
|
|
675
667
|
|
|
668
|
+
// NOTE: We almost never persist tokens, we have to only to support edge case
|
|
669
|
+
// of multiple oidc instance in a single App with no iframe support.
|
|
676
670
|
restore_from_session_storage: {
|
|
677
671
|
if (isUserStoreInMemoryOnly) {
|
|
678
672
|
break restore_from_session_storage;
|
|
@@ -744,6 +738,20 @@ export async function createOidc_nonMemoized<
|
|
|
744
738
|
}
|
|
745
739
|
|
|
746
740
|
if (!canUseIframe) {
|
|
741
|
+
if (
|
|
742
|
+
!(await getIsValidRemoteJson(
|
|
743
|
+
`${issuerUri}${id<typeof WELL_KNOWN_PATH>(
|
|
744
|
+
"/.well-known/openid-configuration"
|
|
745
|
+
)}`
|
|
746
|
+
))
|
|
747
|
+
) {
|
|
748
|
+
return (
|
|
749
|
+
await import("./diagnostic")
|
|
750
|
+
).createWellKnownOidcConfigurationEndpointUnreachableInitializationError({
|
|
751
|
+
issuerUri
|
|
752
|
+
});
|
|
753
|
+
}
|
|
754
|
+
|
|
747
755
|
break actual_silent_signin;
|
|
748
756
|
}
|
|
749
757
|
|
|
@@ -758,7 +766,8 @@ export async function createOidc_nonMemoized<
|
|
|
758
766
|
transformUrlBeforeRedirect,
|
|
759
767
|
getExtraQueryParams,
|
|
760
768
|
getExtraTokenParams,
|
|
761
|
-
autoLogin
|
|
769
|
+
autoLogin,
|
|
770
|
+
log
|
|
762
771
|
});
|
|
763
772
|
|
|
764
773
|
assert(result_loginSilent.outcome !== "token refreshed using refresh token", "876995");
|
|
@@ -832,11 +841,12 @@ export async function createOidc_nonMemoized<
|
|
|
832
841
|
completeLoginOrRefreshProcess();
|
|
833
842
|
|
|
834
843
|
if (autoLogin && persistedAuthState !== "logged in") {
|
|
835
|
-
|
|
844
|
+
evtInitializationOutcomeUserNotLoggedIn.post();
|
|
836
845
|
}
|
|
837
846
|
|
|
838
847
|
await waitForAllOtherOngoingLoginOrRefreshProcessesToComplete({
|
|
839
|
-
prUnlock:
|
|
848
|
+
prUnlock:
|
|
849
|
+
getPrSafelyRestoredFromBfCacheAfterLoginBackNavigationOrInitializationError()
|
|
840
850
|
});
|
|
841
851
|
|
|
842
852
|
if (persistedAuthState === "logged in") {
|
|
@@ -845,7 +855,9 @@ export async function createOidc_nonMemoized<
|
|
|
845
855
|
});
|
|
846
856
|
}
|
|
847
857
|
|
|
848
|
-
|
|
858
|
+
const dCantFetchWellKnownEndpointOrNever = new Deferred<void | never>();
|
|
859
|
+
|
|
860
|
+
loginOrGoToAuthServer({
|
|
849
861
|
action: "login",
|
|
850
862
|
doForceReloadOnBfCache: true,
|
|
851
863
|
redirectUrl: getRootRelativeOriginalLocationHref(),
|
|
@@ -864,9 +876,20 @@ export async function createOidc_nonMemoized<
|
|
|
864
876
|
}
|
|
865
877
|
|
|
866
878
|
return "ensure no interaction";
|
|
867
|
-
})()
|
|
879
|
+
})(),
|
|
880
|
+
onCantFetchWellKnownEndpointError: () => {
|
|
881
|
+
dCantFetchWellKnownEndpointOrNever.resolve();
|
|
882
|
+
}
|
|
883
|
+
});
|
|
884
|
+
|
|
885
|
+
await dCantFetchWellKnownEndpointOrNever.pr;
|
|
886
|
+
|
|
887
|
+
return (
|
|
888
|
+
await import("./diagnostic")
|
|
889
|
+
).createFailedToFetchTokenEndpointInitializationError({
|
|
890
|
+
clientId,
|
|
891
|
+
issuerUri
|
|
868
892
|
});
|
|
869
|
-
assert(false, "321389");
|
|
870
893
|
}
|
|
871
894
|
|
|
872
895
|
if (authResponse_error !== undefined) {
|
|
@@ -913,7 +936,7 @@ export async function createOidc_nonMemoized<
|
|
|
913
936
|
break not_loggedIn_case;
|
|
914
937
|
}
|
|
915
938
|
|
|
916
|
-
|
|
939
|
+
evtInitializationOutcomeUserNotLoggedIn.post();
|
|
917
940
|
|
|
918
941
|
if (getPersistedAuthState({ configId }) !== "explicitly logged out") {
|
|
919
942
|
persistAuthState({ configId, state: undefined });
|
|
@@ -970,7 +993,8 @@ export async function createOidc_nonMemoized<
|
|
|
970
993
|
transformUrlBeforeRedirect
|
|
971
994
|
}) => {
|
|
972
995
|
await waitForAllOtherOngoingLoginOrRefreshProcessesToComplete({
|
|
973
|
-
prUnlock:
|
|
996
|
+
prUnlock:
|
|
997
|
+
getPrSafelyRestoredFromBfCacheAfterLoginBackNavigationOrInitializationError()
|
|
974
998
|
});
|
|
975
999
|
|
|
976
1000
|
return loginOrGoToAuthServer({
|
|
@@ -985,7 +1009,11 @@ export async function createOidc_nonMemoized<
|
|
|
985
1009
|
interaction:
|
|
986
1010
|
getPersistedAuthState({ configId }) === "explicitly logged out"
|
|
987
1011
|
? "ensure interaction"
|
|
988
|
-
: "directly redirect if active session show login otherwise"
|
|
1012
|
+
: "directly redirect if active session show login otherwise",
|
|
1013
|
+
onCantFetchWellKnownEndpointError: () => {
|
|
1014
|
+
log?.("Login called but the auth server seems to be down..");
|
|
1015
|
+
alert("Authentication unavailable please try again later.");
|
|
1016
|
+
}
|
|
989
1017
|
});
|
|
990
1018
|
},
|
|
991
1019
|
initializationError: undefined
|
|
@@ -1017,8 +1045,6 @@ export async function createOidc_nonMemoized<
|
|
|
1017
1045
|
|
|
1018
1046
|
log?.("User is logged in");
|
|
1019
1047
|
|
|
1020
|
-
evtIsUserLoggedIn.post(true);
|
|
1021
|
-
|
|
1022
1048
|
let currentTokens = oidcClientTsUserToTokens({
|
|
1023
1049
|
oidcClientTsUser: resultOfLoginProcess.oidcClientTsUser,
|
|
1024
1050
|
decodedIdTokenSchema,
|
|
@@ -1198,7 +1224,16 @@ export async function createOidc_nonMemoized<
|
|
|
1198
1224
|
extraQueryParams_local: undefined,
|
|
1199
1225
|
transformUrlBeforeRedirect_local: undefined,
|
|
1200
1226
|
doNavigateBackToLastPublicUrlIfTheTheUserNavigateBack: false,
|
|
1201
|
-
interaction: "directly redirect if active session show login otherwise"
|
|
1227
|
+
interaction: "directly redirect if active session show login otherwise",
|
|
1228
|
+
onCantFetchWellKnownEndpointError: () => {
|
|
1229
|
+
log?.(
|
|
1230
|
+
[
|
|
1231
|
+
"The auth server seems to be down while we needed to refresh the token",
|
|
1232
|
+
"with a full page redirect. Reloading the page"
|
|
1233
|
+
].join(" ")
|
|
1234
|
+
);
|
|
1235
|
+
window.location.reload();
|
|
1236
|
+
}
|
|
1202
1237
|
});
|
|
1203
1238
|
assert(false, "136134");
|
|
1204
1239
|
};
|
|
@@ -1229,14 +1264,20 @@ export async function createOidc_nonMemoized<
|
|
|
1229
1264
|
transformUrlBeforeRedirect,
|
|
1230
1265
|
getExtraQueryParams,
|
|
1231
1266
|
getExtraTokenParams: () => extraTokenParams,
|
|
1232
|
-
autoLogin
|
|
1267
|
+
autoLogin,
|
|
1268
|
+
log
|
|
1233
1269
|
});
|
|
1234
1270
|
|
|
1235
1271
|
if (result_loginSilent.outcome === "failure") {
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1272
|
+
log?.(
|
|
1273
|
+
[
|
|
1274
|
+
`Silent refresh of the token failed with ${result_loginSilent.cause}.`,
|
|
1275
|
+
`This isn't recoverable, reloading the page.`
|
|
1276
|
+
].join(" ")
|
|
1277
|
+
);
|
|
1278
|
+
window.location.reload();
|
|
1279
|
+
await new Promise<never>(() => {});
|
|
1280
|
+
assert(false);
|
|
1240
1281
|
}
|
|
1241
1282
|
|
|
1242
1283
|
let oidcClientTsUser: OidcClientTsUser;
|
|
@@ -1420,7 +1461,11 @@ export async function createOidc_nonMemoized<
|
|
|
1420
1461
|
action: "go to auth server",
|
|
1421
1462
|
redirectUrl: redirectUrl ?? window.location.href,
|
|
1422
1463
|
extraQueryParams_local: extraQueryParams,
|
|
1423
|
-
transformUrlBeforeRedirect_local: transformUrlBeforeRedirect
|
|
1464
|
+
transformUrlBeforeRedirect_local: transformUrlBeforeRedirect,
|
|
1465
|
+
onCantFetchWellKnownEndpointError: () => {
|
|
1466
|
+
log?.("goToAuthServer called but the auth server seems to be down..");
|
|
1467
|
+
alert("Authentication unavailable please try again later.");
|
|
1468
|
+
}
|
|
1424
1469
|
}),
|
|
1425
1470
|
backFromAuthServer: resultOfLoginProcess.backFromAuthServer,
|
|
1426
1471
|
isNewBrowserSession: (() => {
|
|
@@ -1493,12 +1538,12 @@ export async function createOidc_nonMemoized<
|
|
|
1493
1538
|
});
|
|
1494
1539
|
})();
|
|
1495
1540
|
|
|
1496
|
-
(function
|
|
1541
|
+
(function scheduleTokenRefreshToKeepSessionAlive() {
|
|
1497
1542
|
if (!currentTokens.hasRefreshToken && !canUseIframe) {
|
|
1498
1543
|
log?.(
|
|
1499
1544
|
[
|
|
1500
|
-
"
|
|
1501
|
-
"
|
|
1545
|
+
"Session keep-alive disabled: no refresh token and no iframe support. ",
|
|
1546
|
+
"Result: once tokens expire, continuing requires full reload."
|
|
1502
1547
|
].join(" ")
|
|
1503
1548
|
);
|
|
1504
1549
|
return;
|
|
@@ -1508,7 +1553,34 @@ export async function createOidc_nonMemoized<
|
|
|
1508
1553
|
currentTokens.refreshTokenExpirationTime !== undefined &&
|
|
1509
1554
|
currentTokens.refreshTokenExpirationTime >= INFINITY_TIME
|
|
1510
1555
|
) {
|
|
1511
|
-
|
|
1556
|
+
const warningLines: string[] = [];
|
|
1557
|
+
|
|
1558
|
+
if (scopes.includes("offline_access")) {
|
|
1559
|
+
warningLines.push("offline_access scope was explicitly requested.");
|
|
1560
|
+
} else if (isKeycloak({ issuerUri })) {
|
|
1561
|
+
warningLines.push("Keycloak likely enabled offline_access by default.");
|
|
1562
|
+
}
|
|
1563
|
+
|
|
1564
|
+
if (warningLines.length > 0) {
|
|
1565
|
+
warningLines.push(
|
|
1566
|
+
...[
|
|
1567
|
+
"Misconfiguration: offline_access is for native apps, not SPAs. ",
|
|
1568
|
+
"You lose SSO and users must log in after every reload."
|
|
1569
|
+
]
|
|
1570
|
+
);
|
|
1571
|
+
}
|
|
1572
|
+
|
|
1573
|
+
const logMessage = [
|
|
1574
|
+
"Refresh token never expires → no need to ping server.",
|
|
1575
|
+
"The backend session will not expire.",
|
|
1576
|
+
...warningLines
|
|
1577
|
+
].join(" ");
|
|
1578
|
+
|
|
1579
|
+
if (warningLines.length > 0) {
|
|
1580
|
+
console.warn(`oidc-spa: ${logMessage}`);
|
|
1581
|
+
} else {
|
|
1582
|
+
log?.(logMessage);
|
|
1583
|
+
}
|
|
1512
1584
|
return;
|
|
1513
1585
|
}
|
|
1514
1586
|
|
|
@@ -1524,7 +1596,7 @@ export async function createOidc_nonMemoized<
|
|
|
1524
1596
|
if (msBeforeExpiration <= RENEW_MS_BEFORE_EXPIRES) {
|
|
1525
1597
|
log?.(
|
|
1526
1598
|
[
|
|
1527
|
-
"
|
|
1599
|
+
"Session keep-alive disabled. We just got fresh tokens",
|
|
1528
1600
|
(() => {
|
|
1529
1601
|
switch (typeOfTheTokenWeGotTheTtlFrom) {
|
|
1530
1602
|
case "refresh":
|
|
@@ -1608,7 +1680,7 @@ export async function createOidc_nonMemoized<
|
|
|
1608
1680
|
const { unsubscribe: tokenChangeUnsubscribe } = oidc_loggedIn.subscribeToTokensChange(() => {
|
|
1609
1681
|
clearTimeout(timer);
|
|
1610
1682
|
tokenChangeUnsubscribe();
|
|
1611
|
-
|
|
1683
|
+
scheduleTokenRefreshToKeepSessionAlive();
|
|
1612
1684
|
});
|
|
1613
1685
|
})();
|
|
1614
1686
|
|
package/src/core/diagnostic.ts
CHANGED
|
@@ -2,13 +2,13 @@ import { OidcInitializationError } from "./OidcInitializationError";
|
|
|
2
2
|
import { isKeycloak, createKeycloakUtils } from "../keycloak";
|
|
3
3
|
import { getIsValidRemoteJson } from "../tools/getIsValidRemoteJson";
|
|
4
4
|
|
|
5
|
+
export const WELL_KNOWN_PATH = "/.well-known/openid-configuration";
|
|
6
|
+
|
|
5
7
|
export async function createWellKnownOidcConfigurationEndpointUnreachableInitializationError(params: {
|
|
6
8
|
issuerUri: string;
|
|
7
9
|
}): Promise<OidcInitializationError> {
|
|
8
10
|
const { issuerUri } = params;
|
|
9
11
|
|
|
10
|
-
const WELL_KNOWN_PATH = "/.well-known/openid-configuration";
|
|
11
|
-
|
|
12
12
|
const commonFallbackMessagePart = [
|
|
13
13
|
`The OIDC server is either down or the issuerUri you provided is incorrect.`,
|
|
14
14
|
`You provided the issuerUri: ${issuerUri}`,
|
|
@@ -2,14 +2,14 @@ import type { NonPostableEvt } from "../tools/Evt";
|
|
|
2
2
|
|
|
3
3
|
export function createGetIsNewBrowserSession(params: {
|
|
4
4
|
configId: string;
|
|
5
|
-
|
|
5
|
+
evtInitializationOutcomeUserNotLoggedIn: NonPostableEvt<void>;
|
|
6
6
|
}) {
|
|
7
|
-
const { configId,
|
|
7
|
+
const { configId, evtInitializationOutcomeUserNotLoggedIn } = params;
|
|
8
8
|
|
|
9
9
|
const SESSION_STORAGE_KEY = `oidc-spa.subject-id:${configId}`;
|
|
10
10
|
|
|
11
11
|
{
|
|
12
|
-
const { unsubscribe } =
|
|
12
|
+
const { unsubscribe } = evtInitializationOutcomeUserNotLoggedIn.subscribe(() => {
|
|
13
13
|
unsubscribe();
|
|
14
14
|
sessionStorage.removeItem(SESSION_STORAGE_KEY);
|
|
15
15
|
});
|
|
@@ -7,6 +7,7 @@ import type { NonPostableEvt } from "../tools/Evt";
|
|
|
7
7
|
import { createStatefulEvt } from "../tools/StatefulEvt";
|
|
8
8
|
import { Deferred } from "../tools/Deferred";
|
|
9
9
|
import { addOrUpdateSearchParam, getAllSearchParams } from "../tools/urlSearchParams";
|
|
10
|
+
import { getIsOnline } from "../tools/getIsOnline";
|
|
10
11
|
|
|
11
12
|
const globalContext = {
|
|
12
13
|
evtHasLoginBeenCalled: createStatefulEvt(() => false)
|
|
@@ -19,6 +20,7 @@ namespace Params {
|
|
|
19
20
|
redirectUrl: string;
|
|
20
21
|
extraQueryParams_local: Record<string, string | undefined> | undefined;
|
|
21
22
|
transformUrlBeforeRedirect_local: ((url: string) => string) | undefined;
|
|
23
|
+
onCantFetchWellKnownEndpointError: () => void;
|
|
22
24
|
};
|
|
23
25
|
|
|
24
26
|
export type Login = Common & {
|
|
@@ -36,7 +38,7 @@ namespace Params {
|
|
|
36
38
|
};
|
|
37
39
|
}
|
|
38
40
|
|
|
39
|
-
export function
|
|
41
|
+
export function getPrSafelyRestoredFromBfCacheAfterLoginBackNavigationOrInitializationError() {
|
|
40
42
|
const dOut = new Deferred<void>();
|
|
41
43
|
|
|
42
44
|
const { unsubscribe } = globalContext.evtHasLoginBeenCalled.subscribe(hasLoginBeenCalled => {
|
|
@@ -63,7 +65,7 @@ export function createLoginOrGoToAuthServer(params: {
|
|
|
63
65
|
getExtraTokenParams: (() => Record<string, string | undefined>) | undefined;
|
|
64
66
|
|
|
65
67
|
homeUrl: string;
|
|
66
|
-
|
|
68
|
+
evtInitializationOutcomeUserNotLoggedIn: NonPostableEvt<void>;
|
|
67
69
|
log: typeof console.log | undefined;
|
|
68
70
|
}) {
|
|
69
71
|
const {
|
|
@@ -76,12 +78,11 @@ export function createLoginOrGoToAuthServer(params: {
|
|
|
76
78
|
getExtraTokenParams,
|
|
77
79
|
|
|
78
80
|
homeUrl,
|
|
79
|
-
|
|
81
|
+
evtInitializationOutcomeUserNotLoggedIn,
|
|
82
|
+
|
|
80
83
|
log
|
|
81
84
|
} = params;
|
|
82
85
|
|
|
83
|
-
const LOCAL_STORAGE_KEY_TO_CLEAR_WHEN_USER_LOGGED_IN = `oidc-spa.login-redirect-initiated:${configId}`;
|
|
84
|
-
|
|
85
86
|
let lastPublicUrl: string | undefined = undefined;
|
|
86
87
|
|
|
87
88
|
async function loginOrGoToAuthServer(params: Params): Promise<never> {
|
|
@@ -89,11 +90,24 @@ export function createLoginOrGoToAuthServer(params: {
|
|
|
89
90
|
redirectUrl: redirectUrl_params,
|
|
90
91
|
extraQueryParams_local,
|
|
91
92
|
transformUrlBeforeRedirect_local,
|
|
93
|
+
onCantFetchWellKnownEndpointError: onCantFetchWellKnownEndpointError_params,
|
|
92
94
|
...rest
|
|
93
95
|
} = params;
|
|
96
|
+
let onCantFetchWellKnownEndpointError = onCantFetchWellKnownEndpointError_params;
|
|
94
97
|
|
|
95
98
|
log?.(`Calling loginOrGoToAuthServer ${JSON.stringify(params, null, 2)}`);
|
|
96
99
|
|
|
100
|
+
delay_until_online: {
|
|
101
|
+
const { isOnline, prOnline } = getIsOnline();
|
|
102
|
+
if (isOnline) {
|
|
103
|
+
break delay_until_online;
|
|
104
|
+
}
|
|
105
|
+
log?.(
|
|
106
|
+
"The browser seem offline, waiting to get back a connection before proceeding to login"
|
|
107
|
+
);
|
|
108
|
+
await prOnline;
|
|
109
|
+
}
|
|
110
|
+
|
|
97
111
|
login_specific_handling: {
|
|
98
112
|
if (rest.action !== "login") {
|
|
99
113
|
break login_specific_handling;
|
|
@@ -125,17 +139,23 @@ export function createLoginOrGoToAuthServer(params: {
|
|
|
125
139
|
|
|
126
140
|
bf_cache_handling: {
|
|
127
141
|
if (rest.doForceReloadOnBfCache) {
|
|
128
|
-
|
|
142
|
+
const callback = (event: { persisted: boolean }) => {
|
|
129
143
|
if (!event.persisted) {
|
|
130
144
|
return;
|
|
131
145
|
}
|
|
132
146
|
location.reload();
|
|
133
|
-
}
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
window.addEventListener("pageshow", callback);
|
|
150
|
+
|
|
151
|
+
onCantFetchWellKnownEndpointError = () => {
|
|
152
|
+
window.removeEventListener("pageshow", callback);
|
|
153
|
+
onCantFetchWellKnownEndpointError_params();
|
|
154
|
+
};
|
|
155
|
+
|
|
134
156
|
break bf_cache_handling;
|
|
135
157
|
}
|
|
136
158
|
|
|
137
|
-
localStorage.setItem(LOCAL_STORAGE_KEY_TO_CLEAR_WHEN_USER_LOGGED_IN, "true");
|
|
138
|
-
|
|
139
159
|
const callback = (event: { persisted: boolean }) => {
|
|
140
160
|
if (!event.persisted) {
|
|
141
161
|
return;
|
|
@@ -156,21 +176,19 @@ export function createLoginOrGoToAuthServer(params: {
|
|
|
156
176
|
window.history.back();
|
|
157
177
|
}
|
|
158
178
|
} else {
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
localStorage.getItem(LOCAL_STORAGE_KEY_TO_CLEAR_WHEN_USER_LOGGED_IN) === null
|
|
163
|
-
) {
|
|
164
|
-
log?.("but the user is now authenticated, reloading the page");
|
|
165
|
-
location.reload();
|
|
166
|
-
} else {
|
|
167
|
-
log?.("and the user doesn't seem to be authenticated, avoiding a reload");
|
|
168
|
-
globalContext.evtHasLoginBeenCalled.current = false;
|
|
169
|
-
}
|
|
179
|
+
// NOTE: We know the user is not logged in because login can only be called when not logged in.
|
|
180
|
+
log?.("The current page doesn't require auth, avoiding reloading the page");
|
|
181
|
+
globalContext.evtHasLoginBeenCalled.current = false;
|
|
170
182
|
}
|
|
171
183
|
};
|
|
172
184
|
|
|
173
185
|
window.addEventListener("pageshow", callback);
|
|
186
|
+
|
|
187
|
+
onCantFetchWellKnownEndpointError = () => {
|
|
188
|
+
window.removeEventListener("pageshow", callback);
|
|
189
|
+
globalContext.evtHasLoginBeenCalled.current = false;
|
|
190
|
+
onCantFetchWellKnownEndpointError_params();
|
|
191
|
+
};
|
|
174
192
|
}
|
|
175
193
|
}
|
|
176
194
|
|
|
@@ -327,21 +345,31 @@ export function createLoginOrGoToAuthServer(params: {
|
|
|
327
345
|
extraTokenParams:
|
|
328
346
|
getExtraTokenParams === undefined ? undefined : noUndefined(getExtraTokenParams())
|
|
329
347
|
})
|
|
330
|
-
.then(
|
|
348
|
+
.then(
|
|
349
|
+
() => new Promise<never>(() => {}),
|
|
350
|
+
(error: Error) => {
|
|
351
|
+
if (error.message === "Failed to fetch") {
|
|
352
|
+
// NOTE: See ./loginSilent for explanation.
|
|
353
|
+
onCantFetchWellKnownEndpointError();
|
|
354
|
+
|
|
355
|
+
return new Promise<never>(() => {});
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
// NOTE: Here, except error on our understanding there can't be any other
|
|
359
|
+
// error.
|
|
360
|
+
assert(false, "30442320");
|
|
361
|
+
}
|
|
362
|
+
);
|
|
331
363
|
}
|
|
332
364
|
|
|
333
|
-
const { unsubscribe } =
|
|
365
|
+
const { unsubscribe } = evtInitializationOutcomeUserNotLoggedIn.subscribe(() => {
|
|
334
366
|
unsubscribe();
|
|
335
367
|
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
lastPublicUrl = window.location.href;
|
|
342
|
-
return realPushState(...args);
|
|
343
|
-
};
|
|
344
|
-
}
|
|
368
|
+
const realPushState = history.pushState.bind(history);
|
|
369
|
+
history.pushState = function pushState(...args) {
|
|
370
|
+
lastPublicUrl = window.location.href;
|
|
371
|
+
return realPushState(...args);
|
|
372
|
+
};
|
|
345
373
|
});
|
|
346
374
|
|
|
347
375
|
return {
|
package/src/core/loginSilent.ts
CHANGED
|
@@ -12,6 +12,7 @@ import { getIsDev } from "../tools/isDev";
|
|
|
12
12
|
import { type AuthResponse } from "./AuthResponse";
|
|
13
13
|
import { addOrUpdateSearchParam } from "../tools/urlSearchParams";
|
|
14
14
|
import { initIframeMessageProtection } from "./iframeMessageProtection";
|
|
15
|
+
import { getIsOnline } from "../tools/getIsOnline";
|
|
15
16
|
|
|
16
17
|
type ResultOfLoginSilent =
|
|
17
18
|
| {
|
|
@@ -42,6 +43,7 @@ export async function loginSilent(params: {
|
|
|
42
43
|
|
|
43
44
|
getExtraTokenParams: (() => Record<string, string | undefined>) | undefined;
|
|
44
45
|
autoLogin: boolean;
|
|
46
|
+
log: typeof console.log | undefined;
|
|
45
47
|
}): Promise<ResultOfLoginSilent> {
|
|
46
48
|
const {
|
|
47
49
|
oidcClientTsUserManager,
|
|
@@ -50,9 +52,19 @@ export async function loginSilent(params: {
|
|
|
50
52
|
transformUrlBeforeRedirect,
|
|
51
53
|
getExtraQueryParams,
|
|
52
54
|
getExtraTokenParams,
|
|
53
|
-
autoLogin
|
|
55
|
+
autoLogin,
|
|
56
|
+
log
|
|
54
57
|
} = params;
|
|
55
58
|
|
|
59
|
+
delay_until_online: {
|
|
60
|
+
const { isOnline, prOnline } = getIsOnline();
|
|
61
|
+
if (isOnline) {
|
|
62
|
+
break delay_until_online;
|
|
63
|
+
}
|
|
64
|
+
log?.("The browser seems offline, waiting to get back a connection before proceeding to login");
|
|
65
|
+
await prOnline;
|
|
66
|
+
}
|
|
67
|
+
|
|
56
68
|
const dResult = new Deferred<ResultOfLoginSilent>();
|
|
57
69
|
|
|
58
70
|
const timeoutDelayMs: number = (() => {
|
|
@@ -32,6 +32,14 @@ export async function startLoginOrRefreshProcess(): Promise<{
|
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
export async function waitForAllOtherOngoingLoginOrRefreshProcessesToComplete(params: {
|
|
35
|
+
// NOTE: when providing
|
|
36
|
+
// - prUnlock: new Promise<never>(()=>{}); All the subsequent startLoginOrRefreshProcess()
|
|
37
|
+
// will never resolve: No lock can be acquired anymore in this app instance.
|
|
38
|
+
// - prUnlock: Promise.resolve(); The subsequent startLoginOrRefreshProcess() will resolve
|
|
39
|
+
// normally: The lock can be acquired again
|
|
40
|
+
// - prUnlock: prMightOrMightNotResolve. The lock will be acquirable again assuming the pr ever resolves.
|
|
41
|
+
//
|
|
42
|
+
// In any case it does not affect the call that are already running.
|
|
35
43
|
prUnlock: Promise<void>;
|
|
36
44
|
}): Promise<void> {
|
|
37
45
|
const { prUnlock } = params;
|
package/vendor/backend/tsafe.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
(()=>{"use strict";var e={720:function(e,r){var t,n=this&&this.__extends||(t=function(e,r){return t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,r){e.__proto__=r}||function(e,r){for(var t in r)Object.prototype.hasOwnProperty.call(r,t)&&(e[t]=r[t])},t(e,r)},function(e,r){if("function"!=typeof r&&null!==r)throw new TypeError("Class extends value "+String(r)+" is not a constructor or null");function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)});Object.defineProperty(r,"__esModule",{value:!0}),r.AssertionError=void 0,r.assert=function e(r,t){if(0===arguments.length&&(r=!0),void 0===i){if(!r){var n=new o("function"==typeof t?t():t);throw Error.captureStackTrace&&Error.captureStackTrace(n,e),n}}else i=void 0},r.is=function(e){var r={};if(void 0!==i)throw i=void 0,new Error(u);return i=r,Promise.resolve().then((function(){if(i===r)throw new Error(u)})),null};var o=function(e){function r(r){var t=this.constructor,n=e.call(this,"Wrong assertion encountered"+(r?': "'.concat(r,'"'):""))||this;return n.originalMessage=r,Object.setPrototypeOf(n,t.prototype),n
|
|
1
|
+
(()=>{"use strict";var e={720:function(e,r){var t,n=this&&this.__extends||(t=function(e,r){return t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,r){e.__proto__=r}||function(e,r){for(var t in r)Object.prototype.hasOwnProperty.call(r,t)&&(e[t]=r[t])},t(e,r)},function(e,r){if("function"!=typeof r&&null!==r)throw new TypeError("Class extends value "+String(r)+" is not a constructor or null");function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)});Object.defineProperty(r,"__esModule",{value:!0}),r.AssertionError=void 0,r.assert=function e(r,t){if(0===arguments.length&&(r=!0),void 0===i){if(!r){var n=new o("function"==typeof t?t():t);throw Error.captureStackTrace&&Error.captureStackTrace(n,e),n}}else i=void 0},r.is=function(e){var r={};if(void 0!==i)throw i=void 0,new Error(u);return i=r,Promise.resolve().then((function(){if(i===r)throw new Error(u)})),null};var o=function(e){function r(r){var t=this.constructor,n=e.call(this,"Wrong assertion encountered"+(r?': "'.concat(r,'"'):""))||this;return n.originalMessage=r,Object.setPrototypeOf(n,t.prototype),n}return n(r,e),r}(Error);r.AssertionError=o;var i=void 0,u="Wrong usage of the `is` function refer to https://docs.tsafe.dev/is"},202:(e,r)=>{Object.defineProperty(r,"__esModule",{value:!0}),r.exclude=function(e){var r=e instanceof Object?function(r){return e.indexOf(r)<0}:function(r){return r!==e};return function(e){return r(e)}}},135:(e,r)=>{Object.defineProperty(r,"__esModule",{value:!0}),r.id=void 0,r.id=function(e){return e}},952:function(e,r){var t=this&&this.__values||function(e){var r="function"==typeof Symbol&&Symbol.iterator,t=r&&e[r],n=0;if(t)return t.call(e);if(e&&"number"==typeof e.length)return{next:function(){return e&&n>=e.length&&(e=void 0),{value:e&&e[n++],done:!e}}};throw new TypeError(r?"Object is not iterable.":"Symbol.iterator is not defined.")};Object.defineProperty(r,"__esModule",{value:!0}),r.isAmong=function(e,r){var n,o;try{for(var i=t(e),u=i.next();!u.done;u=i.next())if(u.value===r)return!0}catch(e){n={error:e}}finally{try{u&&!u.done&&(o=i.return)&&o.call(i)}finally{if(n)throw n.error}}return!1}}},r={};function t(n){var o=r[n];if(void 0!==o)return o.exports;var i=r[n]={exports:{}};return e[n].call(i.exports,i,i.exports,t),i.exports}var n={};(()=>{var e=n;Object.defineProperty(e,"__esModule",{value:!0}),e.exclude=e.isAmong=e.id=e.is=e.assert=void 0;var r=t(720);Object.defineProperty(e,"assert",{enumerable:!0,get:function(){return r.assert}}),Object.defineProperty(e,"is",{enumerable:!0,get:function(){return r.is}});var o=t(135);Object.defineProperty(e,"id",{enumerable:!0,get:function(){return o.id}});var i=t(952);Object.defineProperty(e,"isAmong",{enumerable:!0,get:function(){return i.isAmong}});var u=t(202);Object.defineProperty(e,"exclude",{enumerable:!0,get:function(){return u.exclude}})})(),module.exports=n})();
|
|
2
2
|
exports.__oidcSpaBundle = true;
|