oidc-spa 6.15.1 → 7.0.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/README.md +12 -13
- package/core/Oidc.d.ts +24 -12
- package/core/createOidc.d.ts +15 -30
- package/core/createOidc.js +184 -146
- package/core/createOidc.js.map +1 -1
- package/core/handleOidcCallback.js +2 -29
- package/core/handleOidcCallback.js.map +1 -1
- package/core/loginOrGoToAuthServer.d.ts +1 -2
- package/core/loginOrGoToAuthServer.js +10 -10
- package/core/loginOrGoToAuthServer.js.map +1 -1
- package/core/loginSilent.d.ts +1 -1
- package/core/loginSilent.js +4 -4
- package/core/loginSilent.js.map +1 -1
- package/core/oidcClientTsUserToTokens.d.ts +1 -2
- package/core/oidcClientTsUserToTokens.js +93 -58
- package/core/oidcClientTsUserToTokens.js.map +1 -1
- package/mock/oidc.d.ts +1 -1
- package/mock/oidc.js +29 -19
- package/mock/oidc.js.map +1 -1
- package/package.json +1 -5
- package/react/react.d.ts +9 -14
- package/react/react.js +32 -60
- package/react/react.js.map +1 -1
- package/src/core/Oidc.ts +27 -14
- package/src/core/createOidc.ts +189 -149
- package/src/core/handleOidcCallback.ts +2 -55
- package/src/core/loginOrGoToAuthServer.ts +10 -11
- package/src/core/loginSilent.ts +4 -4
- package/src/core/oidcClientTsUserToTokens.ts +129 -82
- package/src/mock/oidc.ts +16 -6
- package/src/react/react.tsx +52 -80
- package/src/tools/readExpirationTimeInJwt.ts +4 -5
- package/src/tools/startCountdown.ts +4 -5
- package/tools/readExpirationTimeInJwt.js +4 -4
- package/tools/readExpirationTimeInJwt.js.map +1 -1
- package/tools/startCountdown.d.ts +3 -2
- package/tools/startCountdown.js +4 -4
- package/tools/startCountdown.js.map +1 -1
- package/vendor/frontend/oidc-client-ts-and-jwt-decode.js +1 -1
- package/core/debug966975.d.ts +0 -7
- package/core/debug966975.js +0 -88
- package/core/debug966975.js.map +0 -1
- package/src/core/debug966975.ts +0 -85
package/src/core/createOidc.ts
CHANGED
|
@@ -8,7 +8,6 @@ import type { OidcMetadata } from "./OidcMetadata";
|
|
|
8
8
|
import { id, assert, is, type Equals } from "../vendor/frontend/tsafe";
|
|
9
9
|
import { setTimeout, clearTimeout } from "../tools/workerTimers";
|
|
10
10
|
import { Deferred } from "../tools/Deferred";
|
|
11
|
-
import { decodeJwt } from "../tools/decodeJwt";
|
|
12
11
|
import { createEvtIsUserActive } from "./evtIsUserActive";
|
|
13
12
|
import { createStartCountdown } from "../tools/startCountdown";
|
|
14
13
|
import { toHumanReadableDuration } from "../tools/toHumanReadableDuration";
|
|
@@ -23,7 +22,7 @@ import { type StateData, generateStateQueryParamValue, STATE_STORE_KEY_PREFIX }
|
|
|
23
22
|
import { notifyOtherTabsOfLogout, getPrOtherTabLogout } from "./logoutPropagationToOtherTabs";
|
|
24
23
|
import { notifyOtherTabsOfLogin, getPrOtherTabLogin } from "./loginPropagationToOtherTabs";
|
|
25
24
|
import { getConfigId } from "./configId";
|
|
26
|
-
import { oidcClientTsUserToTokens
|
|
25
|
+
import { oidcClientTsUserToTokens } from "./oidcClientTsUserToTokens";
|
|
27
26
|
import { loginSilent } from "./loginSilent";
|
|
28
27
|
import { authResponseToUrl } from "./AuthResponse";
|
|
29
28
|
import { handleOidcCallback, retrieveRedirectAuthResponseAndStateData } from "./handleOidcCallback";
|
|
@@ -60,23 +59,14 @@ export type ParamsOfCreateOidc<
|
|
|
60
59
|
* (the scope "openid" is added automatically as it's mandatory)
|
|
61
60
|
**/
|
|
62
61
|
scopes?: string[];
|
|
63
|
-
/**
|
|
64
|
-
* Transform the url of the authorization endpoint before redirecting to the login pages.
|
|
65
|
-
*/
|
|
66
|
-
transformUrlBeforeRedirect?: (url: string) => string;
|
|
67
62
|
|
|
68
63
|
/**
|
|
69
|
-
* NOTE: Will replace transformUrlBeforeRedirect in the next major version.
|
|
70
|
-
*
|
|
71
64
|
* Transform the url (authorization endpoint) before redirecting to the login pages.
|
|
72
65
|
*
|
|
73
66
|
* The isSilent parameter is true when the redirect is initiated in the background iframe for silent signin.
|
|
74
67
|
* This can be used to omit ui related query parameters (like `ui_locales`).
|
|
75
68
|
*/
|
|
76
|
-
|
|
77
|
-
authorizationUrl: string;
|
|
78
|
-
isSilent: boolean;
|
|
79
|
-
}) => string;
|
|
69
|
+
transformUrlBeforeRedirect?: (params: { authorizationUrl: string; isSilent: boolean }) => string;
|
|
80
70
|
|
|
81
71
|
/**
|
|
82
72
|
* Extra query params to be added to the authorization endpoint url before redirecting or silent signing in.
|
|
@@ -120,30 +110,10 @@ export type ParamsOfCreateOidc<
|
|
|
120
110
|
*/
|
|
121
111
|
homeUrl: string;
|
|
122
112
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
*
|
|
127
|
-
* This is only useful for when you also shipping your app as a Desktop App with Electron.
|
|
128
|
-
* NOTE that even in this case, it's not automatic, you still need to handle the response
|
|
129
|
-
* in the electron node process.
|
|
130
|
-
*
|
|
131
|
-
* Example: __callbackUri: "myapp://oidc-callback/"
|
|
132
|
-
*/
|
|
133
|
-
__callbackUri?: string;
|
|
113
|
+
decodedIdTokenSchema?: {
|
|
114
|
+
parse: (decodedIdToken_original: Oidc.Tokens.DecodedIdToken_base) => DecodedIdToken;
|
|
115
|
+
};
|
|
134
116
|
|
|
135
|
-
decodedIdTokenSchema?: { parse: (data: unknown) => DecodedIdToken };
|
|
136
|
-
/**
|
|
137
|
-
* @deprecated: Use idleSessionLifetimeInSeconds instead
|
|
138
|
-
*
|
|
139
|
-
* This parameter defines after how many seconds of inactivity the user should be
|
|
140
|
-
* logged out automatically.
|
|
141
|
-
*
|
|
142
|
-
* WARNING: It should be configured on the identity server side
|
|
143
|
-
* as it's the authoritative source for security policies and not the client.
|
|
144
|
-
* If you don't provide this parameter it will be inferred from the refresh token expiration time.
|
|
145
|
-
* */
|
|
146
|
-
__unsafe_ssoSessionIdleSeconds?: number;
|
|
147
117
|
/**
|
|
148
118
|
* This parameter defines after how many seconds of inactivity the user should be
|
|
149
119
|
* logged out automatically.
|
|
@@ -154,6 +124,9 @@ export type ParamsOfCreateOidc<
|
|
|
154
124
|
* */
|
|
155
125
|
idleSessionLifetimeInSeconds?: number;
|
|
156
126
|
|
|
127
|
+
/**
|
|
128
|
+
* Default: { redirectTo: "current page" }
|
|
129
|
+
*/
|
|
157
130
|
autoLogoutParams?: Parameters<Oidc.LoggedIn<any>["logout"]>[0];
|
|
158
131
|
autoLogin?: AutoLogin;
|
|
159
132
|
|
|
@@ -166,6 +139,16 @@ export type ParamsOfCreateOidc<
|
|
|
166
139
|
|
|
167
140
|
debugLogs?: boolean;
|
|
168
141
|
|
|
142
|
+
/**
|
|
143
|
+
* WARNING: This option exists solely as a workaround
|
|
144
|
+
* for limitations in the Google OAuth API.
|
|
145
|
+
* See: https://docs.oidc-spa.dev/providers-configuration/google-oauth
|
|
146
|
+
*
|
|
147
|
+
* Do not use this for other providers.
|
|
148
|
+
* If you think you need a client secret in a SPA, you are likely
|
|
149
|
+
* trying to use a confidential (private) client in the browser,
|
|
150
|
+
* which is insecure and not supported.
|
|
151
|
+
*/
|
|
169
152
|
__unsafe_clientSecret?: string;
|
|
170
153
|
|
|
171
154
|
/**
|
|
@@ -195,8 +178,6 @@ const globalContext = {
|
|
|
195
178
|
evtRequestToPersistTokens: createEvt<{ configIdOfInstancePostingTheRequest: string }>()
|
|
196
179
|
};
|
|
197
180
|
|
|
198
|
-
const MIN_RENEW_BEFORE_EXPIRE_MS = 2_000;
|
|
199
|
-
|
|
200
181
|
/** @see: https://docs.oidc-spa.dev/v/v6/usage */
|
|
201
182
|
export async function createOidc<
|
|
202
183
|
DecodedIdToken extends Record<string, unknown> = Record<string, unknown>,
|
|
@@ -296,15 +277,12 @@ export async function createOidc_nonMemoized<
|
|
|
296
277
|
}
|
|
297
278
|
): Promise<AutoLogin extends true ? Oidc.LoggedIn<DecodedIdToken> : Oidc<DecodedIdToken>> {
|
|
298
279
|
const {
|
|
299
|
-
transformUrlBeforeRedirect_next,
|
|
300
280
|
transformUrlBeforeRedirect,
|
|
301
281
|
extraQueryParams: extraQueryParamsOrGetter,
|
|
302
282
|
extraTokenParams: extraTokenParamsOrGetter,
|
|
303
283
|
homeUrl: homeUrl_params,
|
|
304
|
-
__callbackUri,
|
|
305
284
|
decodedIdTokenSchema,
|
|
306
|
-
|
|
307
|
-
idleSessionLifetimeInSeconds = __unsafe_ssoSessionIdleSeconds,
|
|
285
|
+
idleSessionLifetimeInSeconds,
|
|
308
286
|
autoLogoutParams = { redirectTo: "current page" },
|
|
309
287
|
autoLogin = false,
|
|
310
288
|
postLoginRedirectUrl: postLoginRedirectUrl_default,
|
|
@@ -347,7 +325,7 @@ export async function createOidc_nonMemoized<
|
|
|
347
325
|
});
|
|
348
326
|
|
|
349
327
|
const callbackUri = toFullyQualifiedUrl({
|
|
350
|
-
urlish:
|
|
328
|
+
urlish: homeUrl,
|
|
351
329
|
doAssertNoQueryParams: true,
|
|
352
330
|
doOutputWithTrailingSlash: true
|
|
353
331
|
});
|
|
@@ -476,7 +454,6 @@ export async function createOidc_nonMemoized<
|
|
|
476
454
|
configId,
|
|
477
455
|
oidcClientTsUserManager,
|
|
478
456
|
transformUrlBeforeRedirect,
|
|
479
|
-
transformUrlBeforeRedirect_next,
|
|
480
457
|
getExtraQueryParams,
|
|
481
458
|
getExtraTokenParams,
|
|
482
459
|
homeUrl,
|
|
@@ -675,7 +652,7 @@ export async function createOidc_nonMemoized<
|
|
|
675
652
|
oidcClientTsUserManager,
|
|
676
653
|
stateQueryParamValue_instance,
|
|
677
654
|
configId,
|
|
678
|
-
|
|
655
|
+
transformUrlBeforeRedirect,
|
|
679
656
|
getExtraQueryParams,
|
|
680
657
|
getExtraTokenParams,
|
|
681
658
|
autoLogin
|
|
@@ -966,18 +943,33 @@ export async function createOidc_nonMemoized<
|
|
|
966
943
|
|
|
967
944
|
const onTokenChanges = new Set<(tokens: Oidc.Tokens<DecodedIdToken>) => void>();
|
|
968
945
|
|
|
969
|
-
const { sid: sessionId, sub: subjectId } =
|
|
970
|
-
currentTokens.idToken
|
|
971
|
-
);
|
|
946
|
+
const { sid: sessionId, sub: subjectId } = currentTokens.decodedIdToken_original;
|
|
972
947
|
|
|
973
948
|
assert(subjectId !== undefined, "The 'sub' claim is missing from the id token");
|
|
949
|
+
assert(sessionId === undefined || typeof sessionId === "string");
|
|
974
950
|
|
|
975
951
|
const oidc_loggedIn = id<Oidc.LoggedIn<DecodedIdToken>>({
|
|
976
952
|
...oidc_common,
|
|
977
953
|
isUserLoggedIn: true,
|
|
978
|
-
getTokens: () =>
|
|
979
|
-
|
|
980
|
-
|
|
954
|
+
getTokens: async () => {
|
|
955
|
+
renew_tokens: {
|
|
956
|
+
{
|
|
957
|
+
const msBeforeExpirationOfTheAccessToken =
|
|
958
|
+
currentTokens.accessTokenExpirationTime - Date.now();
|
|
959
|
+
|
|
960
|
+
if (msBeforeExpirationOfTheAccessToken > 30_000) {
|
|
961
|
+
break renew_tokens;
|
|
962
|
+
}
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
{
|
|
966
|
+
const msElapsedSinceCurrentTokenWereIssued = Date.now() - currentTokens.issuedAtTime;
|
|
967
|
+
|
|
968
|
+
if (msElapsedSinceCurrentTokenWereIssued < 5_000) {
|
|
969
|
+
break renew_tokens;
|
|
970
|
+
}
|
|
971
|
+
}
|
|
972
|
+
|
|
981
973
|
await oidc_loggedIn.renewTokens();
|
|
982
974
|
}
|
|
983
975
|
|
|
@@ -1059,17 +1051,42 @@ export async function createOidc_nonMemoized<
|
|
|
1059
1051
|
}) {
|
|
1060
1052
|
const { extraTokenParams } = params;
|
|
1061
1053
|
|
|
1054
|
+
const fallbackToFullPageReload = async (): Promise<never> => {
|
|
1055
|
+
persistAuthState({ configId, state: undefined });
|
|
1056
|
+
|
|
1057
|
+
await waitForAllOtherOngoingLoginOrRefreshProcessesToComplete({
|
|
1058
|
+
prUnlock: new Promise<never>(() => {})
|
|
1059
|
+
});
|
|
1060
|
+
|
|
1061
|
+
globalContext.evtRequestToPersistTokens.post({
|
|
1062
|
+
configIdOfInstancePostingTheRequest: configId
|
|
1063
|
+
});
|
|
1064
|
+
|
|
1065
|
+
await loginOrGoToAuthServer({
|
|
1066
|
+
action: "login",
|
|
1067
|
+
redirectUrl: window.location.href,
|
|
1068
|
+
doForceReloadOnBfCache: true,
|
|
1069
|
+
extraQueryParams_local: undefined,
|
|
1070
|
+
transformUrlBeforeRedirect_local: undefined,
|
|
1071
|
+
doNavigateBackToLastPublicUrlIfTheTheUserNavigateBack: false,
|
|
1072
|
+
interaction: "directly redirect if active session show login otherwise"
|
|
1073
|
+
});
|
|
1074
|
+
assert(false, "136134");
|
|
1075
|
+
};
|
|
1076
|
+
|
|
1062
1077
|
if (!currentTokens.hasRefreshToken && !canUseIframe) {
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1078
|
+
log?.(
|
|
1079
|
+
[
|
|
1080
|
+
"Unable to refresh tokens without a full app reload,",
|
|
1081
|
+
"because no refresh token is available",
|
|
1082
|
+
"and your app setup prevents silent sign-in via iframe.",
|
|
1083
|
+
"Your only option to refresh tokens is to call `window.location.reload()`"
|
|
1084
|
+
].join(" ")
|
|
1085
|
+
);
|
|
1069
1086
|
|
|
1070
|
-
|
|
1087
|
+
await fallbackToFullPageReload();
|
|
1071
1088
|
|
|
1072
|
-
|
|
1089
|
+
assert(false, "136135");
|
|
1073
1090
|
}
|
|
1074
1091
|
|
|
1075
1092
|
log?.("Renewing tokens");
|
|
@@ -1080,7 +1097,7 @@ export async function createOidc_nonMemoized<
|
|
|
1080
1097
|
oidcClientTsUserManager,
|
|
1081
1098
|
stateQueryParamValue_instance,
|
|
1082
1099
|
configId,
|
|
1083
|
-
|
|
1100
|
+
transformUrlBeforeRedirect,
|
|
1084
1101
|
getExtraQueryParams,
|
|
1085
1102
|
getExtraTokenParams: () => extraTokenParams,
|
|
1086
1103
|
autoLogin
|
|
@@ -1088,6 +1105,8 @@ export async function createOidc_nonMemoized<
|
|
|
1088
1105
|
|
|
1089
1106
|
if (result_loginSilent.outcome === "failure") {
|
|
1090
1107
|
completeLoginOrRefreshProcess();
|
|
1108
|
+
// NOTE: This is a configuration or network error, okay to throw,
|
|
1109
|
+
// this exception doesn't have to be handle if it fails it fails.
|
|
1091
1110
|
throw new Error(result_loginSilent.cause);
|
|
1092
1111
|
}
|
|
1093
1112
|
|
|
@@ -1120,35 +1139,27 @@ export async function createOidc_nonMemoized<
|
|
|
1120
1139
|
|
|
1121
1140
|
if (authResponse_error === undefined) {
|
|
1122
1141
|
completeLoginOrRefreshProcess();
|
|
1142
|
+
// Same here, if it fails it fails.
|
|
1123
1143
|
throw error;
|
|
1124
1144
|
}
|
|
1125
|
-
|
|
1126
|
-
oidcClientTsUser_scope = undefined;
|
|
1127
1145
|
}
|
|
1128
1146
|
|
|
1129
1147
|
if (oidcClientTsUser_scope === undefined) {
|
|
1130
|
-
|
|
1148
|
+
// NOTE: Here we got a response but it's an error, session might have been
|
|
1149
|
+
// deleted or other edge case.
|
|
1131
1150
|
|
|
1132
1151
|
completeLoginOrRefreshProcess();
|
|
1133
1152
|
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1153
|
+
log?.(
|
|
1154
|
+
[
|
|
1155
|
+
"The user is probably not logged in anymore,",
|
|
1156
|
+
"need to redirect to login pages"
|
|
1157
|
+
].join(" ")
|
|
1158
|
+
);
|
|
1137
1159
|
|
|
1138
|
-
|
|
1139
|
-
configIdOfInstancePostingTheRequest: configId
|
|
1140
|
-
});
|
|
1160
|
+
await fallbackToFullPageReload();
|
|
1141
1161
|
|
|
1142
|
-
|
|
1143
|
-
action: "login",
|
|
1144
|
-
redirectUrl: window.location.href,
|
|
1145
|
-
doForceReloadOnBfCache: true,
|
|
1146
|
-
extraQueryParams_local: undefined,
|
|
1147
|
-
transformUrlBeforeRedirect_local: undefined,
|
|
1148
|
-
doNavigateBackToLastPublicUrlIfTheTheUserNavigateBack: false,
|
|
1149
|
-
interaction: "ensure no interaction"
|
|
1150
|
-
});
|
|
1151
|
-
assert(false, "136134");
|
|
1162
|
+
assert(false, "136135");
|
|
1152
1163
|
}
|
|
1153
1164
|
|
|
1154
1165
|
oidcClientTsUser = oidcClientTsUser_scope;
|
|
@@ -1298,64 +1309,83 @@ export async function createOidc_nonMemoized<
|
|
|
1298
1309
|
}
|
|
1299
1310
|
|
|
1300
1311
|
(function scheduleRenew() {
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1312
|
+
if (!currentTokens.hasRefreshToken && !canUseIframe) {
|
|
1313
|
+
log?.(
|
|
1314
|
+
[
|
|
1315
|
+
"Disabling token auto refresh mechanism because we",
|
|
1316
|
+
"have no way to renew the tokens without a full page reload"
|
|
1317
|
+
].join(" ")
|
|
1318
|
+
);
|
|
1319
|
+
return;
|
|
1320
|
+
}
|
|
1305
1321
|
|
|
1306
|
-
|
|
1322
|
+
const typeOfTheTokenWeGotTheTtlFrom = currentTokens.hasRefreshToken ? "refresh" : "access";
|
|
1307
1323
|
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
doForceReloadOnBfCache: true,
|
|
1312
|
-
extraQueryParams_local: undefined,
|
|
1313
|
-
transformUrlBeforeRedirect_local: undefined,
|
|
1314
|
-
// NOTE: Wether or not it's the preferred behavior, pushing to history
|
|
1315
|
-
// only works on user interaction so it have to be false
|
|
1316
|
-
doNavigateBackToLastPublicUrlIfTheTheUserNavigateBack: false,
|
|
1317
|
-
interaction: "ensure no interaction"
|
|
1318
|
-
});
|
|
1319
|
-
};
|
|
1324
|
+
const msBeforeExpiration =
|
|
1325
|
+
(currentTokens.refreshTokenExpirationTime ?? currentTokens.accessTokenExpirationTime) -
|
|
1326
|
+
Date.now();
|
|
1320
1327
|
|
|
1321
|
-
const
|
|
1328
|
+
const RENEW_MS_BEFORE_EXPIRES = 30_000;
|
|
1322
1329
|
|
|
1323
|
-
if (msBeforeExpiration <=
|
|
1330
|
+
if (msBeforeExpiration <= RENEW_MS_BEFORE_EXPIRES) {
|
|
1324
1331
|
// NOTE: We just got a new token that is about to expire. This means that
|
|
1325
1332
|
// the refresh token has reached it's max SSO time.
|
|
1326
|
-
|
|
1333
|
+
// ...or that the refresh token have a very short lifespan...
|
|
1334
|
+
// anyway, no need to keep alive, it will probably redirect on the next getTokens() or refreshTokens() call
|
|
1335
|
+
log?.(
|
|
1336
|
+
[
|
|
1337
|
+
"Disabling auto renew mechanism. We just got fresh tokens",
|
|
1338
|
+
(() => {
|
|
1339
|
+
switch (typeOfTheTokenWeGotTheTtlFrom) {
|
|
1340
|
+
case "refresh":
|
|
1341
|
+
return [
|
|
1342
|
+
" and the refresh token is already about to expires.",
|
|
1343
|
+
"This means that we have reached the max session lifespan, we can't keep",
|
|
1344
|
+
"the session alive any longer.",
|
|
1345
|
+
"(This can also mean that the refresh token was configured with a TTL,",
|
|
1346
|
+
"aka the idle session lifespan, too low to make sense)"
|
|
1347
|
+
].join(" ");
|
|
1348
|
+
case "access":
|
|
1349
|
+
return [
|
|
1350
|
+
", we have no refresh token and the access token is already about to expire",
|
|
1351
|
+
"we would spam the auth server by constantly renewing the access token in the background",
|
|
1352
|
+
"avoiding to do so."
|
|
1353
|
+
].join(" ");
|
|
1354
|
+
}
|
|
1355
|
+
})()
|
|
1356
|
+
].join(" ")
|
|
1357
|
+
);
|
|
1327
1358
|
return;
|
|
1328
1359
|
}
|
|
1329
1360
|
|
|
1330
|
-
// NOTE: We refresh the token 25 seconds before it expires.
|
|
1331
|
-
// If the token expiration time is less than 25 seconds we refresh the token when
|
|
1332
|
-
// only 1/10 of the token time is left.
|
|
1333
|
-
const renewMsBeforeExpires = Math.max(
|
|
1334
|
-
Math.min(25_000, msBeforeExpiration * 0.1),
|
|
1335
|
-
MIN_RENEW_BEFORE_EXPIRE_MS
|
|
1336
|
-
);
|
|
1337
|
-
|
|
1338
1361
|
log?.(
|
|
1339
1362
|
[
|
|
1340
1363
|
toHumanReadableDuration(msBeforeExpiration),
|
|
1341
|
-
`before expiration of the
|
|
1342
|
-
`Scheduling renewal ${toHumanReadableDuration(
|
|
1364
|
+
`before expiration of the ${typeOfTheTokenWeGotTheTtlFrom} token.`,
|
|
1365
|
+
`Scheduling renewal ${toHumanReadableDuration(
|
|
1366
|
+
RENEW_MS_BEFORE_EXPIRES
|
|
1367
|
+
)} before expiration to keep the session alive on the OIDC server.`
|
|
1343
1368
|
].join(" ")
|
|
1344
1369
|
);
|
|
1345
1370
|
|
|
1346
|
-
const timer = setTimeout(
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1371
|
+
const timer = setTimeout(
|
|
1372
|
+
async () => {
|
|
1373
|
+
log?.(
|
|
1374
|
+
`Renewing the ${typeOfTheTokenWeGotTheTtlFrom} token now as it will expires in ${toHumanReadableDuration(
|
|
1375
|
+
RENEW_MS_BEFORE_EXPIRES
|
|
1376
|
+
)}`
|
|
1377
|
+
);
|
|
1352
1378
|
|
|
1353
|
-
try {
|
|
1354
1379
|
await oidc_loggedIn.renewTokens();
|
|
1355
|
-
}
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1380
|
+
},
|
|
1381
|
+
Math.min(
|
|
1382
|
+
msBeforeExpiration - RENEW_MS_BEFORE_EXPIRES,
|
|
1383
|
+
// NOTE: We want to make sure we do not overflow the setTimeout
|
|
1384
|
+
// that must be a 32 bit unsigned integer.
|
|
1385
|
+
// This can happen if the tokenExpirationTime is more than 24.8 days in the future.
|
|
1386
|
+
Math.pow(2, 31) - 1
|
|
1387
|
+
)
|
|
1388
|
+
);
|
|
1359
1389
|
|
|
1360
1390
|
const { unsubscribe: tokenChangeUnsubscribe } = oidc_loggedIn.subscribeToTokensChange(() => {
|
|
1361
1391
|
clearTimeout(timer);
|
|
@@ -1365,10 +1395,19 @@ export async function createOidc_nonMemoized<
|
|
|
1365
1395
|
})();
|
|
1366
1396
|
|
|
1367
1397
|
auto_logout: {
|
|
1368
|
-
|
|
1369
|
-
(
|
|
1370
|
-
|
|
1371
|
-
|
|
1398
|
+
const getCurrentRefreshTokenTtlInSeconds = () => {
|
|
1399
|
+
if (idleSessionLifetimeInSeconds !== undefined) {
|
|
1400
|
+
return idleSessionLifetimeInSeconds;
|
|
1401
|
+
}
|
|
1402
|
+
|
|
1403
|
+
if (currentTokens.refreshTokenExpirationTime === undefined) {
|
|
1404
|
+
return undefined;
|
|
1405
|
+
}
|
|
1406
|
+
|
|
1407
|
+
return (currentTokens.refreshTokenExpirationTime - currentTokens.issuedAtTime) / 1000;
|
|
1408
|
+
};
|
|
1409
|
+
|
|
1410
|
+
if (getCurrentRefreshTokenTtlInSeconds() === undefined) {
|
|
1372
1411
|
log?.(
|
|
1373
1412
|
`${
|
|
1374
1413
|
currentTokens.hasRefreshToken
|
|
@@ -1380,31 +1419,6 @@ export async function createOidc_nonMemoized<
|
|
|
1380
1419
|
}
|
|
1381
1420
|
|
|
1382
1421
|
const { startCountdown } = createStartCountdown({
|
|
1383
|
-
getCountdownEndTime: (() => {
|
|
1384
|
-
const getCountdownEndTime = () =>
|
|
1385
|
-
idleSessionLifetimeInSeconds !== undefined
|
|
1386
|
-
? Date.now() + idleSessionLifetimeInSeconds * 1000
|
|
1387
|
-
: (assert(currentTokens.hasRefreshToken, "230198"),
|
|
1388
|
-
assert(currentTokens.refreshTokenExpirationTime !== undefined, "435490"),
|
|
1389
|
-
currentTokens.refreshTokenExpirationTime);
|
|
1390
|
-
|
|
1391
|
-
const durationBeforeAutoLogout = toHumanReadableDuration(
|
|
1392
|
-
getCountdownEndTime() - Date.now()
|
|
1393
|
-
);
|
|
1394
|
-
|
|
1395
|
-
log?.(
|
|
1396
|
-
[
|
|
1397
|
-
`The user will be automatically logged out after ${durationBeforeAutoLogout} of inactivity.`,
|
|
1398
|
-
idleSessionLifetimeInSeconds === undefined
|
|
1399
|
-
? undefined
|
|
1400
|
-
: `It was artificially defined by using the idleSessionLifetimeInSeconds param.`
|
|
1401
|
-
]
|
|
1402
|
-
.filter(x => x !== undefined)
|
|
1403
|
-
.join("\n")
|
|
1404
|
-
);
|
|
1405
|
-
|
|
1406
|
-
return getCountdownEndTime;
|
|
1407
|
-
})(),
|
|
1408
1422
|
tickCallback: ({ secondsLeft }) => {
|
|
1409
1423
|
Array.from(autoLogoutCountdownTickCallbacks).forEach(tickCallback =>
|
|
1410
1424
|
tickCallback({ secondsLeft })
|
|
@@ -1431,9 +1445,35 @@ export async function createOidc_nonMemoized<
|
|
|
1431
1445
|
}
|
|
1432
1446
|
} else {
|
|
1433
1447
|
assert(stopCountdown === undefined, "902992");
|
|
1434
|
-
|
|
1448
|
+
|
|
1449
|
+
const currentRefreshTokenTtlInSeconds = getCurrentRefreshTokenTtlInSeconds();
|
|
1450
|
+
|
|
1451
|
+
assert(currentRefreshTokenTtlInSeconds !== undefined, "902992326");
|
|
1452
|
+
|
|
1453
|
+
stopCountdown = startCountdown({
|
|
1454
|
+
countDownFromSeconds: currentRefreshTokenTtlInSeconds
|
|
1455
|
+
}).stopCountdown;
|
|
1435
1456
|
}
|
|
1436
1457
|
});
|
|
1458
|
+
|
|
1459
|
+
{
|
|
1460
|
+
const currentRefreshTokenTtlInSeconds = getCurrentRefreshTokenTtlInSeconds();
|
|
1461
|
+
|
|
1462
|
+
assert(currentRefreshTokenTtlInSeconds !== undefined, "9029923253");
|
|
1463
|
+
|
|
1464
|
+
log?.(
|
|
1465
|
+
[
|
|
1466
|
+
`The user will be automatically logged out after ${toHumanReadableDuration(
|
|
1467
|
+
currentRefreshTokenTtlInSeconds * 1_000
|
|
1468
|
+
)} of inactivity.`,
|
|
1469
|
+
idleSessionLifetimeInSeconds === undefined
|
|
1470
|
+
? undefined
|
|
1471
|
+
: `It was artificially defined by using the idleSessionLifetimeInSeconds param.`
|
|
1472
|
+
]
|
|
1473
|
+
.filter(x => x !== undefined)
|
|
1474
|
+
.join("\n")
|
|
1475
|
+
);
|
|
1476
|
+
}
|
|
1437
1477
|
}
|
|
1438
1478
|
|
|
1439
1479
|
return oidc_loggedIn;
|