@frontegg/redux-store 7.131.0-alpha.0 → 7.131.0-alpha.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/auth/ActivateAccountState/actions.js +6 -0
- package/auth/LoginState/actions/hostedLoginAuthorize.actions.js +6 -1
- package/auth/LoginState/actions/index.js +77 -36
- package/auth/MfaState/actions.js +3 -0
- package/auth/StepUpState/actions/generateStepUpSession.actions.js +5 -0
- package/auth/StepUpState/helpers.d.ts +2 -1
- package/auth/StepUpState/helpers.js +3 -2
- package/auth/TenantsState/actions.js +2 -2
- package/auth/helpers.d.ts +15 -0
- package/auth/helpers.js +60 -2
- package/index.js +1 -1
- package/node/auth/ActivateAccountState/actions.js +6 -0
- package/node/auth/LoginState/actions/hostedLoginAuthorize.actions.js +5 -0
- package/node/auth/LoginState/actions/index.js +75 -34
- package/node/auth/MfaState/actions.js +3 -0
- package/node/auth/StepUpState/actions/generateStepUpSession.actions.js +5 -0
- package/node/auth/StepUpState/helpers.js +3 -2
- package/node/auth/TenantsState/actions.js +1 -1
- package/node/auth/helpers.js +66 -2
- package/node/index.js +1 -1
- package/package.json +2 -2
|
@@ -151,6 +151,9 @@ export default ((store, api, sharedActions) => {
|
|
|
151
151
|
});
|
|
152
152
|
callback == null ? void 0 : callback(true);
|
|
153
153
|
} catch (e) {
|
|
154
|
+
if (await actions.__redirectToSsoIfRequired(e)) {
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
154
157
|
setActivateState({
|
|
155
158
|
loading: false,
|
|
156
159
|
error: errorHandler(e)
|
|
@@ -188,6 +191,9 @@ export default ((store, api, sharedActions) => {
|
|
|
188
191
|
});
|
|
189
192
|
callback == null ? void 0 : callback(true);
|
|
190
193
|
} catch (e) {
|
|
194
|
+
if (await actions.__redirectToSsoIfRequired(e)) {
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
191
197
|
setActivateState({
|
|
192
198
|
submitting: false,
|
|
193
199
|
loading: false,
|
|
@@ -3,7 +3,7 @@ import { createRandomString, generateCodeChallenge, GTMEventAction, isSsoEnforce
|
|
|
3
3
|
import { HOSTED_LOGIN_VERIFIER_KEY } from '../../../constants';
|
|
4
4
|
import { isEnforceSsoOnTenantAccessEnabled } from '@frontegg/rest-api';
|
|
5
5
|
import { getBaseNameWithoutSlashSuffix, getSearchParam, isOauthCallbackRoute, TENANT_ID_PARAM_KEY } from '../helpers';
|
|
6
|
-
import { getUri, getUrlDerivedStepUp, isSteppedUp, redirectByStepUpUrl } from '../../helpers';
|
|
6
|
+
import { getUri, getUrlDerivedStepUp, isSteppedUp, redirectByStepUpUrl, restoreTabTenantUnlessSsoCallback } from '../../helpers';
|
|
7
7
|
import { SHOULD_STEP_UP_KEY } from '../../StepUpState/consts';
|
|
8
8
|
import { FronteggNativeModule } from '../../../toolkit';
|
|
9
9
|
export default ((store, api, sharedActions) => {
|
|
@@ -15,6 +15,7 @@ export default ((store, api, sharedActions) => {
|
|
|
15
15
|
const __requestHostedLoginSilentAuthorize = async () => {
|
|
16
16
|
var _response;
|
|
17
17
|
let response;
|
|
18
|
+
restoreTabTenantUnlessSsoCallback(store);
|
|
18
19
|
if (FronteggNativeModule.isGetTokensAvailable()) {
|
|
19
20
|
const authApi = api.auth;
|
|
20
21
|
response = await refreshTokenWithRetry(async () => {
|
|
@@ -26,6 +27,10 @@ export default ((store, api, sharedActions) => {
|
|
|
26
27
|
response = await api.auth.silentOAuthRefreshTokenV2();
|
|
27
28
|
} catch (error) {
|
|
28
29
|
var _store$auth$user, _error$errorContext;
|
|
30
|
+
// the tenant requires SSO: hosted login for that tenant, not the plain one the caller falls back to
|
|
31
|
+
if (await actions.__redirectToSsoIfRequired(error)) {
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
29
34
|
const tenantId = (_store$auth$user = store.auth.user) == null ? void 0 : _store$auth$user.tenantId;
|
|
30
35
|
if (!isEnforceSsoOnTenantAccessEnabled(store.root.appName) || !isSsoEnforcementError(error) || ((_error$errorContext = error.errorContext) == null ? void 0 : _error$errorContext.ssoRequired) !== false || !tenantId) {
|
|
31
36
|
throw error;
|
|
@@ -1,21 +1,20 @@
|
|
|
1
|
-
import _extends from "@babel/runtime/helpers/esm/extends";
|
|
2
1
|
import _objectWithoutPropertiesLoose from "@babel/runtime/helpers/esm/objectWithoutPropertiesLoose";
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
import _extends from "@babel/runtime/helpers/esm/extends";
|
|
3
|
+
const _excluded = ["callback", "error"],
|
|
4
|
+
_excluded2 = ["callback"],
|
|
5
5
|
_excluded3 = ["callback"],
|
|
6
6
|
_excluded4 = ["callback"],
|
|
7
7
|
_excluded5 = ["callback"],
|
|
8
|
-
_excluded6 = ["callback"],
|
|
9
|
-
_excluded7 = ["callback"
|
|
8
|
+
_excluded6 = ["callback", "events"],
|
|
9
|
+
_excluded7 = ["callback"],
|
|
10
10
|
_excluded8 = ["callback"],
|
|
11
|
-
_excluded9 = ["
|
|
12
|
-
_excluded10 = ["
|
|
11
|
+
_excluded9 = ["user"],
|
|
12
|
+
_excluded10 = ["callback"],
|
|
13
13
|
_excluded11 = ["callback"],
|
|
14
14
|
_excluded12 = ["callback"],
|
|
15
15
|
_excluded13 = ["callback"],
|
|
16
16
|
_excluded14 = ["callback"],
|
|
17
|
-
_excluded15 = ["callback"]
|
|
18
|
-
_excluded16 = ["callback"];
|
|
17
|
+
_excluded15 = ["callback"];
|
|
19
18
|
import afterAuthNavigationActions from './afterAuthNavigation.actions';
|
|
20
19
|
import handleVerifyMFAResponseActions from './handleVerifyMFAResponse.actions';
|
|
21
20
|
import mfaRequiredStateActions from './mfaRequiredState.actions';
|
|
@@ -33,8 +32,8 @@ import { clearHostedOAuthState } from '../oauthStorage';
|
|
|
33
32
|
import { SHOULD_STEP_UP_KEY } from '../../StepUpState/consts';
|
|
34
33
|
import { FronteggNativeModule, isEntitlementsDeeplyEqual } from '../../../toolkit';
|
|
35
34
|
import { REQUEST_NAME, UserVerifiedOriginTypes } from '../../interfaces';
|
|
36
|
-
import { authStrategyLoginStepMap,
|
|
37
|
-
import { isMfaRequired, isResetPasswordRequired, setAfterAuthRedirectUrlForStepUp } from '../../helpers';
|
|
35
|
+
import { authStrategyLoginStepMap, defaultOnRedirectTo } from '../consts';
|
|
36
|
+
import { isMfaRequired, isOnAuthPageRoute, isOnOidcCallbackRoute, isResetPasswordRequired, restoreTabTenantUnlessSsoCallback, setAfterAuthRedirectUrlForStepUp } from '../../helpers';
|
|
38
37
|
import { MFAStep } from '../../MfaState/interfaces';
|
|
39
38
|
import { SamlVendors } from '../../SSOState/interfaces';
|
|
40
39
|
import { DEFAULT_RETRY_CONFIG } from '../../../constants';
|
|
@@ -48,17 +47,44 @@ export default ((store, api, sharedActions) => {
|
|
|
48
47
|
* Sends the user to log in through the tenant's SSO and back to the current page afterwards.
|
|
49
48
|
* @protected
|
|
50
49
|
*/
|
|
50
|
+
// as preLogin (takeLeading): an SSO redirect started while another is in flight is dropped; the first one leaves the
|
|
51
|
+
// page, and a second hosted one would replace the PKCE verifier the first one's callback needs
|
|
52
|
+
let ssoRedirectInFlight = false;
|
|
51
53
|
const __redirectToSsoForTenant = async ({
|
|
52
54
|
tenantId,
|
|
53
55
|
address
|
|
54
56
|
}) => {
|
|
57
|
+
if (ssoRedirectInFlight) {
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
ssoRedirectInFlight = true;
|
|
61
|
+
try {
|
|
62
|
+
await __redirectToSsoForTenantNow({
|
|
63
|
+
tenantId,
|
|
64
|
+
address
|
|
65
|
+
});
|
|
66
|
+
} finally {
|
|
67
|
+
ssoRedirectInFlight = false;
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
const __redirectToSsoForTenantNow = async ({
|
|
71
|
+
tenantId,
|
|
72
|
+
address
|
|
73
|
+
}) => {
|
|
74
|
+
var _store$root$urlStrate;
|
|
75
|
+
// the login box shows login's "redirecting to SSO" step instead of the screen that was refused (its spinner and
|
|
76
|
+
// a previous error)
|
|
77
|
+
setLoginState({
|
|
78
|
+
step: LoginStep.redirectToSSO,
|
|
79
|
+
loading: false,
|
|
80
|
+
error: undefined
|
|
81
|
+
});
|
|
55
82
|
// on an auth page (login, tenant chooser, social / magic link / SSO callback) keep the destination the login
|
|
56
83
|
// already saved: the page itself is not one to come back to
|
|
57
|
-
const
|
|
58
|
-
|
|
59
|
-
const isOnAuthPage = Object.values(authRoutes).some(route => typeof route === 'string' && !!route && window.location.pathname.endsWith(route));
|
|
84
|
+
const urlStrategy = (_store$root$urlStrate = store.root.urlStrategy) != null ? _store$root$urlStrate : 'path';
|
|
85
|
+
const isOnAuthPage = isOnAuthPageRoute(urlStrategy, store.auth.routes);
|
|
60
86
|
if (!isOnAuthPage) {
|
|
61
|
-
setAfterAuthRedirectUrlForStepUp();
|
|
87
|
+
setAfterAuthRedirectUrlForStepUp(urlStrategy);
|
|
62
88
|
}
|
|
63
89
|
if (store.auth.hostedLoginBox) {
|
|
64
90
|
var _window$localStorage;
|
|
@@ -72,9 +98,12 @@ export default ((store, api, sharedActions) => {
|
|
|
72
98
|
});
|
|
73
99
|
return;
|
|
74
100
|
}
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
101
|
+
// as login does for an OIDC SSO page without redirect_uri; the refusal has no idpType, but an OIDC page asks for a code
|
|
102
|
+
let ssoRedirectUrl = address;
|
|
103
|
+
if (/[?&]response_type=code(&|$)/.test(address) && !address.includes('redirect_uri')) {
|
|
104
|
+
ssoRedirectUrl += `&redirect_uri=${window.location.origin}${store.auth.routes.oidcRedirectUrl}`;
|
|
105
|
+
}
|
|
106
|
+
redirectToFullPage(ssoRedirectUrl);
|
|
78
107
|
};
|
|
79
108
|
|
|
80
109
|
/**
|
|
@@ -84,7 +113,8 @@ export default ((store, api, sharedActions) => {
|
|
|
84
113
|
* @protected
|
|
85
114
|
*/
|
|
86
115
|
const __redirectToSsoIfRequired = async e => {
|
|
87
|
-
|
|
116
|
+
var _e$errorContext;
|
|
117
|
+
if (!isEnforceSsoOnTenantAccessEnabled(store.root.appName) || !isSsoEnforcementError(e) || !((_e$errorContext = e.errorContext) != null && _e$errorContext.ssoRequired)) {
|
|
88
118
|
return false;
|
|
89
119
|
}
|
|
90
120
|
await __redirectToSsoForTenant(e.errorContext);
|
|
@@ -215,8 +245,9 @@ export default ((store, api, sharedActions) => {
|
|
|
215
245
|
});
|
|
216
246
|
}
|
|
217
247
|
} catch (e) {
|
|
218
|
-
// a refused identity refresh has already used up the refresh token: no retry, only the SSO redirect
|
|
219
|
-
|
|
248
|
+
// a refused identity refresh has already used up the refresh token: no retry, only the SSO redirect, except on
|
|
249
|
+
// the OIDC callback, where the page itself completes the OIDC login
|
|
250
|
+
if (isEnforceSsoOnTenantAccessEnabled(store.root.appName) && !isOnOidcCallbackRoute(store) && (await __redirectToSsoIfRequired(e))) {
|
|
220
251
|
return;
|
|
221
252
|
}
|
|
222
253
|
contextHolder.setAccessToken(null);
|
|
@@ -263,6 +294,7 @@ export default ((store, api, sharedActions) => {
|
|
|
263
294
|
|
|
264
295
|
/** @protected */
|
|
265
296
|
const __refreshToken = async () => {
|
|
297
|
+
restoreTabTenantUnlessSsoCallback(store);
|
|
266
298
|
if (FronteggNativeModule.isGetTokensAvailable()) {
|
|
267
299
|
await __refreshTokenWithNativeTokens();
|
|
268
300
|
return;
|
|
@@ -455,7 +487,7 @@ export default ((store, api, sharedActions) => {
|
|
|
455
487
|
callback,
|
|
456
488
|
error
|
|
457
489
|
} = _ref3,
|
|
458
|
-
body = _objectWithoutPropertiesLoose(_ref3,
|
|
490
|
+
body = _objectWithoutPropertiesLoose(_ref3, _excluded);
|
|
459
491
|
const publicPolicy = store.auth.securityPolicyState.publicPolicy.policy;
|
|
460
492
|
if (!(publicPolicy != null && publicPolicy.authStrategy)) {
|
|
461
493
|
actions.setLoginState({
|
|
@@ -851,7 +883,7 @@ export default ((store, api, sharedActions) => {
|
|
|
851
883
|
const {
|
|
852
884
|
callback
|
|
853
885
|
} = _payload,
|
|
854
|
-
payload = _objectWithoutPropertiesLoose(_payload,
|
|
886
|
+
payload = _objectWithoutPropertiesLoose(_payload, _excluded2);
|
|
855
887
|
try {
|
|
856
888
|
setLoginState({
|
|
857
889
|
loading: true
|
|
@@ -881,7 +913,7 @@ export default ((store, api, sharedActions) => {
|
|
|
881
913
|
const {
|
|
882
914
|
callback
|
|
883
915
|
} = _payload,
|
|
884
|
-
payload = _objectWithoutPropertiesLoose(_payload,
|
|
916
|
+
payload = _objectWithoutPropertiesLoose(_payload, _excluded3);
|
|
885
917
|
try {
|
|
886
918
|
setLoginState({
|
|
887
919
|
loading: true
|
|
@@ -906,7 +938,7 @@ export default ((store, api, sharedActions) => {
|
|
|
906
938
|
const {
|
|
907
939
|
callback
|
|
908
940
|
} = _payload,
|
|
909
|
-
payload = _objectWithoutPropertiesLoose(_payload,
|
|
941
|
+
payload = _objectWithoutPropertiesLoose(_payload, _excluded4);
|
|
910
942
|
try {
|
|
911
943
|
setLoginState({
|
|
912
944
|
loading: true
|
|
@@ -927,7 +959,7 @@ export default ((store, api, sharedActions) => {
|
|
|
927
959
|
const {
|
|
928
960
|
callback
|
|
929
961
|
} = _payload,
|
|
930
|
-
payload = _objectWithoutPropertiesLoose(_payload,
|
|
962
|
+
payload = _objectWithoutPropertiesLoose(_payload, _excluded5);
|
|
931
963
|
try {
|
|
932
964
|
var _username;
|
|
933
965
|
setLoginState({
|
|
@@ -971,7 +1003,7 @@ export default ((store, api, sharedActions) => {
|
|
|
971
1003
|
callback,
|
|
972
1004
|
events
|
|
973
1005
|
} = _payload,
|
|
974
|
-
payload = _objectWithoutPropertiesLoose(_payload,
|
|
1006
|
+
payload = _objectWithoutPropertiesLoose(_payload, _excluded6);
|
|
975
1007
|
try {
|
|
976
1008
|
setLoginState({
|
|
977
1009
|
loading: true
|
|
@@ -1102,7 +1134,7 @@ export default ((store, api, sharedActions) => {
|
|
|
1102
1134
|
const {
|
|
1103
1135
|
callback
|
|
1104
1136
|
} = payload,
|
|
1105
|
-
body = _objectWithoutPropertiesLoose(payload,
|
|
1137
|
+
body = _objectWithoutPropertiesLoose(payload, _excluded7);
|
|
1106
1138
|
try {
|
|
1107
1139
|
var _options$allowCredent;
|
|
1108
1140
|
actions.setPasskeysState({
|
|
@@ -1142,7 +1174,7 @@ export default ((store, api, sharedActions) => {
|
|
|
1142
1174
|
const {
|
|
1143
1175
|
callback
|
|
1144
1176
|
} = payload,
|
|
1145
|
-
body = _objectWithoutPropertiesLoose(payload,
|
|
1177
|
+
body = _objectWithoutPropertiesLoose(payload, _excluded8);
|
|
1146
1178
|
try {
|
|
1147
1179
|
var _publicKey$response$u;
|
|
1148
1180
|
actions.setPasskeysState({
|
|
@@ -1162,7 +1194,7 @@ export default ((store, api, sharedActions) => {
|
|
|
1162
1194
|
{
|
|
1163
1195
|
user
|
|
1164
1196
|
} = _await$api$auth$webAu,
|
|
1165
|
-
rest = _objectWithoutPropertiesLoose(_await$api$auth$webAu,
|
|
1197
|
+
rest = _objectWithoutPropertiesLoose(_await$api$auth$webAu, _excluded9);
|
|
1166
1198
|
if (isMfaRequired(user, store.root.appName)) {
|
|
1167
1199
|
const {
|
|
1168
1200
|
routes,
|
|
@@ -1249,7 +1281,7 @@ export default ((store, api, sharedActions) => {
|
|
|
1249
1281
|
const {
|
|
1250
1282
|
callback
|
|
1251
1283
|
} = payload,
|
|
1252
|
-
body = _objectWithoutPropertiesLoose(payload,
|
|
1284
|
+
body = _objectWithoutPropertiesLoose(payload, _excluded10);
|
|
1253
1285
|
try {
|
|
1254
1286
|
setLoginState({
|
|
1255
1287
|
loading: true
|
|
@@ -1314,7 +1346,7 @@ export default ((store, api, sharedActions) => {
|
|
|
1314
1346
|
const {
|
|
1315
1347
|
callback
|
|
1316
1348
|
} = _payload,
|
|
1317
|
-
payload = _objectWithoutPropertiesLoose(_payload,
|
|
1349
|
+
payload = _objectWithoutPropertiesLoose(_payload, _excluded11);
|
|
1318
1350
|
setLoginState({
|
|
1319
1351
|
loading: true
|
|
1320
1352
|
});
|
|
@@ -1349,7 +1381,7 @@ export default ((store, api, sharedActions) => {
|
|
|
1349
1381
|
const {
|
|
1350
1382
|
callback
|
|
1351
1383
|
} = _payload,
|
|
1352
|
-
payload = _objectWithoutPropertiesLoose(_payload,
|
|
1384
|
+
payload = _objectWithoutPropertiesLoose(_payload, _excluded12);
|
|
1353
1385
|
setLoginState({
|
|
1354
1386
|
loading: true
|
|
1355
1387
|
});
|
|
@@ -1364,6 +1396,9 @@ export default ((store, api, sharedActions) => {
|
|
|
1364
1396
|
});
|
|
1365
1397
|
callback == null ? void 0 : callback(true);
|
|
1366
1398
|
} catch (e) {
|
|
1399
|
+
if (await __redirectToSsoIfRequired(e)) {
|
|
1400
|
+
return;
|
|
1401
|
+
}
|
|
1367
1402
|
setLoginState({
|
|
1368
1403
|
loading: false,
|
|
1369
1404
|
error: errorHandler(e)
|
|
@@ -1375,7 +1410,7 @@ export default ((store, api, sharedActions) => {
|
|
|
1375
1410
|
const {
|
|
1376
1411
|
callback
|
|
1377
1412
|
} = _payload,
|
|
1378
|
-
payload = _objectWithoutPropertiesLoose(_payload,
|
|
1413
|
+
payload = _objectWithoutPropertiesLoose(_payload, _excluded13);
|
|
1379
1414
|
setLoginState({
|
|
1380
1415
|
loading: true
|
|
1381
1416
|
});
|
|
@@ -1387,6 +1422,9 @@ export default ((store, api, sharedActions) => {
|
|
|
1387
1422
|
});
|
|
1388
1423
|
callback == null ? void 0 : callback(true);
|
|
1389
1424
|
} catch (e) {
|
|
1425
|
+
if (await __redirectToSsoIfRequired(e)) {
|
|
1426
|
+
return;
|
|
1427
|
+
}
|
|
1390
1428
|
setLoginState({
|
|
1391
1429
|
loading: false,
|
|
1392
1430
|
error: errorHandler(e)
|
|
@@ -1398,7 +1436,7 @@ export default ((store, api, sharedActions) => {
|
|
|
1398
1436
|
const {
|
|
1399
1437
|
callback
|
|
1400
1438
|
} = _payload,
|
|
1401
|
-
payload = _objectWithoutPropertiesLoose(_payload,
|
|
1439
|
+
payload = _objectWithoutPropertiesLoose(_payload, _excluded14);
|
|
1402
1440
|
setLoginState({
|
|
1403
1441
|
loading: true
|
|
1404
1442
|
});
|
|
@@ -1425,7 +1463,7 @@ export default ((store, api, sharedActions) => {
|
|
|
1425
1463
|
const {
|
|
1426
1464
|
callback
|
|
1427
1465
|
} = _payload,
|
|
1428
|
-
payload = _objectWithoutPropertiesLoose(_payload,
|
|
1466
|
+
payload = _objectWithoutPropertiesLoose(_payload, _excluded15);
|
|
1429
1467
|
setLoginState({
|
|
1430
1468
|
loading: true
|
|
1431
1469
|
});
|
|
@@ -1437,6 +1475,9 @@ export default ((store, api, sharedActions) => {
|
|
|
1437
1475
|
});
|
|
1438
1476
|
callback == null ? void 0 : callback(true);
|
|
1439
1477
|
} catch (e) {
|
|
1478
|
+
if (await __redirectToSsoIfRequired(e)) {
|
|
1479
|
+
return;
|
|
1480
|
+
}
|
|
1440
1481
|
setLoginState({
|
|
1441
1482
|
loading: false,
|
|
1442
1483
|
error: errorHandler(e)
|
package/auth/MfaState/actions.js
CHANGED
|
@@ -169,6 +169,9 @@ export default ((store, api, sharedActions) => {
|
|
|
169
169
|
}
|
|
170
170
|
callback == null ? void 0 : callback(mfaState.recoveryCode);
|
|
171
171
|
} catch (e) {
|
|
172
|
+
if (await actions.__redirectToSsoIfRequired(e)) {
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
172
175
|
setMfaState({
|
|
173
176
|
loading: false,
|
|
174
177
|
error: errorHandler(e)
|
|
@@ -95,6 +95,11 @@ export default ((store, api, sharedActions) => {
|
|
|
95
95
|
callback == null ? void 0 : callback(true);
|
|
96
96
|
} catch (e) {
|
|
97
97
|
callback == null ? void 0 : callback(false);
|
|
98
|
+
|
|
99
|
+
// the session's tenant requires SSO: its SSO login steps the user up, instead of logging them out
|
|
100
|
+
if (await actions.__redirectToSsoIfRequired(e)) {
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
98
103
|
await __handleStepUpError(e);
|
|
99
104
|
}
|
|
100
105
|
};
|
|
@@ -22,8 +22,9 @@ export interface UrlDerivedStepUp {
|
|
|
22
22
|
export declare const getUrlDerivedStepUp: () => UrlDerivedStepUp;
|
|
23
23
|
/**
|
|
24
24
|
* Set the url and query params in the local storage FRONTEGG_AFTER_AUTH_REDIRECT_URL value
|
|
25
|
+
* @param urlStrategy 'hash' saves the route in the hash, which is the page the app shows
|
|
25
26
|
*/
|
|
26
|
-
export declare function setAfterAuthRedirectUrlForStepUp(): void;
|
|
27
|
+
export declare function setAfterAuthRedirectUrlForStepUp(urlStrategy?: 'path' | 'hash'): void;
|
|
27
28
|
/**
|
|
28
29
|
* Redirects to the step up url with the max age param and set the redirect url in the local storage
|
|
29
30
|
* The redirect url will be used after the step up flow is done
|
|
@@ -51,9 +51,10 @@ export const getUrlDerivedStepUp = () => {
|
|
|
51
51
|
|
|
52
52
|
/**
|
|
53
53
|
* Set the url and query params in the local storage FRONTEGG_AFTER_AUTH_REDIRECT_URL value
|
|
54
|
+
* @param urlStrategy 'hash' saves the route in the hash, which is the page the app shows
|
|
54
55
|
*/
|
|
55
|
-
export function setAfterAuthRedirectUrlForStepUp() {
|
|
56
|
-
const encodedRedirectUrl = window.location.pathname + window.location.search;
|
|
56
|
+
export function setAfterAuthRedirectUrlForStepUp(urlStrategy = 'path') {
|
|
57
|
+
const encodedRedirectUrl = urlStrategy === 'hash' ? window.location.hash.substring(1) || '/' : window.location.pathname + window.location.search;
|
|
57
58
|
window.localStorage.setItem(FRONTEGG_AFTER_AUTH_REDIRECT_URL, encodedRedirectUrl);
|
|
58
59
|
}
|
|
59
60
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { initialState } from './state';
|
|
2
2
|
import { deepResetState } from '../../helpers';
|
|
3
|
-
import { ContextHolder, getCurrentUserTenantsFunction,
|
|
3
|
+
import { ContextHolder, getCurrentUserTenantsFunction, setTabTenantForSsoSwitch } from '@frontegg/rest-api';
|
|
4
4
|
export default ((store, api, sharedActions) => {
|
|
5
5
|
const actions = sharedActions;
|
|
6
6
|
const setTenantsState = state => {
|
|
@@ -54,7 +54,7 @@ export default ((store, api, sharedActions) => {
|
|
|
54
54
|
if (await actions.__redirectToSsoIfRequired(e)) {
|
|
55
55
|
// the tab comes back from SSO in the target tenant, not the one the failed switch restored
|
|
56
56
|
if (ContextHolder.for(store.root.appName).isSessionPerTenantEnabled()) {
|
|
57
|
-
|
|
57
|
+
setTabTenantForSsoSwitch(tenantId);
|
|
58
58
|
}
|
|
59
59
|
return;
|
|
60
60
|
}
|
package/auth/helpers.d.ts
CHANGED
|
@@ -8,5 +8,20 @@ export declare const isMfaRequired: (user: ILoginResponse, appName: string) => b
|
|
|
8
8
|
export declare const isResetPasswordRequired: (user: ILoginResponse, appName: string) => boolean;
|
|
9
9
|
export declare const mapMetaDataObjectToActions: (obj: any, path?: string[]) => CommitChangeDto[];
|
|
10
10
|
export declare const getUri: (urlStrategy: FronteggState["root"]["urlStrategy"]) => string;
|
|
11
|
+
/**
|
|
12
|
+
* On the OIDC callback the page still has to finish the OIDC login with its code: a refresh refused before that is not
|
|
13
|
+
* a reason to go back to the IdP, which would send the user straight back here, forever.
|
|
14
|
+
*/
|
|
15
|
+
export declare const isOnOidcCallbackRoute: (store: FronteggState) => boolean;
|
|
16
|
+
/**
|
|
17
|
+
* After a switch refused for SSO the tab points at the SSO tenant. Its SSO login comes back on a callback route and
|
|
18
|
+
* keeps it; any other page load means the user didn't finish that login, so the tab goes back to its tenant.
|
|
19
|
+
*/
|
|
20
|
+
export declare const restoreTabTenantUnlessSsoCallback: (store: FronteggState) => void;
|
|
11
21
|
export declare const prepareIdentifiersForSignup: (payload: ISignUpUser) => ISignUpUser;
|
|
22
|
+
/**
|
|
23
|
+
* Whether the current route is an auth page (login, tenant chooser, social / magic link / SSO callback), not one to come
|
|
24
|
+
* back to. Unlike isAuthRoute: after-login / sign-up destinations don't count, and endsWith lets a basename prefix it.
|
|
25
|
+
*/
|
|
26
|
+
export declare const isOnAuthPageRoute: (urlStrategy: FronteggState["root"]["urlStrategy"], routes?: Partial<AuthPageRoutes>) => boolean;
|
|
12
27
|
export declare const isAuthRoute: (path: string, routes?: Partial<AuthPageRoutes>) => boolean;
|
package/auth/helpers.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import _extends from "@babel/runtime/helpers/esm/extends";
|
|
2
1
|
import _objectWithoutPropertiesLoose from "@babel/runtime/helpers/esm/objectWithoutPropertiesLoose";
|
|
2
|
+
import _extends from "@babel/runtime/helpers/esm/extends";
|
|
3
3
|
const _excluded = ["phoneNumber", "email", "username"],
|
|
4
4
|
_excluded2 = ["authenticatedUrl"];
|
|
5
|
-
import { ContextHolder } from '@frontegg/rest-api';
|
|
5
|
+
import { ContextHolder, restoreTabTenantBeforeSsoSwitch, isEnforceSsoOnTenantAccessEnabled } from '@frontegg/rest-api';
|
|
6
6
|
import { defaultFronteggRoutes } from './LoginState/consts';
|
|
7
7
|
export * from './Entitlements/helpers';
|
|
8
8
|
export * from './LoginState/helpers';
|
|
@@ -53,6 +53,52 @@ export const getUri = urlStrategy => {
|
|
|
53
53
|
}
|
|
54
54
|
}
|
|
55
55
|
};
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* The route the app shows and the page's path. With hash routing they differ: the app's pages live in the hash, but
|
|
59
|
+
* SAML, OIDC, social and magic link callbacks come back on the path, which is where login matches them.
|
|
60
|
+
*/
|
|
61
|
+
const getCurrentRoutes = urlStrategy => {
|
|
62
|
+
const hashOrPathRoute = getUri(urlStrategy);
|
|
63
|
+
const {
|
|
64
|
+
pathname
|
|
65
|
+
} = window.location;
|
|
66
|
+
return hashOrPathRoute === pathname ? [pathname] : [hashOrPathRoute, pathname];
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* On the OIDC callback the page still has to finish the OIDC login with its code: a refresh refused before that is not
|
|
71
|
+
* a reason to go back to the IdP, which would send the user straight back here, forever.
|
|
72
|
+
*/
|
|
73
|
+
export const isOnOidcCallbackRoute = store => {
|
|
74
|
+
var _store$root$urlStrate;
|
|
75
|
+
const {
|
|
76
|
+
oidcRedirectUrl
|
|
77
|
+
} = _extends({}, defaultFronteggRoutes, store.auth.routes);
|
|
78
|
+
return !!oidcRedirectUrl && getCurrentRoutes((_store$root$urlStrate = store.root.urlStrategy) != null ? _store$root$urlStrate : 'path').some(currentRoute => currentRoute.endsWith(oidcRedirectUrl));
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* After a switch refused for SSO the tab points at the SSO tenant. Its SSO login comes back on a callback route and
|
|
83
|
+
* keeps it; any other page load means the user didn't finish that login, so the tab goes back to its tenant.
|
|
84
|
+
*/
|
|
85
|
+
export const restoreTabTenantUnlessSsoCallback = store => {
|
|
86
|
+
var _store$root$urlStrate2;
|
|
87
|
+
if (!isEnforceSsoOnTenantAccessEnabled(store.root.appName) || !ContextHolder.for(store.root.appName).isSessionPerTenantEnabled()) {
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
const {
|
|
91
|
+
samlCallbackUrl,
|
|
92
|
+
oidcRedirectUrl,
|
|
93
|
+
hostedLoginRedirectUrl
|
|
94
|
+
} = _extends({}, defaultFronteggRoutes, store.auth.routes);
|
|
95
|
+
// matched like login matches its callback pages: endsWith, so a basename before the route still counts
|
|
96
|
+
const currentRoutes = getCurrentRoutes((_store$root$urlStrate2 = store.root.urlStrategy) != null ? _store$root$urlStrate2 : 'path');
|
|
97
|
+
const isSsoCallback = [samlCallbackUrl, oidcRedirectUrl, hostedLoginRedirectUrl].some(route => !!route && currentRoutes.some(currentRoute => currentRoute.endsWith(route)));
|
|
98
|
+
if (!isSsoCallback) {
|
|
99
|
+
restoreTabTenantBeforeSsoSwitch();
|
|
100
|
+
}
|
|
101
|
+
};
|
|
56
102
|
export const prepareIdentifiersForSignup = payload => {
|
|
57
103
|
const {
|
|
58
104
|
phoneNumber,
|
|
@@ -77,6 +123,18 @@ export const prepareIdentifiersForSignup = payload => {
|
|
|
77
123
|
}
|
|
78
124
|
return finalDto;
|
|
79
125
|
};
|
|
126
|
+
|
|
127
|
+
// Pages the user lands on after login or sign-up: destinations, not auth pages.
|
|
128
|
+
const AFTER_AUTH_DESTINATION_ROUTES = ['authenticatedUrl', 'signUpSuccessUrl', 'accountSignUpSuccessUrl', 'userSignUpSuccessUrl', 'customLoginAuthenticatedUrl'];
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Whether the current route is an auth page (login, tenant chooser, social / magic link / SSO callback), not one to come
|
|
132
|
+
* back to. Unlike isAuthRoute: after-login / sign-up destinations don't count, and endsWith lets a basename prefix it.
|
|
133
|
+
*/
|
|
134
|
+
export const isOnAuthPageRoute = (urlStrategy, routes) => {
|
|
135
|
+
const currentRoutes = getCurrentRoutes(urlStrategy);
|
|
136
|
+
return Object.entries(_extends({}, defaultFronteggRoutes, routes)).some(([name, route]) => !AFTER_AUTH_DESTINATION_ROUTES.includes(name) && typeof route === 'string' && !!route && currentRoutes.some(currentRoute => currentRoute.endsWith(route)));
|
|
137
|
+
};
|
|
80
138
|
export const isAuthRoute = (path, routes) => {
|
|
81
139
|
const _defaultFronteggRoute = _extends({}, defaultFronteggRoutes, routes),
|
|
82
140
|
authRoutes = _objectWithoutPropertiesLoose(_defaultFronteggRoute, _excluded2);
|
package/index.js
CHANGED
|
@@ -158,6 +158,9 @@ var _default = (store, api, sharedActions) => {
|
|
|
158
158
|
});
|
|
159
159
|
callback == null ? void 0 : callback(true);
|
|
160
160
|
} catch (e) {
|
|
161
|
+
if (await actions.__redirectToSsoIfRequired(e)) {
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
161
164
|
setActivateState({
|
|
162
165
|
loading: false,
|
|
163
166
|
error: (0, _helpers.errorHandler)(e)
|
|
@@ -195,6 +198,9 @@ var _default = (store, api, sharedActions) => {
|
|
|
195
198
|
});
|
|
196
199
|
callback == null ? void 0 : callback(true);
|
|
197
200
|
} catch (e) {
|
|
201
|
+
if (await actions.__redirectToSsoIfRequired(e)) {
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
198
204
|
setActivateState({
|
|
199
205
|
submitting: false,
|
|
200
206
|
loading: false,
|
|
@@ -22,6 +22,7 @@ var _default = (store, api, sharedActions) => {
|
|
|
22
22
|
const __requestHostedLoginSilentAuthorize = async () => {
|
|
23
23
|
var _response;
|
|
24
24
|
let response;
|
|
25
|
+
(0, _helpers3.restoreTabTenantUnlessSsoCallback)(store);
|
|
25
26
|
if (_toolkit.FronteggNativeModule.isGetTokensAvailable()) {
|
|
26
27
|
const authApi = api.auth;
|
|
27
28
|
response = await (0, _helpers.refreshTokenWithRetry)(async () => {
|
|
@@ -33,6 +34,10 @@ var _default = (store, api, sharedActions) => {
|
|
|
33
34
|
response = await api.auth.silentOAuthRefreshTokenV2();
|
|
34
35
|
} catch (error) {
|
|
35
36
|
var _store$auth$user, _error$errorContext;
|
|
37
|
+
// the tenant requires SSO: hosted login for that tenant, not the plain one the caller falls back to
|
|
38
|
+
if (await actions.__redirectToSsoIfRequired(error)) {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
36
41
|
const tenantId = (_store$auth$user = store.auth.user) == null ? void 0 : _store$auth$user.tenantId;
|
|
37
42
|
if (!(0, _restApi.isEnforceSsoOnTenantAccessEnabled)(store.root.appName) || !(0, _helpers.isSsoEnforcementError)(error) || ((_error$errorContext = error.errorContext) == null ? void 0 : _error$errorContext.ssoRequired) !== false || !tenantId) {
|
|
38
43
|
throw error;
|
|
@@ -5,8 +5,8 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
value: true
|
|
6
6
|
});
|
|
7
7
|
exports.default = void 0;
|
|
8
|
-
var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
|
|
9
8
|
var _objectWithoutPropertiesLoose2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutPropertiesLoose"));
|
|
9
|
+
var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
|
|
10
10
|
var _afterAuthNavigation = _interopRequireDefault(require("./afterAuthNavigation.actions"));
|
|
11
11
|
var _handleVerifyMFAResponse = _interopRequireDefault(require("./handleVerifyMFAResponse.actions"));
|
|
12
12
|
var _mfaRequiredState = _interopRequireDefault(require("./mfaRequiredState.actions"));
|
|
@@ -29,22 +29,21 @@ var _helpers3 = require("../../helpers");
|
|
|
29
29
|
var _interfaces3 = require("../../MfaState/interfaces");
|
|
30
30
|
var _interfaces4 = require("../../SSOState/interfaces");
|
|
31
31
|
var _constants = require("../../../constants");
|
|
32
|
-
const _excluded = ["
|
|
33
|
-
_excluded2 = ["callback"
|
|
32
|
+
const _excluded = ["callback", "error"],
|
|
33
|
+
_excluded2 = ["callback"],
|
|
34
34
|
_excluded3 = ["callback"],
|
|
35
35
|
_excluded4 = ["callback"],
|
|
36
36
|
_excluded5 = ["callback"],
|
|
37
|
-
_excluded6 = ["callback"],
|
|
38
|
-
_excluded7 = ["callback"
|
|
37
|
+
_excluded6 = ["callback", "events"],
|
|
38
|
+
_excluded7 = ["callback"],
|
|
39
39
|
_excluded8 = ["callback"],
|
|
40
|
-
_excluded9 = ["
|
|
41
|
-
_excluded10 = ["
|
|
40
|
+
_excluded9 = ["user"],
|
|
41
|
+
_excluded10 = ["callback"],
|
|
42
42
|
_excluded11 = ["callback"],
|
|
43
43
|
_excluded12 = ["callback"],
|
|
44
44
|
_excluded13 = ["callback"],
|
|
45
45
|
_excluded14 = ["callback"],
|
|
46
|
-
_excluded15 = ["callback"]
|
|
47
|
-
_excluded16 = ["callback"];
|
|
46
|
+
_excluded15 = ["callback"];
|
|
48
47
|
const SSO_REDIRECT_DELAY_MS = 2000;
|
|
49
48
|
const isUsableRedirect = onRedirectTo => typeof onRedirectTo === 'function' && onRedirectTo !== _consts2.defaultOnRedirectTo;
|
|
50
49
|
var _default = (store, api, sharedActions) => {
|
|
@@ -55,17 +54,44 @@ var _default = (store, api, sharedActions) => {
|
|
|
55
54
|
* Sends the user to log in through the tenant's SSO and back to the current page afterwards.
|
|
56
55
|
* @protected
|
|
57
56
|
*/
|
|
57
|
+
// as preLogin (takeLeading): an SSO redirect started while another is in flight is dropped; the first one leaves the
|
|
58
|
+
// page, and a second hosted one would replace the PKCE verifier the first one's callback needs
|
|
59
|
+
let ssoRedirectInFlight = false;
|
|
58
60
|
const __redirectToSsoForTenant = async ({
|
|
59
61
|
tenantId,
|
|
60
62
|
address
|
|
61
63
|
}) => {
|
|
64
|
+
if (ssoRedirectInFlight) {
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
ssoRedirectInFlight = true;
|
|
68
|
+
try {
|
|
69
|
+
await __redirectToSsoForTenantNow({
|
|
70
|
+
tenantId,
|
|
71
|
+
address
|
|
72
|
+
});
|
|
73
|
+
} finally {
|
|
74
|
+
ssoRedirectInFlight = false;
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
const __redirectToSsoForTenantNow = async ({
|
|
78
|
+
tenantId,
|
|
79
|
+
address
|
|
80
|
+
}) => {
|
|
81
|
+
var _store$root$urlStrate;
|
|
82
|
+
// the login box shows login's "redirecting to SSO" step instead of the screen that was refused (its spinner and
|
|
83
|
+
// a previous error)
|
|
84
|
+
setLoginState({
|
|
85
|
+
step: _interfaces.LoginStep.redirectToSSO,
|
|
86
|
+
loading: false,
|
|
87
|
+
error: undefined
|
|
88
|
+
});
|
|
62
89
|
// on an auth page (login, tenant chooser, social / magic link / SSO callback) keep the destination the login
|
|
63
90
|
// already saved: the page itself is not one to come back to
|
|
64
|
-
const
|
|
65
|
-
|
|
66
|
-
const isOnAuthPage = Object.values(authRoutes).some(route => typeof route === 'string' && !!route && window.location.pathname.endsWith(route));
|
|
91
|
+
const urlStrategy = (_store$root$urlStrate = store.root.urlStrategy) != null ? _store$root$urlStrate : 'path';
|
|
92
|
+
const isOnAuthPage = (0, _helpers3.isOnAuthPageRoute)(urlStrategy, store.auth.routes);
|
|
67
93
|
if (!isOnAuthPage) {
|
|
68
|
-
(0, _helpers3.setAfterAuthRedirectUrlForStepUp)();
|
|
94
|
+
(0, _helpers3.setAfterAuthRedirectUrlForStepUp)(urlStrategy);
|
|
69
95
|
}
|
|
70
96
|
if (store.auth.hostedLoginBox) {
|
|
71
97
|
var _window$localStorage;
|
|
@@ -79,9 +105,12 @@ var _default = (store, api, sharedActions) => {
|
|
|
79
105
|
});
|
|
80
106
|
return;
|
|
81
107
|
}
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
108
|
+
// as login does for an OIDC SSO page without redirect_uri; the refusal has no idpType, but an OIDC page asks for a code
|
|
109
|
+
let ssoRedirectUrl = address;
|
|
110
|
+
if (/[?&]response_type=code(&|$)/.test(address) && !address.includes('redirect_uri')) {
|
|
111
|
+
ssoRedirectUrl += `&redirect_uri=${window.location.origin}${store.auth.routes.oidcRedirectUrl}`;
|
|
112
|
+
}
|
|
113
|
+
redirectToFullPage(ssoRedirectUrl);
|
|
85
114
|
};
|
|
86
115
|
|
|
87
116
|
/**
|
|
@@ -91,7 +120,8 @@ var _default = (store, api, sharedActions) => {
|
|
|
91
120
|
* @protected
|
|
92
121
|
*/
|
|
93
122
|
const __redirectToSsoIfRequired = async e => {
|
|
94
|
-
|
|
123
|
+
var _e$errorContext;
|
|
124
|
+
if (!(0, _restApi.isEnforceSsoOnTenantAccessEnabled)(store.root.appName) || !(0, _helpers.isSsoEnforcementError)(e) || !((_e$errorContext = e.errorContext) != null && _e$errorContext.ssoRequired)) {
|
|
95
125
|
return false;
|
|
96
126
|
}
|
|
97
127
|
await __redirectToSsoForTenant(e.errorContext);
|
|
@@ -222,8 +252,9 @@ var _default = (store, api, sharedActions) => {
|
|
|
222
252
|
});
|
|
223
253
|
}
|
|
224
254
|
} catch (e) {
|
|
225
|
-
// a refused identity refresh has already used up the refresh token: no retry, only the SSO redirect
|
|
226
|
-
|
|
255
|
+
// a refused identity refresh has already used up the refresh token: no retry, only the SSO redirect, except on
|
|
256
|
+
// the OIDC callback, where the page itself completes the OIDC login
|
|
257
|
+
if ((0, _restApi.isEnforceSsoOnTenantAccessEnabled)(store.root.appName) && !(0, _helpers3.isOnOidcCallbackRoute)(store) && (await __redirectToSsoIfRequired(e))) {
|
|
227
258
|
return;
|
|
228
259
|
}
|
|
229
260
|
contextHolder.setAccessToken(null);
|
|
@@ -270,6 +301,7 @@ var _default = (store, api, sharedActions) => {
|
|
|
270
301
|
|
|
271
302
|
/** @protected */
|
|
272
303
|
const __refreshToken = async () => {
|
|
304
|
+
(0, _helpers3.restoreTabTenantUnlessSsoCallback)(store);
|
|
273
305
|
if (_toolkit.FronteggNativeModule.isGetTokensAvailable()) {
|
|
274
306
|
await __refreshTokenWithNativeTokens();
|
|
275
307
|
return;
|
|
@@ -462,7 +494,7 @@ var _default = (store, api, sharedActions) => {
|
|
|
462
494
|
callback,
|
|
463
495
|
error
|
|
464
496
|
} = _ref3,
|
|
465
|
-
body = (0, _objectWithoutPropertiesLoose2.default)(_ref3,
|
|
497
|
+
body = (0, _objectWithoutPropertiesLoose2.default)(_ref3, _excluded);
|
|
466
498
|
const publicPolicy = store.auth.securityPolicyState.publicPolicy.policy;
|
|
467
499
|
if (!(publicPolicy != null && publicPolicy.authStrategy)) {
|
|
468
500
|
actions.setLoginState({
|
|
@@ -858,7 +890,7 @@ var _default = (store, api, sharedActions) => {
|
|
|
858
890
|
const {
|
|
859
891
|
callback
|
|
860
892
|
} = _payload,
|
|
861
|
-
payload = (0, _objectWithoutPropertiesLoose2.default)(_payload,
|
|
893
|
+
payload = (0, _objectWithoutPropertiesLoose2.default)(_payload, _excluded2);
|
|
862
894
|
try {
|
|
863
895
|
setLoginState({
|
|
864
896
|
loading: true
|
|
@@ -888,7 +920,7 @@ var _default = (store, api, sharedActions) => {
|
|
|
888
920
|
const {
|
|
889
921
|
callback
|
|
890
922
|
} = _payload,
|
|
891
|
-
payload = (0, _objectWithoutPropertiesLoose2.default)(_payload,
|
|
923
|
+
payload = (0, _objectWithoutPropertiesLoose2.default)(_payload, _excluded3);
|
|
892
924
|
try {
|
|
893
925
|
setLoginState({
|
|
894
926
|
loading: true
|
|
@@ -913,7 +945,7 @@ var _default = (store, api, sharedActions) => {
|
|
|
913
945
|
const {
|
|
914
946
|
callback
|
|
915
947
|
} = _payload,
|
|
916
|
-
payload = (0, _objectWithoutPropertiesLoose2.default)(_payload,
|
|
948
|
+
payload = (0, _objectWithoutPropertiesLoose2.default)(_payload, _excluded4);
|
|
917
949
|
try {
|
|
918
950
|
setLoginState({
|
|
919
951
|
loading: true
|
|
@@ -934,7 +966,7 @@ var _default = (store, api, sharedActions) => {
|
|
|
934
966
|
const {
|
|
935
967
|
callback
|
|
936
968
|
} = _payload,
|
|
937
|
-
payload = (0, _objectWithoutPropertiesLoose2.default)(_payload,
|
|
969
|
+
payload = (0, _objectWithoutPropertiesLoose2.default)(_payload, _excluded5);
|
|
938
970
|
try {
|
|
939
971
|
var _username;
|
|
940
972
|
setLoginState({
|
|
@@ -978,7 +1010,7 @@ var _default = (store, api, sharedActions) => {
|
|
|
978
1010
|
callback,
|
|
979
1011
|
events
|
|
980
1012
|
} = _payload,
|
|
981
|
-
payload = (0, _objectWithoutPropertiesLoose2.default)(_payload,
|
|
1013
|
+
payload = (0, _objectWithoutPropertiesLoose2.default)(_payload, _excluded6);
|
|
982
1014
|
try {
|
|
983
1015
|
setLoginState({
|
|
984
1016
|
loading: true
|
|
@@ -1109,7 +1141,7 @@ var _default = (store, api, sharedActions) => {
|
|
|
1109
1141
|
const {
|
|
1110
1142
|
callback
|
|
1111
1143
|
} = payload,
|
|
1112
|
-
body = (0, _objectWithoutPropertiesLoose2.default)(payload,
|
|
1144
|
+
body = (0, _objectWithoutPropertiesLoose2.default)(payload, _excluded7);
|
|
1113
1145
|
try {
|
|
1114
1146
|
var _options$allowCredent;
|
|
1115
1147
|
actions.setPasskeysState({
|
|
@@ -1149,7 +1181,7 @@ var _default = (store, api, sharedActions) => {
|
|
|
1149
1181
|
const {
|
|
1150
1182
|
callback
|
|
1151
1183
|
} = payload,
|
|
1152
|
-
body = (0, _objectWithoutPropertiesLoose2.default)(payload,
|
|
1184
|
+
body = (0, _objectWithoutPropertiesLoose2.default)(payload, _excluded8);
|
|
1153
1185
|
try {
|
|
1154
1186
|
var _publicKey$response$u;
|
|
1155
1187
|
actions.setPasskeysState({
|
|
@@ -1169,7 +1201,7 @@ var _default = (store, api, sharedActions) => {
|
|
|
1169
1201
|
{
|
|
1170
1202
|
user
|
|
1171
1203
|
} = _await$api$auth$webAu,
|
|
1172
|
-
rest = (0, _objectWithoutPropertiesLoose2.default)(_await$api$auth$webAu,
|
|
1204
|
+
rest = (0, _objectWithoutPropertiesLoose2.default)(_await$api$auth$webAu, _excluded9);
|
|
1173
1205
|
if ((0, _helpers3.isMfaRequired)(user, store.root.appName)) {
|
|
1174
1206
|
const {
|
|
1175
1207
|
routes,
|
|
@@ -1256,7 +1288,7 @@ var _default = (store, api, sharedActions) => {
|
|
|
1256
1288
|
const {
|
|
1257
1289
|
callback
|
|
1258
1290
|
} = payload,
|
|
1259
|
-
body = (0, _objectWithoutPropertiesLoose2.default)(payload,
|
|
1291
|
+
body = (0, _objectWithoutPropertiesLoose2.default)(payload, _excluded10);
|
|
1260
1292
|
try {
|
|
1261
1293
|
setLoginState({
|
|
1262
1294
|
loading: true
|
|
@@ -1321,7 +1353,7 @@ var _default = (store, api, sharedActions) => {
|
|
|
1321
1353
|
const {
|
|
1322
1354
|
callback
|
|
1323
1355
|
} = _payload,
|
|
1324
|
-
payload = (0, _objectWithoutPropertiesLoose2.default)(_payload,
|
|
1356
|
+
payload = (0, _objectWithoutPropertiesLoose2.default)(_payload, _excluded11);
|
|
1325
1357
|
setLoginState({
|
|
1326
1358
|
loading: true
|
|
1327
1359
|
});
|
|
@@ -1356,7 +1388,7 @@ var _default = (store, api, sharedActions) => {
|
|
|
1356
1388
|
const {
|
|
1357
1389
|
callback
|
|
1358
1390
|
} = _payload,
|
|
1359
|
-
payload = (0, _objectWithoutPropertiesLoose2.default)(_payload,
|
|
1391
|
+
payload = (0, _objectWithoutPropertiesLoose2.default)(_payload, _excluded12);
|
|
1360
1392
|
setLoginState({
|
|
1361
1393
|
loading: true
|
|
1362
1394
|
});
|
|
@@ -1371,6 +1403,9 @@ var _default = (store, api, sharedActions) => {
|
|
|
1371
1403
|
});
|
|
1372
1404
|
callback == null ? void 0 : callback(true);
|
|
1373
1405
|
} catch (e) {
|
|
1406
|
+
if (await __redirectToSsoIfRequired(e)) {
|
|
1407
|
+
return;
|
|
1408
|
+
}
|
|
1374
1409
|
setLoginState({
|
|
1375
1410
|
loading: false,
|
|
1376
1411
|
error: (0, _helpers.errorHandler)(e)
|
|
@@ -1382,7 +1417,7 @@ var _default = (store, api, sharedActions) => {
|
|
|
1382
1417
|
const {
|
|
1383
1418
|
callback
|
|
1384
1419
|
} = _payload,
|
|
1385
|
-
payload = (0, _objectWithoutPropertiesLoose2.default)(_payload,
|
|
1420
|
+
payload = (0, _objectWithoutPropertiesLoose2.default)(_payload, _excluded13);
|
|
1386
1421
|
setLoginState({
|
|
1387
1422
|
loading: true
|
|
1388
1423
|
});
|
|
@@ -1394,6 +1429,9 @@ var _default = (store, api, sharedActions) => {
|
|
|
1394
1429
|
});
|
|
1395
1430
|
callback == null ? void 0 : callback(true);
|
|
1396
1431
|
} catch (e) {
|
|
1432
|
+
if (await __redirectToSsoIfRequired(e)) {
|
|
1433
|
+
return;
|
|
1434
|
+
}
|
|
1397
1435
|
setLoginState({
|
|
1398
1436
|
loading: false,
|
|
1399
1437
|
error: (0, _helpers.errorHandler)(e)
|
|
@@ -1405,7 +1443,7 @@ var _default = (store, api, sharedActions) => {
|
|
|
1405
1443
|
const {
|
|
1406
1444
|
callback
|
|
1407
1445
|
} = _payload,
|
|
1408
|
-
payload = (0, _objectWithoutPropertiesLoose2.default)(_payload,
|
|
1446
|
+
payload = (0, _objectWithoutPropertiesLoose2.default)(_payload, _excluded14);
|
|
1409
1447
|
setLoginState({
|
|
1410
1448
|
loading: true
|
|
1411
1449
|
});
|
|
@@ -1432,7 +1470,7 @@ var _default = (store, api, sharedActions) => {
|
|
|
1432
1470
|
const {
|
|
1433
1471
|
callback
|
|
1434
1472
|
} = _payload,
|
|
1435
|
-
payload = (0, _objectWithoutPropertiesLoose2.default)(_payload,
|
|
1473
|
+
payload = (0, _objectWithoutPropertiesLoose2.default)(_payload, _excluded15);
|
|
1436
1474
|
setLoginState({
|
|
1437
1475
|
loading: true
|
|
1438
1476
|
});
|
|
@@ -1444,6 +1482,9 @@ var _default = (store, api, sharedActions) => {
|
|
|
1444
1482
|
});
|
|
1445
1483
|
callback == null ? void 0 : callback(true);
|
|
1446
1484
|
} catch (e) {
|
|
1485
|
+
if (await __redirectToSsoIfRequired(e)) {
|
|
1486
|
+
return;
|
|
1487
|
+
}
|
|
1447
1488
|
setLoginState({
|
|
1448
1489
|
loading: false,
|
|
1449
1490
|
error: (0, _helpers.errorHandler)(e)
|
|
@@ -176,6 +176,9 @@ var _default = (store, api, sharedActions) => {
|
|
|
176
176
|
}
|
|
177
177
|
callback == null ? void 0 : callback(mfaState.recoveryCode);
|
|
178
178
|
} catch (e) {
|
|
179
|
+
if (await actions.__redirectToSsoIfRequired(e)) {
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
179
182
|
setMfaState({
|
|
180
183
|
loading: false,
|
|
181
184
|
error: (0, _helpers.errorHandler)(e)
|
|
@@ -101,6 +101,11 @@ var _default = (store, api, sharedActions) => {
|
|
|
101
101
|
callback == null ? void 0 : callback(true);
|
|
102
102
|
} catch (e) {
|
|
103
103
|
callback == null ? void 0 : callback(false);
|
|
104
|
+
|
|
105
|
+
// the session's tenant requires SSO: its SSO login steps the user up, instead of logging them out
|
|
106
|
+
if (await actions.__redirectToSsoIfRequired(e)) {
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
104
109
|
await __handleStepUpError(e);
|
|
105
110
|
}
|
|
106
111
|
};
|
|
@@ -59,10 +59,11 @@ const getUrlDerivedStepUp = () => {
|
|
|
59
59
|
|
|
60
60
|
/**
|
|
61
61
|
* Set the url and query params in the local storage FRONTEGG_AFTER_AUTH_REDIRECT_URL value
|
|
62
|
+
* @param urlStrategy 'hash' saves the route in the hash, which is the page the app shows
|
|
62
63
|
*/
|
|
63
64
|
exports.getUrlDerivedStepUp = getUrlDerivedStepUp;
|
|
64
|
-
function setAfterAuthRedirectUrlForStepUp() {
|
|
65
|
-
const encodedRedirectUrl = window.location.pathname + window.location.search;
|
|
65
|
+
function setAfterAuthRedirectUrlForStepUp(urlStrategy = 'path') {
|
|
66
|
+
const encodedRedirectUrl = urlStrategy === 'hash' ? window.location.hash.substring(1) || '/' : window.location.pathname + window.location.search;
|
|
66
67
|
window.localStorage.setItem(_constants.FRONTEGG_AFTER_AUTH_REDIRECT_URL, encodedRedirectUrl);
|
|
67
68
|
}
|
|
68
69
|
|
|
@@ -60,7 +60,7 @@ var _default = (store, api, sharedActions) => {
|
|
|
60
60
|
if (await actions.__redirectToSsoIfRequired(e)) {
|
|
61
61
|
// the tab comes back from SSO in the target tenant, not the one the failed switch restored
|
|
62
62
|
if (_restApi.ContextHolder.for(store.root.appName).isSessionPerTenantEnabled()) {
|
|
63
|
-
(0, _restApi.
|
|
63
|
+
(0, _restApi.setTabTenantForSsoSwitch)(tenantId);
|
|
64
64
|
}
|
|
65
65
|
return;
|
|
66
66
|
}
|
package/node/auth/helpers.js
CHANGED
|
@@ -9,12 +9,15 @@ var _exportNames = {
|
|
|
9
9
|
isResetPasswordRequired: true,
|
|
10
10
|
mapMetaDataObjectToActions: true,
|
|
11
11
|
getUri: true,
|
|
12
|
+
isOnOidcCallbackRoute: true,
|
|
13
|
+
restoreTabTenantUnlessSsoCallback: true,
|
|
12
14
|
prepareIdentifiersForSignup: true,
|
|
15
|
+
isOnAuthPageRoute: true,
|
|
13
16
|
isAuthRoute: true
|
|
14
17
|
};
|
|
15
|
-
exports.prepareIdentifiersForSignup = exports.mapMetaDataObjectToActions = exports.isResetPasswordRequired = exports.isMfaRequired = exports.isAuthRoute = exports.getUri = void 0;
|
|
16
|
-
var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
|
|
18
|
+
exports.restoreTabTenantUnlessSsoCallback = exports.prepareIdentifiersForSignup = exports.mapMetaDataObjectToActions = exports.isResetPasswordRequired = exports.isOnOidcCallbackRoute = exports.isOnAuthPageRoute = exports.isMfaRequired = exports.isAuthRoute = exports.getUri = void 0;
|
|
17
19
|
var _objectWithoutPropertiesLoose2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutPropertiesLoose"));
|
|
20
|
+
var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
|
|
18
21
|
var _restApi = require("@frontegg/rest-api");
|
|
19
22
|
var _consts = require("./LoginState/consts");
|
|
20
23
|
var _helpers = require("./Entitlements/helpers");
|
|
@@ -104,7 +107,55 @@ const getUri = urlStrategy => {
|
|
|
104
107
|
}
|
|
105
108
|
}
|
|
106
109
|
};
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* The route the app shows and the page's path. With hash routing they differ: the app's pages live in the hash, but
|
|
113
|
+
* SAML, OIDC, social and magic link callbacks come back on the path, which is where login matches them.
|
|
114
|
+
*/
|
|
107
115
|
exports.getUri = getUri;
|
|
116
|
+
const getCurrentRoutes = urlStrategy => {
|
|
117
|
+
const hashOrPathRoute = getUri(urlStrategy);
|
|
118
|
+
const {
|
|
119
|
+
pathname
|
|
120
|
+
} = window.location;
|
|
121
|
+
return hashOrPathRoute === pathname ? [pathname] : [hashOrPathRoute, pathname];
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* On the OIDC callback the page still has to finish the OIDC login with its code: a refresh refused before that is not
|
|
126
|
+
* a reason to go back to the IdP, which would send the user straight back here, forever.
|
|
127
|
+
*/
|
|
128
|
+
const isOnOidcCallbackRoute = store => {
|
|
129
|
+
var _store$root$urlStrate;
|
|
130
|
+
const {
|
|
131
|
+
oidcRedirectUrl
|
|
132
|
+
} = (0, _extends2.default)({}, _consts.defaultFronteggRoutes, store.auth.routes);
|
|
133
|
+
return !!oidcRedirectUrl && getCurrentRoutes((_store$root$urlStrate = store.root.urlStrategy) != null ? _store$root$urlStrate : 'path').some(currentRoute => currentRoute.endsWith(oidcRedirectUrl));
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* After a switch refused for SSO the tab points at the SSO tenant. Its SSO login comes back on a callback route and
|
|
138
|
+
* keeps it; any other page load means the user didn't finish that login, so the tab goes back to its tenant.
|
|
139
|
+
*/
|
|
140
|
+
exports.isOnOidcCallbackRoute = isOnOidcCallbackRoute;
|
|
141
|
+
const restoreTabTenantUnlessSsoCallback = store => {
|
|
142
|
+
var _store$root$urlStrate2;
|
|
143
|
+
if (!(0, _restApi.isEnforceSsoOnTenantAccessEnabled)(store.root.appName) || !_restApi.ContextHolder.for(store.root.appName).isSessionPerTenantEnabled()) {
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
const {
|
|
147
|
+
samlCallbackUrl,
|
|
148
|
+
oidcRedirectUrl,
|
|
149
|
+
hostedLoginRedirectUrl
|
|
150
|
+
} = (0, _extends2.default)({}, _consts.defaultFronteggRoutes, store.auth.routes);
|
|
151
|
+
// matched like login matches its callback pages: endsWith, so a basename before the route still counts
|
|
152
|
+
const currentRoutes = getCurrentRoutes((_store$root$urlStrate2 = store.root.urlStrategy) != null ? _store$root$urlStrate2 : 'path');
|
|
153
|
+
const isSsoCallback = [samlCallbackUrl, oidcRedirectUrl, hostedLoginRedirectUrl].some(route => !!route && currentRoutes.some(currentRoute => currentRoute.endsWith(route)));
|
|
154
|
+
if (!isSsoCallback) {
|
|
155
|
+
(0, _restApi.restoreTabTenantBeforeSsoSwitch)();
|
|
156
|
+
}
|
|
157
|
+
};
|
|
158
|
+
exports.restoreTabTenantUnlessSsoCallback = restoreTabTenantUnlessSsoCallback;
|
|
108
159
|
const prepareIdentifiersForSignup = payload => {
|
|
109
160
|
const {
|
|
110
161
|
phoneNumber,
|
|
@@ -129,7 +180,20 @@ const prepareIdentifiersForSignup = payload => {
|
|
|
129
180
|
}
|
|
130
181
|
return finalDto;
|
|
131
182
|
};
|
|
183
|
+
|
|
184
|
+
// Pages the user lands on after login or sign-up: destinations, not auth pages.
|
|
132
185
|
exports.prepareIdentifiersForSignup = prepareIdentifiersForSignup;
|
|
186
|
+
const AFTER_AUTH_DESTINATION_ROUTES = ['authenticatedUrl', 'signUpSuccessUrl', 'accountSignUpSuccessUrl', 'userSignUpSuccessUrl', 'customLoginAuthenticatedUrl'];
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Whether the current route is an auth page (login, tenant chooser, social / magic link / SSO callback), not one to come
|
|
190
|
+
* back to. Unlike isAuthRoute: after-login / sign-up destinations don't count, and endsWith lets a basename prefix it.
|
|
191
|
+
*/
|
|
192
|
+
const isOnAuthPageRoute = (urlStrategy, routes) => {
|
|
193
|
+
const currentRoutes = getCurrentRoutes(urlStrategy);
|
|
194
|
+
return Object.entries((0, _extends2.default)({}, _consts.defaultFronteggRoutes, routes)).some(([name, route]) => !AFTER_AUTH_DESTINATION_ROUTES.includes(name) && typeof route === 'string' && !!route && currentRoutes.some(currentRoute => currentRoute.endsWith(route)));
|
|
195
|
+
};
|
|
196
|
+
exports.isOnAuthPageRoute = isOnAuthPageRoute;
|
|
133
197
|
const isAuthRoute = (path, routes) => {
|
|
134
198
|
const _defaultFronteggRoute = (0, _extends2.default)({}, _consts.defaultFronteggRoutes, routes),
|
|
135
199
|
authRoutes = (0, _objectWithoutPropertiesLoose2.default)(_defaultFronteggRoute, _excluded2);
|
package/node/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@frontegg/redux-store",
|
|
3
|
-
"version": "7.131.0-alpha.
|
|
3
|
+
"version": "7.131.0-alpha.1",
|
|
4
4
|
"main": "./node/index.js",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Frontegg LTD",
|
|
7
7
|
"dependencies": {
|
|
8
8
|
"@babel/runtime": "^7.18.6",
|
|
9
9
|
"@frontegg/entitlements-javascript-commons": "1.1.2",
|
|
10
|
-
"@frontegg/rest-api": "7.131.0-alpha.
|
|
10
|
+
"@frontegg/rest-api": "7.131.0-alpha.1",
|
|
11
11
|
"fast-deep-equal": "3.1.3",
|
|
12
12
|
"get-value": "^3.0.1",
|
|
13
13
|
"proxy-compare": "^3.0.0",
|