oidc-spa 6.15.1 → 7.0.0
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 +131 -123
- 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 +1 -7
- package/react/react.js +8 -59
- package/react/react.js.map +1 -1
- package/src/core/Oidc.ts +27 -14
- package/src/core/createOidc.ts +121 -119
- 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 +11 -72
- package/src/tools/readExpirationTimeInJwt.ts +4 -5
- package/tools/readExpirationTimeInJwt.js +4 -4
- package/tools/readExpirationTimeInJwt.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,55 @@ export async function createOidc_nonMemoized<
|
|
|
1298
1309
|
}
|
|
1299
1310
|
|
|
1300
1311
|
(function scheduleRenew() {
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1312
|
+
if (!currentTokens.hasRefreshToken && !canUseIframe) {
|
|
1313
|
+
log?.(
|
|
1314
|
+
"Disabling token auto refresh mechanism because we have no way to do it without reloading the page"
|
|
1315
|
+
);
|
|
1316
|
+
return;
|
|
1317
|
+
}
|
|
1307
1318
|
|
|
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
|
-
};
|
|
1319
|
+
const msBeforeExpiration =
|
|
1320
|
+
(currentTokens.refreshTokenExpirationTime ?? currentTokens.accessTokenExpirationTime) -
|
|
1321
|
+
Date.now();
|
|
1320
1322
|
|
|
1321
|
-
const
|
|
1323
|
+
const RENEW_MS_BEFORE_EXPIRES = 30_000;
|
|
1322
1324
|
|
|
1323
|
-
if (msBeforeExpiration <=
|
|
1325
|
+
if (msBeforeExpiration <= RENEW_MS_BEFORE_EXPIRES) {
|
|
1324
1326
|
// NOTE: We just got a new token that is about to expire. This means that
|
|
1325
1327
|
// the refresh token has reached it's max SSO time.
|
|
1326
|
-
|
|
1328
|
+
// ...or that the refresh token have a very short lifespan...
|
|
1329
|
+
// anyway, no need to keep alive, it will probably redirect on the next getTokens() or refreshTokens() call
|
|
1327
1330
|
return;
|
|
1328
1331
|
}
|
|
1329
1332
|
|
|
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
1333
|
log?.(
|
|
1339
1334
|
[
|
|
1340
1335
|
toHumanReadableDuration(msBeforeExpiration),
|
|
1341
1336
|
`before expiration of the access token.`,
|
|
1342
|
-
`Scheduling renewal ${toHumanReadableDuration(
|
|
1337
|
+
`Scheduling renewal ${toHumanReadableDuration(
|
|
1338
|
+
RENEW_MS_BEFORE_EXPIRES
|
|
1339
|
+
)} before expiration`
|
|
1343
1340
|
].join(" ")
|
|
1344
1341
|
);
|
|
1345
1342
|
|
|
1346
|
-
const timer = setTimeout(
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1343
|
+
const timer = setTimeout(
|
|
1344
|
+
async () => {
|
|
1345
|
+
log?.(
|
|
1346
|
+
`Renewing the access token now as it will expires in ${toHumanReadableDuration(
|
|
1347
|
+
RENEW_MS_BEFORE_EXPIRES
|
|
1348
|
+
)}`
|
|
1349
|
+
);
|
|
1352
1350
|
|
|
1353
|
-
try {
|
|
1354
1351
|
await oidc_loggedIn.renewTokens();
|
|
1355
|
-
}
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1352
|
+
},
|
|
1353
|
+
Math.min(
|
|
1354
|
+
msBeforeExpiration - RENEW_MS_BEFORE_EXPIRES,
|
|
1355
|
+
// NOTE: We want to make sure we do not overflow the setTimeout
|
|
1356
|
+
// that must be a 32 bit unsigned integer.
|
|
1357
|
+
// This can happen if the tokenExpirationTime is more than 24.8 days in the future.
|
|
1358
|
+
Math.pow(2, 31) - 1
|
|
1359
|
+
)
|
|
1360
|
+
);
|
|
1359
1361
|
|
|
1360
1362
|
const { unsubscribe: tokenChangeUnsubscribe } = oidc_loggedIn.subscribeToTokensChange(() => {
|
|
1361
1363
|
clearTimeout(timer);
|
|
@@ -8,7 +8,6 @@ import { assert, id } from "../vendor/frontend/tsafe";
|
|
|
8
8
|
import type { AuthResponse } from "./AuthResponse";
|
|
9
9
|
import { initialLocationHref } from "./initialLocationHref";
|
|
10
10
|
import { captureFetch } from "./trustedFetch";
|
|
11
|
-
import { debug966975 } from "./debug966975";
|
|
12
11
|
|
|
13
12
|
captureFetch();
|
|
14
13
|
|
|
@@ -16,19 +15,8 @@ const globalContext = {
|
|
|
16
15
|
previousCall: id<{ isHandled: boolean } | undefined>(undefined)
|
|
17
16
|
};
|
|
18
17
|
|
|
19
|
-
debug966975.log(
|
|
20
|
-
`=================== Evaluating the handleOidcCallback file, isInIframe: ${
|
|
21
|
-
window.self !== window.top ? "true" : "false"
|
|
22
|
-
}, location.href: ${initialLocationHref}`
|
|
23
|
-
);
|
|
24
|
-
|
|
25
18
|
export function handleOidcCallback(): { isHandled: boolean } {
|
|
26
19
|
if (globalContext.previousCall !== undefined) {
|
|
27
|
-
debug966975.log(
|
|
28
|
-
`handleOidcCallback() call, it has been called previously ${JSON.stringify(
|
|
29
|
-
globalContext.previousCall
|
|
30
|
-
)}`
|
|
31
|
-
);
|
|
32
20
|
return globalContext.previousCall;
|
|
33
21
|
}
|
|
34
22
|
|
|
@@ -36,20 +24,16 @@ export function handleOidcCallback(): { isHandled: boolean } {
|
|
|
36
24
|
}
|
|
37
25
|
|
|
38
26
|
function handleOidcCallback_nonMemoized(): { isHandled: boolean } {
|
|
39
|
-
debug966975.log(`In handleOidcCallback_nonMemoized()`);
|
|
40
|
-
|
|
41
27
|
const location_urlObj = new URL(initialLocationHref);
|
|
42
28
|
|
|
43
29
|
const stateQueryParamValue = (() => {
|
|
44
30
|
const stateQueryParamValue = location_urlObj.searchParams.get("state");
|
|
45
31
|
|
|
46
32
|
if (stateQueryParamValue === null) {
|
|
47
|
-
debug966975.log("No state in url");
|
|
48
33
|
return undefined;
|
|
49
34
|
}
|
|
50
35
|
|
|
51
36
|
if (!getIsStatQueryParamValue({ maybeStateQueryParamValue: stateQueryParamValue })) {
|
|
52
|
-
debug966975.log(`State query param value ${stateQueryParamValue} is malformed`);
|
|
53
37
|
return undefined;
|
|
54
38
|
}
|
|
55
39
|
|
|
@@ -58,9 +42,6 @@ function handleOidcCallback_nonMemoized(): { isHandled: boolean } {
|
|
|
58
42
|
location_urlObj.searchParams.get("response_type") !== null &&
|
|
59
43
|
location_urlObj.searchParams.get("redirect_uri") !== null
|
|
60
44
|
) {
|
|
61
|
-
debug966975.log(
|
|
62
|
-
"NOTE: We are probably in a Keycloakify theme and oidc-spa was loaded by mistake."
|
|
63
|
-
);
|
|
64
45
|
// NOTE: We are probably in a Keycloakify theme and oidc-spa was loaded by mistake.
|
|
65
46
|
return undefined;
|
|
66
47
|
}
|
|
@@ -68,13 +49,9 @@ function handleOidcCallback_nonMemoized(): { isHandled: boolean } {
|
|
|
68
49
|
return stateQueryParamValue;
|
|
69
50
|
})();
|
|
70
51
|
|
|
71
|
-
debug966975.log(`state query param value ${stateQueryParamValue ?? "undefined"}`);
|
|
72
|
-
|
|
73
52
|
if (stateQueryParamValue === undefined) {
|
|
74
53
|
const backForwardTracker = readBackForwardTracker();
|
|
75
54
|
|
|
76
|
-
debug966975.log(`backForwardTracker: ${JSON.stringify(backForwardTracker)}`);
|
|
77
|
-
|
|
78
55
|
if (backForwardTracker !== undefined) {
|
|
79
56
|
writeBackForwardTracker({
|
|
80
57
|
backForwardTracker: {
|
|
@@ -84,8 +61,6 @@ function handleOidcCallback_nonMemoized(): { isHandled: boolean } {
|
|
|
84
61
|
});
|
|
85
62
|
}
|
|
86
63
|
|
|
87
|
-
debug966975.log("returning isHandled false");
|
|
88
|
-
|
|
89
64
|
return { isHandled: false };
|
|
90
65
|
}
|
|
91
66
|
|
|
@@ -98,8 +73,6 @@ function handleOidcCallback_nonMemoized(): { isHandled: boolean } {
|
|
|
98
73
|
|
|
99
74
|
const stateData = getStateData({ stateQueryParamValue });
|
|
100
75
|
|
|
101
|
-
debug966975.log(`stateData: ${JSON.stringify(stateData)}`);
|
|
102
|
-
|
|
103
76
|
if (
|
|
104
77
|
stateData === undefined ||
|
|
105
78
|
(stateData.context === "redirect" && stateData.hasBeenProcessedByCallback)
|
|
@@ -123,8 +96,6 @@ function handleOidcCallback_nonMemoized(): { isHandled: boolean } {
|
|
|
123
96
|
}
|
|
124
97
|
})();
|
|
125
98
|
|
|
126
|
-
debug966975.log(`historyMethod: ${historyMethod}`);
|
|
127
|
-
|
|
128
99
|
writeBackForwardTracker({
|
|
129
100
|
backForwardTracker: {
|
|
130
101
|
previousHistoryMethod: historyMethod,
|
|
@@ -133,8 +104,6 @@ function handleOidcCallback_nonMemoized(): { isHandled: boolean } {
|
|
|
133
104
|
});
|
|
134
105
|
|
|
135
106
|
setTimeout(() => {
|
|
136
|
-
debug966975.log(`(callback 0) Calling window.history.${historyMethod}()`);
|
|
137
|
-
|
|
138
107
|
reloadOnBfCacheNavigation();
|
|
139
108
|
|
|
140
109
|
window.history[historyMethod]();
|
|
@@ -149,8 +118,6 @@ function handleOidcCallback_nonMemoized(): { isHandled: boolean } {
|
|
|
149
118
|
}, 350);
|
|
150
119
|
}, 0);
|
|
151
120
|
|
|
152
|
-
debug966975.log(`returning isHandled: ${isHandled ? "true" : "false"}`);
|
|
153
|
-
|
|
154
121
|
return { isHandled };
|
|
155
122
|
}
|
|
156
123
|
|
|
@@ -162,12 +129,9 @@ function handleOidcCallback_nonMemoized(): { isHandled: boolean } {
|
|
|
162
129
|
|
|
163
130
|
assert(authResponse.state !== "", "063965");
|
|
164
131
|
|
|
165
|
-
debug966975.log(`authResponse: ${JSON.stringify(authResponse)}`);
|
|
166
|
-
|
|
167
132
|
switch (stateData.context) {
|
|
168
133
|
case "iframe":
|
|
169
134
|
setTimeout(() => {
|
|
170
|
-
debug966975.log(`(callback 0) posting message to parent`);
|
|
171
135
|
parent.postMessage(authResponse, location.origin);
|
|
172
136
|
}, 0);
|
|
173
137
|
break;
|
|
@@ -187,15 +151,11 @@ function handleOidcCallback_nonMemoized(): { isHandled: boolean } {
|
|
|
187
151
|
return stateData.redirectUrl;
|
|
188
152
|
})();
|
|
189
153
|
|
|
190
|
-
debug966975.log(`(callback 0) location.href = "${href}";`);
|
|
191
|
-
|
|
192
154
|
location.href = href;
|
|
193
155
|
}, 0);
|
|
194
156
|
break;
|
|
195
157
|
}
|
|
196
158
|
|
|
197
|
-
debug966975.log(`Returning isHandled: ${isHandled ? "true" : "false"}`);
|
|
198
|
-
|
|
199
159
|
return { isHandled };
|
|
200
160
|
}
|
|
201
161
|
|
|
@@ -229,28 +189,18 @@ export function retrieveRedirectAuthResponseAndStateData(params: {
|
|
|
229
189
|
}): { authResponse: AuthResponse; stateData: StateData.Redirect } | undefined {
|
|
230
190
|
const { configId } = params;
|
|
231
191
|
|
|
232
|
-
debug966975.log(`>>> In retrieveRedirectAuthResponseAndStateData(${JSON.stringify({ configId })})`);
|
|
233
|
-
|
|
234
192
|
const authResponses = readRedirectAuthResponses();
|
|
235
193
|
|
|
236
|
-
debug966975.log(`authResponses: ${JSON.stringify(authResponses)}`);
|
|
237
|
-
|
|
238
194
|
let authResponseAndStateData:
|
|
239
195
|
| { authResponse: AuthResponse; stateData: StateData.Redirect }
|
|
240
196
|
| undefined = undefined;
|
|
241
197
|
|
|
242
198
|
for (const authResponse of [...authResponses]) {
|
|
243
|
-
debug966975.log(`authResponse: ${JSON.stringify(authResponse)}`);
|
|
244
|
-
|
|
245
199
|
const stateData = getStateData({ stateQueryParamValue: authResponse.state });
|
|
246
200
|
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
try {
|
|
250
|
-
assert(stateData !== undefined, "966975");
|
|
251
|
-
} catch {
|
|
201
|
+
if (stateData === undefined) {
|
|
202
|
+
// NOTE: We do not understand how this can happen but it can.
|
|
252
203
|
authResponses.splice(authResponses.indexOf(authResponse), 1);
|
|
253
|
-
debug966975.report();
|
|
254
204
|
continue;
|
|
255
205
|
}
|
|
256
206
|
|
|
@@ -266,12 +216,9 @@ export function retrieveRedirectAuthResponseAndStateData(params: {
|
|
|
266
216
|
}
|
|
267
217
|
|
|
268
218
|
if (authResponseAndStateData !== undefined) {
|
|
269
|
-
debug966975.log(`writeRedirectAuthResponses(${JSON.stringify({ authResponses })})`);
|
|
270
219
|
writeRedirectAuthResponses({ authResponses });
|
|
271
220
|
}
|
|
272
221
|
|
|
273
|
-
debug966975.log(`Returning ${JSON.stringify({ authResponseAndStateData })} <<<<<<<<<`);
|
|
274
|
-
|
|
275
222
|
return authResponseAndStateData;
|
|
276
223
|
}
|
|
277
224
|
|
|
@@ -51,8 +51,7 @@ export function getPrSafelyRestoredFromBfCacheAfterLoginBackNavigation() {
|
|
|
51
51
|
export function createLoginOrGoToAuthServer(params: {
|
|
52
52
|
configId: string;
|
|
53
53
|
oidcClientTsUserManager: OidcClientTsUserManager;
|
|
54
|
-
transformUrlBeforeRedirect:
|
|
55
|
-
transformUrlBeforeRedirect_next:
|
|
54
|
+
transformUrlBeforeRedirect:
|
|
56
55
|
| ((params: { authorizationUrl: string; isSilent: boolean }) => string)
|
|
57
56
|
| undefined;
|
|
58
57
|
|
|
@@ -71,7 +70,6 @@ export function createLoginOrGoToAuthServer(params: {
|
|
|
71
70
|
oidcClientTsUserManager,
|
|
72
71
|
|
|
73
72
|
transformUrlBeforeRedirect,
|
|
74
|
-
transformUrlBeforeRedirect_next,
|
|
75
73
|
getExtraQueryParams,
|
|
76
74
|
|
|
77
75
|
getExtraTokenParams,
|
|
@@ -89,7 +87,7 @@ export function createLoginOrGoToAuthServer(params: {
|
|
|
89
87
|
const {
|
|
90
88
|
redirectUrl: redirectUrl_params,
|
|
91
89
|
extraQueryParams_local,
|
|
92
|
-
transformUrlBeforeRedirect_local
|
|
90
|
+
transformUrlBeforeRedirect_local,
|
|
93
91
|
...rest
|
|
94
92
|
} = params;
|
|
95
93
|
|
|
@@ -108,6 +106,8 @@ export function createLoginOrGoToAuthServer(params: {
|
|
|
108
106
|
globalContext.evtHasLoginBeenCalled.current = true;
|
|
109
107
|
|
|
110
108
|
if (document.visibilityState !== "visible") {
|
|
109
|
+
rest.interaction === "ensure no interaction";
|
|
110
|
+
|
|
111
111
|
const dVisible = new Deferred<void>();
|
|
112
112
|
|
|
113
113
|
const onVisible = () => {
|
|
@@ -196,20 +196,19 @@ export function createLoginOrGoToAuthServer(params: {
|
|
|
196
196
|
(
|
|
197
197
|
[
|
|
198
198
|
[
|
|
199
|
-
|
|
200
|
-
|
|
199
|
+
getExtraQueryParams,
|
|
200
|
+
transformUrlBeforeRedirect === undefined
|
|
201
201
|
? undefined
|
|
202
202
|
: (url: string) =>
|
|
203
|
-
|
|
203
|
+
transformUrlBeforeRedirect({
|
|
204
204
|
isSilent,
|
|
205
205
|
authorizationUrl: url
|
|
206
206
|
})
|
|
207
207
|
],
|
|
208
|
-
[
|
|
209
|
-
[extraQueryParams_local, transformUrl]
|
|
208
|
+
[extraQueryParams_local, transformUrlBeforeRedirect_local]
|
|
210
209
|
] as const
|
|
211
|
-
).forEach(([extraQueryParamsMaybeGetter, transformUrlBeforeRedirect], i) => {
|
|
212
|
-
const url_before = i !==
|
|
210
|
+
).forEach(([extraQueryParamsMaybeGetter, transformUrlBeforeRedirect], i, arr) => {
|
|
211
|
+
const url_before = i !== arr.length - 1 ? undefined : url;
|
|
213
212
|
|
|
214
213
|
add_extra_query_params: {
|
|
215
214
|
if (extraQueryParamsMaybeGetter === undefined) {
|