oidc-spa 8.2.1 → 8.2.2
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/AuthResponse.d.ts +0 -5
- package/core/AuthResponse.js +0 -25
- package/core/AuthResponse.js.map +1 -1
- package/core/createOidc.d.ts +3 -2
- package/core/createOidc.js +81 -117
- package/core/createOidc.js.map +1 -1
- package/core/instancesThatCantUseIframes.d.ts +2 -0
- package/core/instancesThatCantUseIframes.js +20 -0
- package/core/instancesThatCantUseIframes.js.map +1 -0
- package/core/loginOrGoToAuthServer.d.ts +1 -0
- package/core/loginOrGoToAuthServer.js +3 -0
- package/core/loginOrGoToAuthServer.js.map +1 -1
- package/core/persistedAuthState.d.ts +1 -0
- package/core/persistedAuthState.js +14 -4
- package/core/persistedAuthState.js.map +1 -1
- package/esm/core/AuthResponse.d.ts +0 -5
- package/esm/core/AuthResponse.js +0 -23
- package/esm/core/AuthResponse.js.map +1 -1
- package/esm/core/createOidc.d.ts +3 -2
- package/esm/core/createOidc.js +82 -118
- package/esm/core/createOidc.js.map +1 -1
- package/esm/core/instancesThatCantUseIframes.d.ts +2 -0
- package/esm/core/instancesThatCantUseIframes.js +16 -0
- package/esm/core/instancesThatCantUseIframes.js.map +1 -0
- package/esm/core/loginOrGoToAuthServer.d.ts +1 -0
- package/esm/core/loginOrGoToAuthServer.js +3 -0
- package/esm/core/loginOrGoToAuthServer.js.map +1 -1
- package/esm/core/persistedAuthState.d.ts +1 -0
- package/esm/core/persistedAuthState.js +14 -4
- package/esm/core/persistedAuthState.js.map +1 -1
- package/esm/tools/{EphemeralSessionStorage.d.ts → lazySessionStorage.d.ts} +2 -4
- package/esm/tools/lazySessionStorage.js +81 -0
- package/esm/tools/lazySessionStorage.js.map +1 -0
- package/package.json +1 -1
- package/src/core/AuthResponse.ts +0 -36
- package/src/core/createOidc.ts +95 -154
- package/src/core/instancesThatCantUseIframes.ts +24 -0
- package/src/core/loginOrGoToAuthServer.ts +5 -0
- package/src/core/persistedAuthState.ts +27 -5
- package/src/tools/lazySessionStorage.ts +119 -0
- package/src/vite-plugin/manageOptimizedDeps.ts +2 -0
- package/tools/{EphemeralSessionStorage.d.ts → lazySessionStorage.d.ts} +2 -4
- package/tools/lazySessionStorage.js +84 -0
- package/tools/lazySessionStorage.js.map +1 -0
- package/vite-plugin/manageOptimizedDeps.js +1 -0
- package/vite-plugin/manageOptimizedDeps.js.map +1 -1
- package/esm/tools/EphemeralSessionStorage.js +0 -143
- package/esm/tools/EphemeralSessionStorage.js.map +0 -1
- package/src/tools/EphemeralSessionStorage.ts +0 -225
- package/tools/EphemeralSessionStorage.js +0 -146
- package/tools/EphemeralSessionStorage.js.map +0 -1
package/src/core/createOidc.ts
CHANGED
|
@@ -25,12 +25,7 @@ import { notifyOtherTabsOfLogin, getPrOtherTabLogin } from "./loginPropagationTo
|
|
|
25
25
|
import { getConfigId } from "./configId";
|
|
26
26
|
import { oidcClientTsUserToTokens } from "./oidcClientTsUserToTokens";
|
|
27
27
|
import { loginSilent } from "./loginSilent";
|
|
28
|
-
import {
|
|
29
|
-
authResponseToUrl,
|
|
30
|
-
getPersistedRedirectAuthResponses,
|
|
31
|
-
setPersistedRedirectAuthResponses,
|
|
32
|
-
type AuthResponse
|
|
33
|
-
} from "./AuthResponse";
|
|
28
|
+
import { authResponseToUrl, type AuthResponse } from "./AuthResponse";
|
|
34
29
|
import { getRootRelativeOriginalLocationHref, getRedirectAuthResponse } from "./earlyInit";
|
|
35
30
|
import { getPersistedAuthState, persistAuthState } from "./persistedAuthState";
|
|
36
31
|
import type { Oidc } from "./Oidc";
|
|
@@ -40,7 +35,7 @@ import {
|
|
|
40
35
|
createLoginOrGoToAuthServer,
|
|
41
36
|
getPrSafelyRestoredFromBfCacheAfterLoginBackNavigationOrInitializationError
|
|
42
37
|
} from "./loginOrGoToAuthServer";
|
|
43
|
-
import {
|
|
38
|
+
import { createLazySessionStorage } from "../tools/lazySessionStorage";
|
|
44
39
|
import {
|
|
45
40
|
startLoginOrRefreshProcess,
|
|
46
41
|
waitForAllOtherOngoingLoginOrRefreshProcessesToComplete
|
|
@@ -53,6 +48,10 @@ import { prShouldLoadApp } from "./prShouldLoadApp";
|
|
|
53
48
|
import { getBASE_URL } from "./BASE_URL";
|
|
54
49
|
import { getIsLikelyDevServer } from "../tools/isLikelyDevServer";
|
|
55
50
|
import { createObjectThatThrowsIfAccessed } from "../tools/createObjectThatThrowsIfAccessed";
|
|
51
|
+
import {
|
|
52
|
+
evtIsThereMoreThanOneInstanceThatCantUserIframes,
|
|
53
|
+
notifyNewInstanceThatCantUseIframes
|
|
54
|
+
} from "./instancesThatCantUseIframes";
|
|
56
55
|
|
|
57
56
|
// NOTE: Replaced at build time
|
|
58
57
|
const VERSION = "{{OIDC_SPA_VERSION}}";
|
|
@@ -108,6 +107,8 @@ export type ParamsOfCreateOidc<
|
|
|
108
107
|
*/
|
|
109
108
|
extraTokenParams?: Record<string, string | undefined> | (() => Record<string, string | undefined>);
|
|
110
109
|
/**
|
|
110
|
+
* @deprecated: Use login({ redirectUrl: "..." }) instead.
|
|
111
|
+
*
|
|
111
112
|
* Usage discouraged, it's here because we don't want to assume too much on your
|
|
112
113
|
* usecase but I can't think of a scenario where you would want anything
|
|
113
114
|
* other than the current page.
|
|
@@ -208,24 +209,9 @@ export type ParamsOfCreateOidc<
|
|
|
208
209
|
|
|
209
210
|
const globalContext = {
|
|
210
211
|
prOidcByConfigId: new Map<string, Promise<Oidc<any>>>(),
|
|
211
|
-
hasLogoutBeenCalled: id<boolean>(false)
|
|
212
|
-
evtRequestToPersistTokens: createEvt<{ configIdOfInstancePostingTheRequest: string }>()
|
|
212
|
+
hasLogoutBeenCalled: id<boolean>(false)
|
|
213
213
|
};
|
|
214
214
|
|
|
215
|
-
globalContext.evtRequestToPersistTokens.subscribe(() => {
|
|
216
|
-
const { authResponse } = getRedirectAuthResponse();
|
|
217
|
-
|
|
218
|
-
if (authResponse === undefined) {
|
|
219
|
-
return;
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
const { authResponses } = getPersistedRedirectAuthResponses();
|
|
223
|
-
|
|
224
|
-
setPersistedRedirectAuthResponses({
|
|
225
|
-
authResponses: [...authResponses, authResponse]
|
|
226
|
-
});
|
|
227
|
-
});
|
|
228
|
-
|
|
229
215
|
/** @see: https://docs.oidc-spa.dev/v/v8/usage */
|
|
230
216
|
export async function createOidc<
|
|
231
217
|
DecodedIdToken extends Record<string, unknown> = Oidc.Tokens.DecodedIdToken_OidcCoreSpec,
|
|
@@ -242,7 +228,7 @@ export async function createOidc<
|
|
|
242
228
|
}
|
|
243
229
|
}
|
|
244
230
|
|
|
245
|
-
const { issuerUri: issuerUri_params, clientId,
|
|
231
|
+
const { issuerUri: issuerUri_params, clientId, debugLogs, ...rest } = params;
|
|
246
232
|
|
|
247
233
|
const issuerUri = toFullyQualifiedUrl({
|
|
248
234
|
urlish: issuerUri_params,
|
|
@@ -298,7 +284,6 @@ export async function createOidc<
|
|
|
298
284
|
const oidc = await createOidc_nonMemoized(rest, {
|
|
299
285
|
issuerUri,
|
|
300
286
|
clientId,
|
|
301
|
-
scopes,
|
|
302
287
|
configId,
|
|
303
288
|
log
|
|
304
289
|
});
|
|
@@ -312,14 +297,10 @@ export async function createOidc_nonMemoized<
|
|
|
312
297
|
DecodedIdToken extends Record<string, unknown>,
|
|
313
298
|
AutoLogin extends boolean
|
|
314
299
|
>(
|
|
315
|
-
params: Omit<
|
|
316
|
-
ParamsOfCreateOidc<DecodedIdToken, AutoLogin>,
|
|
317
|
-
"issuerUri" | "clientId" | "scopes" | "debugLogs"
|
|
318
|
-
>,
|
|
300
|
+
params: Omit<ParamsOfCreateOidc<DecodedIdToken, AutoLogin>, "issuerUri" | "clientId" | "debugLogs">,
|
|
319
301
|
preProcessedParams: {
|
|
320
302
|
issuerUri: string;
|
|
321
303
|
clientId: string;
|
|
322
|
-
scopes: string[];
|
|
323
304
|
configId: string;
|
|
324
305
|
log: typeof console.log | undefined;
|
|
325
306
|
}
|
|
@@ -357,12 +338,13 @@ export async function createOidc_nonMemoized<
|
|
|
357
338
|
__unsafe_clientSecret,
|
|
358
339
|
__unsafe_useIdTokenAsAccessToken = false,
|
|
359
340
|
__metadata,
|
|
360
|
-
noIframe = false
|
|
341
|
+
noIframe = false,
|
|
342
|
+
scopes = ["openid", "profile"]
|
|
361
343
|
} = params;
|
|
362
344
|
|
|
363
345
|
const BASE_URL_params = params.BASE_URL ?? params.homeUrl;
|
|
364
346
|
|
|
365
|
-
const { issuerUri, clientId,
|
|
347
|
+
const { issuerUri, clientId, configId, log } = preProcessedParams;
|
|
366
348
|
|
|
367
349
|
const getExtraQueryParams = (() => {
|
|
368
350
|
if (extraQueryParamsOrGetter === undefined) {
|
|
@@ -422,8 +404,7 @@ export async function createOidc_nonMemoized<
|
|
|
422
404
|
issuerUri,
|
|
423
405
|
clientId,
|
|
424
406
|
scopes,
|
|
425
|
-
|
|
426
|
-
homeUrlAndRedirectUri
|
|
407
|
+
oidcRedirectUri: homeUrlAndRedirectUri
|
|
427
408
|
},
|
|
428
409
|
null,
|
|
429
410
|
2
|
|
@@ -515,7 +496,7 @@ export async function createOidc_nonMemoized<
|
|
|
515
496
|
log?.(
|
|
516
497
|
[
|
|
517
498
|
"Detected localhost environment.",
|
|
518
|
-
"\nWhen reloading while logged in, you
|
|
499
|
+
"\nWhen reloading while logged in, you will briefly see",
|
|
519
500
|
"some URL params appear in the address bar.",
|
|
520
501
|
"\nThis happens because session restore via iframe is disabled,",
|
|
521
502
|
"the browser treats your auth server as a third party.",
|
|
@@ -585,7 +566,16 @@ export async function createOidc_nonMemoized<
|
|
|
585
566
|
return true;
|
|
586
567
|
})();
|
|
587
568
|
|
|
588
|
-
|
|
569
|
+
notifyNewInstanceThatCantUseIframes();
|
|
570
|
+
|
|
571
|
+
if (evtIsThereMoreThanOneInstanceThatCantUserIframes.current) {
|
|
572
|
+
log?.(
|
|
573
|
+
[
|
|
574
|
+
"More than one oidc instance can't use iframe",
|
|
575
|
+
"falling back to persisting tokens in session storage"
|
|
576
|
+
].join(" ")
|
|
577
|
+
);
|
|
578
|
+
}
|
|
589
579
|
|
|
590
580
|
const oidcClientTsUserManager =
|
|
591
581
|
oidcMetadata === undefined
|
|
@@ -606,27 +596,18 @@ export async function createOidc_nonMemoized<
|
|
|
606
596
|
userStore: new WebStorageStateStore({
|
|
607
597
|
store: (() => {
|
|
608
598
|
if (canUseIframe) {
|
|
609
|
-
isUserStoreInMemoryOnly = true;
|
|
610
599
|
return new InMemoryWebStorage();
|
|
611
600
|
}
|
|
612
601
|
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
const storage = createEphemeralSessionStorage({
|
|
616
|
-
sessionStorageTtlMs: 3 * 60_000
|
|
617
|
-
});
|
|
618
|
-
|
|
619
|
-
const { evtRequestToPersistTokens } = globalContext;
|
|
620
|
-
|
|
621
|
-
evtRequestToPersistTokens.subscribe(
|
|
622
|
-
({ configIdOfInstancePostingTheRequest }) => {
|
|
623
|
-
if (configIdOfInstancePostingTheRequest === configId) {
|
|
624
|
-
return;
|
|
625
|
-
}
|
|
602
|
+
const storage = createLazySessionStorage();
|
|
626
603
|
|
|
604
|
+
if (evtIsThereMoreThanOneInstanceThatCantUserIframes.current) {
|
|
605
|
+
storage.persistCurrentStateAndSubsequentChanges();
|
|
606
|
+
} else {
|
|
607
|
+
evtIsThereMoreThanOneInstanceThatCantUserIframes.subscribe(() => {
|
|
627
608
|
storage.persistCurrentStateAndSubsequentChanges();
|
|
628
|
-
}
|
|
629
|
-
|
|
609
|
+
});
|
|
610
|
+
}
|
|
630
611
|
|
|
631
612
|
return storage;
|
|
632
613
|
})()
|
|
@@ -675,75 +656,67 @@ export async function createOidc_nonMemoized<
|
|
|
675
656
|
});
|
|
676
657
|
}
|
|
677
658
|
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
659
|
+
restore_from_session_storage: {
|
|
660
|
+
if (canUseIframe) {
|
|
661
|
+
break restore_from_session_storage;
|
|
662
|
+
}
|
|
682
663
|
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
664
|
+
if (!evtIsThereMoreThanOneInstanceThatCantUserIframes.current) {
|
|
665
|
+
break restore_from_session_storage;
|
|
666
|
+
}
|
|
686
667
|
|
|
687
|
-
|
|
688
|
-
break from_memory;
|
|
689
|
-
}
|
|
668
|
+
let oidcClientTsUser: OidcClientTsUser | null;
|
|
690
669
|
|
|
691
|
-
|
|
670
|
+
try {
|
|
671
|
+
oidcClientTsUser = await oidcClientTsUserManager.getUser();
|
|
672
|
+
} catch {
|
|
673
|
+
// NOTE: Not sure if it can throw, but let's be safe.
|
|
674
|
+
oidcClientTsUser = null;
|
|
675
|
+
try {
|
|
676
|
+
await oidcClientTsUserManager.removeUser();
|
|
677
|
+
} catch {}
|
|
678
|
+
}
|
|
692
679
|
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
}
|
|
680
|
+
if (oidcClientTsUser === null) {
|
|
681
|
+
break restore_from_session_storage;
|
|
682
|
+
}
|
|
697
683
|
|
|
698
|
-
|
|
699
|
-
break from_memory;
|
|
700
|
-
}
|
|
684
|
+
log?.("Session was restored from session storage");
|
|
701
685
|
|
|
702
|
-
|
|
686
|
+
return {
|
|
687
|
+
oidcClientTsUser,
|
|
688
|
+
backFromAuthServer: undefined
|
|
689
|
+
};
|
|
690
|
+
}
|
|
703
691
|
|
|
704
|
-
|
|
692
|
+
handle_redirect_auth_response: {
|
|
693
|
+
let stateDataAndAuthResponse:
|
|
694
|
+
| { stateData: StateData.Redirect; authResponse: AuthResponse }
|
|
695
|
+
| undefined = undefined;
|
|
705
696
|
|
|
706
|
-
|
|
697
|
+
{
|
|
698
|
+
const { authResponse, clearAuthResponse } = getRedirectAuthResponse();
|
|
707
699
|
|
|
708
|
-
|
|
700
|
+
if (authResponse === undefined) {
|
|
701
|
+
break handle_redirect_auth_response;
|
|
709
702
|
}
|
|
710
703
|
|
|
711
|
-
|
|
712
|
-
// setup where one instance would need to redirect before
|
|
713
|
-
// the authResponse in memory had the chance to be processed.
|
|
714
|
-
// This can only happen if:
|
|
715
|
-
// 1) There are multiple oidc instances in the App.
|
|
716
|
-
// 2) They are instantiated in a non deterministic order.
|
|
717
|
-
// 3) We can't use iframe
|
|
718
|
-
// We practically never persist the auth response and do it only in session
|
|
719
|
-
// an ephemeral session storage, when we know it's gonna be required.
|
|
720
|
-
{
|
|
721
|
-
const { authResponses } = getPersistedRedirectAuthResponses();
|
|
722
|
-
|
|
723
|
-
for (const authResponse of authResponses) {
|
|
724
|
-
const stateData = getStateData({ stateUrlParamValue: authResponse.state });
|
|
725
|
-
|
|
726
|
-
if (stateData === undefined) {
|
|
727
|
-
continue;
|
|
728
|
-
}
|
|
704
|
+
const stateData = getStateData({ stateUrlParamValue: authResponse.state });
|
|
729
705
|
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
706
|
+
if (stateData === undefined) {
|
|
707
|
+
clearAuthResponse();
|
|
708
|
+
break handle_redirect_auth_response;
|
|
709
|
+
}
|
|
733
710
|
|
|
734
|
-
|
|
711
|
+
if (stateData.configId !== configId) {
|
|
712
|
+
break handle_redirect_auth_response;
|
|
713
|
+
}
|
|
735
714
|
|
|
736
|
-
|
|
737
|
-
authResponses: authResponses.filter(
|
|
738
|
-
authResponse_i => authResponse_i !== authResponse
|
|
739
|
-
)
|
|
740
|
-
});
|
|
715
|
+
assert(stateData.context === "redirect", "3229492");
|
|
741
716
|
|
|
742
|
-
|
|
717
|
+
clearAuthResponse();
|
|
743
718
|
|
|
744
|
-
|
|
745
|
-
}
|
|
746
|
-
}
|
|
719
|
+
stateDataAndAuthResponse = { stateData, authResponse };
|
|
747
720
|
}
|
|
748
721
|
|
|
749
722
|
if (stateDataAndAuthResponse === undefined) {
|
|
@@ -856,39 +829,6 @@ export async function createOidc_nonMemoized<
|
|
|
856
829
|
}
|
|
857
830
|
}
|
|
858
831
|
|
|
859
|
-
// NOTE: We almost never persist tokens, we have to only to support edge case
|
|
860
|
-
// of multiple oidc instance in a single App with no iframe support.
|
|
861
|
-
restore_from_session_storage: {
|
|
862
|
-
assert(isUserStoreInMemoryOnly !== undefined, "3392204");
|
|
863
|
-
|
|
864
|
-
if (isUserStoreInMemoryOnly) {
|
|
865
|
-
break restore_from_session_storage;
|
|
866
|
-
}
|
|
867
|
-
|
|
868
|
-
let oidcClientTsUser: OidcClientTsUser | null;
|
|
869
|
-
|
|
870
|
-
try {
|
|
871
|
-
oidcClientTsUser = await oidcClientTsUserManager.getUser();
|
|
872
|
-
} catch {
|
|
873
|
-
// NOTE: Not sure if it can throw, but let's be safe.
|
|
874
|
-
oidcClientTsUser = null;
|
|
875
|
-
try {
|
|
876
|
-
await oidcClientTsUserManager.removeUser();
|
|
877
|
-
} catch {}
|
|
878
|
-
}
|
|
879
|
-
|
|
880
|
-
if (oidcClientTsUser === null) {
|
|
881
|
-
break restore_from_session_storage;
|
|
882
|
-
}
|
|
883
|
-
|
|
884
|
-
log?.("Restored the auth from ephemeral session storage");
|
|
885
|
-
|
|
886
|
-
return {
|
|
887
|
-
oidcClientTsUser,
|
|
888
|
-
backFromAuthServer: undefined
|
|
889
|
-
};
|
|
890
|
-
}
|
|
891
|
-
|
|
892
832
|
silent_login_if_possible_and_auto_login: {
|
|
893
833
|
const persistedAuthState = getPersistedAuthState({ configId });
|
|
894
834
|
|
|
@@ -1002,8 +942,6 @@ export async function createOidc_nonMemoized<
|
|
|
1002
942
|
) {
|
|
1003
943
|
log?.("Performing auto login with redirect");
|
|
1004
944
|
|
|
1005
|
-
persistAuthState({ configId, state: undefined });
|
|
1006
|
-
|
|
1007
945
|
completeLoginOrRefreshProcess();
|
|
1008
946
|
|
|
1009
947
|
if (autoLogin && persistedAuthState !== "logged in") {
|
|
@@ -1015,16 +953,16 @@ export async function createOidc_nonMemoized<
|
|
|
1015
953
|
getPrSafelyRestoredFromBfCacheAfterLoginBackNavigationOrInitializationError()
|
|
1016
954
|
});
|
|
1017
955
|
|
|
1018
|
-
if (persistedAuthState === "logged in") {
|
|
1019
|
-
globalContext.evtRequestToPersistTokens.post({
|
|
1020
|
-
configIdOfInstancePostingTheRequest: configId
|
|
1021
|
-
});
|
|
1022
|
-
}
|
|
1023
|
-
|
|
1024
956
|
await loginOrGoToAuthServer({
|
|
1025
957
|
action: "login",
|
|
1026
958
|
doForceReloadOnBfCache: true,
|
|
1027
|
-
redirectUrl:
|
|
959
|
+
redirectUrl: (() => {
|
|
960
|
+
if (evtIsThereMoreThanOneInstanceThatCantUserIframes.current) {
|
|
961
|
+
return window.location.href;
|
|
962
|
+
}
|
|
963
|
+
|
|
964
|
+
return getRootRelativeOriginalLocationHref();
|
|
965
|
+
})(),
|
|
1028
966
|
// NOTE: Wether or not it's the preferred behavior, pushing to history
|
|
1029
967
|
// only works on user interaction so it have to be false
|
|
1030
968
|
doNavigateBackToLastPublicUrlIfTheTheUserNavigateBack: false,
|
|
@@ -1040,7 +978,10 @@ export async function createOidc_nonMemoized<
|
|
|
1040
978
|
}
|
|
1041
979
|
|
|
1042
980
|
return "ensure no interaction";
|
|
1043
|
-
})()
|
|
981
|
+
})(),
|
|
982
|
+
preRedirectHook: () => {
|
|
983
|
+
persistAuthState({ configId, state: undefined });
|
|
984
|
+
}
|
|
1044
985
|
});
|
|
1045
986
|
}
|
|
1046
987
|
|
|
@@ -1161,7 +1102,8 @@ export async function createOidc_nonMemoized<
|
|
|
1161
1102
|
interaction:
|
|
1162
1103
|
getPersistedAuthState({ configId }) === "explicitly logged out"
|
|
1163
1104
|
? "ensure interaction"
|
|
1164
|
-
: "directly redirect if active session show login otherwise"
|
|
1105
|
+
: "directly redirect if active session show login otherwise",
|
|
1106
|
+
preRedirectHook: undefined
|
|
1165
1107
|
});
|
|
1166
1108
|
},
|
|
1167
1109
|
initializationError: undefined
|
|
@@ -1233,6 +1175,7 @@ export async function createOidc_nonMemoized<
|
|
|
1233
1175
|
state: {
|
|
1234
1176
|
stateDescription: "logged in",
|
|
1235
1177
|
refreshTokenExpirationTime: currentTokens.refreshTokenExpirationTime,
|
|
1178
|
+
serverDateNow: currentTokens.getServerDateNow(),
|
|
1236
1179
|
idleSessionLifetimeInSeconds
|
|
1237
1180
|
}
|
|
1238
1181
|
});
|
|
@@ -1382,10 +1325,6 @@ export async function createOidc_nonMemoized<
|
|
|
1382
1325
|
prUnlock: new Promise<never>(() => {})
|
|
1383
1326
|
});
|
|
1384
1327
|
|
|
1385
|
-
globalContext.evtRequestToPersistTokens.post({
|
|
1386
|
-
configIdOfInstancePostingTheRequest: configId
|
|
1387
|
-
});
|
|
1388
|
-
|
|
1389
1328
|
await loginOrGoToAuthServer({
|
|
1390
1329
|
action: "login",
|
|
1391
1330
|
redirectUrl: window.location.href,
|
|
@@ -1393,7 +1332,8 @@ export async function createOidc_nonMemoized<
|
|
|
1393
1332
|
extraQueryParams_local: undefined,
|
|
1394
1333
|
transformUrlBeforeRedirect_local: undefined,
|
|
1395
1334
|
doNavigateBackToLastPublicUrlIfTheTheUserNavigateBack: false,
|
|
1396
|
-
interaction: "directly redirect if active session show login otherwise"
|
|
1335
|
+
interaction: "directly redirect if active session show login otherwise",
|
|
1336
|
+
preRedirectHook: undefined
|
|
1397
1337
|
});
|
|
1398
1338
|
assert(false, "136134");
|
|
1399
1339
|
};
|
|
@@ -1514,6 +1454,7 @@ export async function createOidc_nonMemoized<
|
|
|
1514
1454
|
state: {
|
|
1515
1455
|
stateDescription: "logged in",
|
|
1516
1456
|
refreshTokenExpirationTime: currentTokens.refreshTokenExpirationTime,
|
|
1457
|
+
serverDateNow: currentTokens.getServerDateNow(),
|
|
1517
1458
|
idleSessionLifetimeInSeconds
|
|
1518
1459
|
}
|
|
1519
1460
|
});
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { createStatefulEvt } from "../tools/StatefulEvt";
|
|
2
|
+
|
|
3
|
+
const SESSION_STORAGE_KEY = "oidc-spa:more-than-one-instance-cant-use-iframe";
|
|
4
|
+
|
|
5
|
+
export const evtIsThereMoreThanOneInstanceThatCantUserIframes = createStatefulEvt(
|
|
6
|
+
() => sessionStorage.getItem(SESSION_STORAGE_KEY) !== null
|
|
7
|
+
);
|
|
8
|
+
|
|
9
|
+
let count = 0;
|
|
10
|
+
|
|
11
|
+
export function notifyNewInstanceThatCantUseIframes() {
|
|
12
|
+
count++;
|
|
13
|
+
|
|
14
|
+
if (count === 1) {
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
if (evtIsThereMoreThanOneInstanceThatCantUserIframes.current) {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
sessionStorage.setItem(SESSION_STORAGE_KEY, "true");
|
|
23
|
+
evtIsThereMoreThanOneInstanceThatCantUserIframes.current = true;
|
|
24
|
+
}
|
|
@@ -30,6 +30,7 @@ namespace Params {
|
|
|
30
30
|
| "ensure no interaction"
|
|
31
31
|
| "ensure interaction"
|
|
32
32
|
| "directly redirect if active session show login otherwise";
|
|
33
|
+
preRedirectHook: (() => void) | undefined;
|
|
33
34
|
};
|
|
34
35
|
|
|
35
36
|
export type GoToAuthServer = Common & {
|
|
@@ -305,6 +306,10 @@ export function createLoginOrGoToAuthServer(params: {
|
|
|
305
306
|
|
|
306
307
|
log?.(`redirectMethod: ${redirectMethod}`);
|
|
307
308
|
|
|
309
|
+
if (rest.action === "login") {
|
|
310
|
+
rest.preRedirectHook?.();
|
|
311
|
+
}
|
|
312
|
+
|
|
308
313
|
return oidcClientTsUserManager
|
|
309
314
|
.signinRedirect({
|
|
310
315
|
state: stateData,
|
|
@@ -30,6 +30,7 @@ export function persistAuthState(params: {
|
|
|
30
30
|
stateDescription: "logged in";
|
|
31
31
|
idleSessionLifetimeInSeconds: number | undefined;
|
|
32
32
|
refreshTokenExpirationTime: number | undefined;
|
|
33
|
+
serverDateNow: number;
|
|
33
34
|
}
|
|
34
35
|
| {
|
|
35
36
|
stateDescription: "explicitly logged out";
|
|
@@ -56,14 +57,35 @@ export function persistAuthState(params: {
|
|
|
56
57
|
__brand: "PersistedAuthState-v1",
|
|
57
58
|
stateDescription: "logged in",
|
|
58
59
|
untilTime: (() => {
|
|
59
|
-
const {
|
|
60
|
-
|
|
60
|
+
const {
|
|
61
|
+
idleSessionLifetimeInSeconds,
|
|
62
|
+
refreshTokenExpirationTime,
|
|
63
|
+
serverDateNow
|
|
64
|
+
} = state;
|
|
65
|
+
|
|
66
|
+
const untilTime_real = (() => {
|
|
67
|
+
if (refreshTokenExpirationTime === undefined) {
|
|
68
|
+
return undefined;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const msBeforeExpirationOfTheSession =
|
|
72
|
+
refreshTokenExpirationTime - serverDateNow;
|
|
73
|
+
|
|
74
|
+
return Date.now() + msBeforeExpirationOfTheSession;
|
|
75
|
+
})();
|
|
76
|
+
|
|
77
|
+
const unitTime_userOverwrite = (() => {
|
|
78
|
+
if (idleSessionLifetimeInSeconds === undefined) {
|
|
79
|
+
return undefined;
|
|
80
|
+
}
|
|
61
81
|
|
|
62
|
-
if (idleSessionLifetimeInSeconds !== undefined) {
|
|
63
82
|
return Date.now() + idleSessionLifetimeInSeconds * 1000;
|
|
64
|
-
}
|
|
83
|
+
})();
|
|
65
84
|
|
|
66
|
-
return
|
|
85
|
+
return Math.min(
|
|
86
|
+
untilTime_real ?? Number.POSITIVE_INFINITY,
|
|
87
|
+
unitTime_userOverwrite ?? Number.POSITIVE_INFINITY
|
|
88
|
+
);
|
|
67
89
|
})()
|
|
68
90
|
});
|
|
69
91
|
case "explicitly logged out":
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { assert } from "../tools/tsafe/assert";
|
|
2
|
+
|
|
3
|
+
const SESSION_STORAGE_PREFIX = "lazy-session-storage:";
|
|
4
|
+
|
|
5
|
+
export type LazySessionStorage = {
|
|
6
|
+
// `Storage` methods, we don't use the type directly because it has [name: string]: any;
|
|
7
|
+
readonly length: number;
|
|
8
|
+
clear(): void;
|
|
9
|
+
getItem(key: string): string | null;
|
|
10
|
+
key(index: number): string | null;
|
|
11
|
+
removeItem(key: string): void;
|
|
12
|
+
setItem(key: string, value: string): void;
|
|
13
|
+
|
|
14
|
+
// Custom method
|
|
15
|
+
persistCurrentStateAndSubsequentChanges: () => void;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export function createLazySessionStorage(): LazySessionStorage {
|
|
19
|
+
const entries: { key: string; value: string }[] = [];
|
|
20
|
+
|
|
21
|
+
for (let i = 0; i < sessionStorage.length; i++) {
|
|
22
|
+
const key = sessionStorage.key(i);
|
|
23
|
+
assert(key !== null, "470498");
|
|
24
|
+
|
|
25
|
+
if (!key.startsWith(SESSION_STORAGE_PREFIX)) {
|
|
26
|
+
continue;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const value = sessionStorage.getItem(key);
|
|
30
|
+
|
|
31
|
+
assert(value !== null, "846771");
|
|
32
|
+
|
|
33
|
+
sessionStorage.removeItem(key);
|
|
34
|
+
|
|
35
|
+
entries.push({
|
|
36
|
+
key: key.slice(SESSION_STORAGE_PREFIX.length),
|
|
37
|
+
value
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
let isPersistenceEnabled = false;
|
|
42
|
+
|
|
43
|
+
const storage: LazySessionStorage = {
|
|
44
|
+
persistCurrentStateAndSubsequentChanges: () => {
|
|
45
|
+
isPersistenceEnabled = true;
|
|
46
|
+
|
|
47
|
+
for (let i = 0; i < storage.length; i++) {
|
|
48
|
+
const key = storage.key(i);
|
|
49
|
+
assert(key !== null, "803385");
|
|
50
|
+
|
|
51
|
+
const value = storage.getItem(key);
|
|
52
|
+
|
|
53
|
+
assert(value !== null, "777098");
|
|
54
|
+
|
|
55
|
+
storage.setItem(key, value);
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
get length() {
|
|
59
|
+
return entries.length;
|
|
60
|
+
},
|
|
61
|
+
key: index => {
|
|
62
|
+
const entry = entries[index];
|
|
63
|
+
|
|
64
|
+
if (entry === undefined) {
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return entry.key;
|
|
69
|
+
},
|
|
70
|
+
removeItem: key => {
|
|
71
|
+
const entry = entries.find(entry => entry.key === key);
|
|
72
|
+
|
|
73
|
+
if (entry === undefined) {
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
sessionStorage.removeItem(`${SESSION_STORAGE_PREFIX}${entry.key}`);
|
|
78
|
+
|
|
79
|
+
const index = entries.indexOf(entry);
|
|
80
|
+
|
|
81
|
+
entries.splice(index, 1);
|
|
82
|
+
},
|
|
83
|
+
clear: () => {
|
|
84
|
+
for (let i = 0; i < storage.length; i++) {
|
|
85
|
+
const key = storage.key(i);
|
|
86
|
+
assert(key !== null, "290875");
|
|
87
|
+
storage.removeItem(key);
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
getItem: key => {
|
|
91
|
+
const entry = entries.find(entry => entry.key === key);
|
|
92
|
+
if (entry === undefined) {
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
return entry.value;
|
|
96
|
+
},
|
|
97
|
+
setItem: (key, value) => {
|
|
98
|
+
if (isPersistenceEnabled) {
|
|
99
|
+
sessionStorage.setItem(`${SESSION_STORAGE_PREFIX}${key}`, value);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
update: {
|
|
103
|
+
const entry = entries.find(entry => entry.key === key);
|
|
104
|
+
|
|
105
|
+
if (entry === undefined) {
|
|
106
|
+
break update;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
entry.value = value;
|
|
110
|
+
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
entries.push({ key, value });
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
return storage;
|
|
119
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type
|
|
1
|
+
export type LazySessionStorage = {
|
|
2
2
|
readonly length: number;
|
|
3
3
|
clear(): void;
|
|
4
4
|
getItem(key: string): string | null;
|
|
@@ -7,6 +7,4 @@ export type EphemeralSessionStorage = {
|
|
|
7
7
|
setItem(key: string, value: string): void;
|
|
8
8
|
persistCurrentStateAndSubsequentChanges: () => void;
|
|
9
9
|
};
|
|
10
|
-
export declare function
|
|
11
|
-
sessionStorageTtlMs: number;
|
|
12
|
-
}): EphemeralSessionStorage;
|
|
10
|
+
export declare function createLazySessionStorage(): LazySessionStorage;
|