@frontegg/redux-store 7.129.0-alpha.0 → 7.129.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/auth/LoginState/actions/afterAuthNavigation.actions.js +9 -41
- package/auth/LoginState/actions/hostedLoginAuthorize.actions.js +2 -6
- package/auth/LoginState/actions/index.d.ts +0 -4
- package/auth/LoginState/actions/index.js +53 -133
- package/auth/LoginState/consts.d.ts +1 -0
- package/auth/LoginState/consts.js +1 -0
- package/auth/TenantsState/actions.js +2 -12
- package/auth/index.js +2 -2
- package/constants.d.ts +0 -1
- package/constants.js +0 -1
- package/helpers/handlers.d.ts +1 -4
- package/helpers/handlers.js +1 -4
- package/index.js +1 -1
- package/mocks/auth-mocks/loginActions.mocks.d.ts +0 -4
- package/node/auth/LoginState/actions/afterAuthNavigation.actions.js +8 -40
- package/node/auth/LoginState/actions/hostedLoginAuthorize.actions.js +2 -6
- package/node/auth/LoginState/actions/index.js +48 -128
- package/node/auth/LoginState/consts.js +3 -1
- package/node/auth/TenantsState/actions.js +0 -10
- package/node/auth/index.js +1 -1
- package/node/constants.js +1 -4
- package/node/helpers/handlers.js +1 -5
- package/node/index.js +1 -1
- package/package.json +2 -2
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import _extends from "@babel/runtime/helpers/esm/extends";
|
|
2
|
-
import { ENFORCE_SSO_ON_TENANT_ACCESS_FF, FeatureFlags } from '@frontegg/rest-api';
|
|
3
2
|
import { getPathAndSearchParamsFromUrl, getRedirectUrl, isAbsoluteUrl } from '../helpers';
|
|
4
3
|
import { shouldPromptChooseTenant } from '../helpers/tenantSelect';
|
|
5
|
-
import { FRONTEGG_AFTER_AUTH_REDIRECT_URL
|
|
4
|
+
import { FRONTEGG_AFTER_AUTH_REDIRECT_URL } from '../../../constants';
|
|
6
5
|
import { LoginStep } from '../interfaces';
|
|
7
6
|
import { SHOULD_STEP_UP_KEY } from '../../StepUpState/consts';
|
|
8
7
|
import { delay } from '../../../helpers';
|
|
@@ -57,33 +56,6 @@ export default ((store, api, sharedActions) => {
|
|
|
57
56
|
}, additionalUpdate));
|
|
58
57
|
}
|
|
59
58
|
|
|
60
|
-
/**
|
|
61
|
-
* A switch that needed SSO saved its target tenant (in this tab) before sending the user to SSO.
|
|
62
|
-
* Once logged in again, switch to it once if the login landed in another tenant.
|
|
63
|
-
* @returns true when the switch left the user without a session (MFA step for the target tenant, or logout)
|
|
64
|
-
*/
|
|
65
|
-
async function switchToPendingSsoTenant() {
|
|
66
|
-
var _store$auth$user, _store$auth$user2;
|
|
67
|
-
const [isEnforceSsoOnTenantAccessEnabled] = FeatureFlags.getFeatureFlags([ENFORCE_SSO_ON_TENANT_ACCESS_FF], store.root.appName);
|
|
68
|
-
const pendingTenantId = window.sessionStorage.getItem(FRONTEGG_PENDING_SWITCH_TENANT);
|
|
69
|
-
if (!isEnforceSsoOnTenantAccessEnabled || !pendingTenantId || !((_store$auth$user = store.auth.user) != null && _store$auth$user.accessToken)) {
|
|
70
|
-
return false;
|
|
71
|
-
}
|
|
72
|
-
if (store.auth.user.tenantId === pendingTenantId) {
|
|
73
|
-
window.sessionStorage.removeItem(FRONTEGG_PENDING_SWITCH_TENANT);
|
|
74
|
-
return false;
|
|
75
|
-
}
|
|
76
|
-
// silentReload keeps switchingTenant set, so the switch's own refresh doesn't re-run this navigation
|
|
77
|
-
await actions.switchTenant({
|
|
78
|
-
tenantId: pendingTenantId,
|
|
79
|
-
silentReload: true,
|
|
80
|
-
keepLoginState: true
|
|
81
|
-
});
|
|
82
|
-
// removed only after the switch: a refused re-run must not send the user to SSO again
|
|
83
|
-
window.sessionStorage.removeItem(FRONTEGG_PENDING_SWITCH_TENANT);
|
|
84
|
-
return !((_store$auth$user2 = store.auth.user) != null && _store$auth$user2.accessToken);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
59
|
/**
|
|
88
60
|
* @param customLoginAuthenticatedUrl custom login authenticated url if exists
|
|
89
61
|
* @returns the authenticated url to redirect to after auth navigation
|
|
@@ -108,15 +80,19 @@ export default ((store, api, sharedActions) => {
|
|
|
108
80
|
logoutUrl,
|
|
109
81
|
socialLoginCallbackUrl,
|
|
110
82
|
activateUrl,
|
|
111
|
-
activateWithOTCUrl
|
|
83
|
+
activateWithOTCUrl,
|
|
84
|
+
oidcRedirectUrl
|
|
112
85
|
} = routes;
|
|
113
86
|
let finalUrl = urlFromLocalStorage;
|
|
114
87
|
if (!finalUrl || [loginUrl, logoutUrl, socialLoginCallbackUrl, activateUrl, activateWithOTCUrl].includes(finalUrl)) {
|
|
115
88
|
finalUrl = authenticatedUrl;
|
|
116
89
|
}
|
|
90
|
+
|
|
91
|
+
// The OIDC callback's query is the IdP's code and state; the user's own query was saved with the URL.
|
|
92
|
+
const isOidcCallback = !!oidcRedirectUrl && window.location.pathname.endsWith(oidcRedirectUrl);
|
|
117
93
|
const redirectUrl = getRedirectUrl({
|
|
118
94
|
authenticatedUrl: finalUrl,
|
|
119
|
-
includeQueryParam,
|
|
95
|
+
includeQueryParam: includeQueryParam && !isOidcCallback,
|
|
120
96
|
enforceRedirectToSameSite,
|
|
121
97
|
allowedRedirectOrigins
|
|
122
98
|
});
|
|
@@ -187,7 +163,7 @@ export default ((store, api, sharedActions) => {
|
|
|
187
163
|
* until the resolved-guard, the LD flag, and the option all pass.
|
|
188
164
|
*/
|
|
189
165
|
const shouldRouteToChooseTenant = async () => {
|
|
190
|
-
var _store$auth$tenantSel, _store$auth$
|
|
166
|
+
var _store$auth$tenantSel, _store$auth$user, _store$auth$user$act, _store$auth$tenantsSt;
|
|
191
167
|
const loginState = store.auth.loginState;
|
|
192
168
|
// Guard first so re-entry after the choice is resolved finalizes without re-reading the flag.
|
|
193
169
|
if (loginState.tenantChoiceResolved) {
|
|
@@ -203,7 +179,7 @@ export default ((store, api, sharedActions) => {
|
|
|
203
179
|
return false; // feature off — never read tenant data
|
|
204
180
|
}
|
|
205
181
|
|
|
206
|
-
const isImpersonation = !!((_store$auth$
|
|
182
|
+
const isImpersonation = !!((_store$auth$user = store.auth.user) != null && (_store$auth$user$act = _store$auth$user.act) != null && _store$auth$user$act.sub);
|
|
207
183
|
if (isImpersonation) {
|
|
208
184
|
return false;
|
|
209
185
|
}
|
|
@@ -281,14 +257,6 @@ export default ((store, api, sharedActions) => {
|
|
|
281
257
|
}
|
|
282
258
|
try {
|
|
283
259
|
var _window4, _payload$preventRedir;
|
|
284
|
-
const isSessionLostInPendingSwitch = await switchToPendingSsoTenant();
|
|
285
|
-
if (isSessionLostInPendingSwitch) {
|
|
286
|
-
// MFA for the target tenant or a failed refresh: continue on the login page
|
|
287
|
-
store.auth.onRedirectTo(store.auth.routes.loginUrl, {
|
|
288
|
-
preserveQueryParams: true
|
|
289
|
-
});
|
|
290
|
-
return;
|
|
291
|
-
}
|
|
292
260
|
const {
|
|
293
261
|
customLoginAuthenticatedUrl,
|
|
294
262
|
stepUpUrl
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import _extends from "@babel/runtime/helpers/esm/extends";
|
|
2
2
|
import { createRandomString, generateCodeChallenge, GTMEventAction, refreshTokenWithRetry, reportGTMEvent } from '../../../helpers';
|
|
3
3
|
import { HOSTED_LOGIN_VERIFIER_KEY } from '../../../constants';
|
|
4
|
-
import { ENFORCE_SSO_ON_TENANT_ACCESS_FF, FeatureFlags } from '@frontegg/rest-api';
|
|
5
4
|
import { getBaseNameWithoutSlashSuffix, getSearchParam, isOauthCallbackRoute, TENANT_ID_PARAM_KEY } from '../helpers';
|
|
6
5
|
import { getUri, getUrlDerivedStepUp, isSteppedUp, redirectByStepUpUrl } from '../../helpers';
|
|
7
6
|
import { SHOULD_STEP_UP_KEY } from '../../StepUpState/consts';
|
|
@@ -80,10 +79,7 @@ export default ((store, api, sharedActions) => {
|
|
|
80
79
|
code_challenge_method: 'S256',
|
|
81
80
|
nonce
|
|
82
81
|
}, additionalParams);
|
|
83
|
-
|
|
84
|
-
// the tenant asked for (SSO for a refused switch or refresh) wins over the resolved and the page's tenant
|
|
85
|
-
const isTenantRequested = isEnforceSsoOnTenantAccessEnabled && !!(additionalParams != null && additionalParams.tenantId);
|
|
86
|
-
if (context.tenantResolver && !isTenantRequested) {
|
|
82
|
+
if (context.tenantResolver) {
|
|
87
83
|
var _context$tenantResolv;
|
|
88
84
|
const resolvedTenantResult = await ((_context$tenantResolv = context.tenantResolver) == null ? void 0 : _context$tenantResolv.call(context));
|
|
89
85
|
if (resolvedTenantResult != null && resolvedTenantResult.tenant) {
|
|
@@ -91,7 +87,7 @@ export default ((store, api, sharedActions) => {
|
|
|
91
87
|
}
|
|
92
88
|
}
|
|
93
89
|
const tenantId = getSearchParam(TENANT_ID_PARAM_KEY);
|
|
94
|
-
if (tenantId
|
|
90
|
+
if (tenantId) {
|
|
95
91
|
params['tenantId'] = tenantId;
|
|
96
92
|
}
|
|
97
93
|
if (FronteggNativeModule.isAvailable('closeWindow')) {
|
|
@@ -75,9 +75,5 @@ declare const _default: (store: FronteggState, api: RestApi, sharedActions: Shar
|
|
|
75
75
|
resetBreachedPassword: (payload: IForgotPassword) => Promise<void>;
|
|
76
76
|
refreshTokenForSocialLogins: () => Promise<void>;
|
|
77
77
|
__refreshToken: () => Promise<void>;
|
|
78
|
-
__redirectToSsoForTenant: ({ tenantId, address }: {
|
|
79
|
-
tenantId: string;
|
|
80
|
-
address: string;
|
|
81
|
-
}) => Promise<void>;
|
|
82
78
|
};
|
|
83
79
|
export default _default;
|
|
@@ -23,85 +23,28 @@ import mfaWithEmailCodeActions from './mfaWithEmailCode.actions';
|
|
|
23
23
|
import mfaWithSMSActions from './mfaWithSMS.actions';
|
|
24
24
|
import mfaWithWebAuthnActions from './mfaWithWebAuthn.actions';
|
|
25
25
|
import { LoginFlow, LoginStep } from '../interfaces';
|
|
26
|
-
import { base64urlDecode, deepResetState, delay, errorHandler, errorTraceId, GTMEventAction,
|
|
26
|
+
import { base64urlDecode, deepResetState, delay, errorHandler, errorTraceId, GTMEventAction, publicKeyCredentialToJSON, refreshTokenWithRetry, reportGTMEvent, retryIfNeeded, withRetryConfig } from '../../../helpers';
|
|
27
27
|
import { initialState } from '../state';
|
|
28
28
|
import { getSearchParam, isEmailPayload, isUsernamePayload, shouldShowPasswordRotationPromptFunc, TENANT_ID_PARAM_KEY } from '../helpers';
|
|
29
|
-
import { AuthStrategyEnum, ContextHolder,
|
|
29
|
+
import { AuthStrategyEnum, ContextHolder, FeatureFlags, getTabTenantFromSessionStorage, removeTabTenantFromSessionStorage, WebAuthnDeviceType, PreLoginAddressType } from '@frontegg/rest-api';
|
|
30
30
|
import hostedLoginAuthorizeActions from './hostedLoginAuthorize.actions';
|
|
31
31
|
import { clearHostedOAuthState } from '../oauthStorage';
|
|
32
32
|
import { SHOULD_STEP_UP_KEY } from '../../StepUpState/consts';
|
|
33
33
|
import { FronteggNativeModule, isEntitlementsDeeplyEqual } from '../../../toolkit';
|
|
34
34
|
import { REQUEST_NAME, UserVerifiedOriginTypes } from '../../interfaces';
|
|
35
|
-
import { authStrategyLoginStepMap } from '../consts';
|
|
36
|
-
import { isMfaRequired, isResetPasswordRequired
|
|
35
|
+
import { authStrategyLoginStepMap, defaultOnRedirectTo } from '../consts';
|
|
36
|
+
import { isMfaRequired, isResetPasswordRequired } from '../../helpers';
|
|
37
37
|
import { MFAStep } from '../../MfaState/interfaces';
|
|
38
38
|
import { SamlVendors } from '../../SSOState/interfaces';
|
|
39
|
-
import { DEFAULT_RETRY_CONFIG
|
|
39
|
+
import { DEFAULT_RETRY_CONFIG } from '../../../constants';
|
|
40
|
+
const SSO_REDIRECT_DELAY_MS = 2000;
|
|
41
|
+
const isUsableRedirect = onRedirectTo => typeof onRedirectTo === 'function' && onRedirectTo !== defaultOnRedirectTo;
|
|
40
42
|
export default ((store, api, sharedActions) => {
|
|
41
43
|
const actions = sharedActions;
|
|
42
44
|
const contextHolder = ContextHolder.for(store.root.appName);
|
|
43
45
|
|
|
44
|
-
/**
|
|
45
|
-
* Sends the user to log in through the tenant's SSO and back to the current page afterwards.
|
|
46
|
-
* @protected
|
|
47
|
-
*/
|
|
48
|
-
const __redirectToSsoForTenant = async ({
|
|
49
|
-
tenantId,
|
|
50
|
-
address
|
|
51
|
-
}) => {
|
|
52
|
-
// on the login page (tenant chooser) keep the destination the login already saved
|
|
53
|
-
if (!window.location.pathname.endsWith(store.auth.routes.loginUrl)) {
|
|
54
|
-
setAfterAuthRedirectUrlForStepUp();
|
|
55
|
-
}
|
|
56
|
-
if (store.auth.hostedLoginBox) {
|
|
57
|
-
await actions.requestHostedLoginAuthorize({
|
|
58
|
-
prompt: 'login',
|
|
59
|
-
tenantId
|
|
60
|
-
});
|
|
61
|
-
return;
|
|
62
|
-
}
|
|
63
|
-
store.auth.onRedirectTo(address, {
|
|
64
|
-
refresh: true
|
|
65
|
-
});
|
|
66
|
-
};
|
|
67
|
-
/**
|
|
68
|
-
* Handles a token refresh refused because the tenant requires SSO.
|
|
69
|
-
* ssoRequired: true sends the user to SSO. ssoRequired: false renews once more for the tenant of the
|
|
70
|
-
* current token, which keeps the session.
|
|
71
|
-
* @returns true when handled, false when the caller should log out
|
|
72
|
-
* @private
|
|
73
|
-
*/
|
|
74
|
-
const __handleSsoEnforcementRefreshError = async (e, isSsoEnforcementRetry, refreshForTenant) => {
|
|
75
|
-
var _store$auth$user;
|
|
76
|
-
const [isEnforceSsoOnTenantAccessEnabled] = FeatureFlags.getFeatureFlags([ENFORCE_SSO_ON_TENANT_ACCESS_FF], store.root.appName);
|
|
77
|
-
if (!isEnforceSsoOnTenantAccessEnabled || !isSsoEnforcementError(e)) {
|
|
78
|
-
return false;
|
|
79
|
-
}
|
|
80
|
-
const {
|
|
81
|
-
errorContext
|
|
82
|
-
} = e;
|
|
83
|
-
// the switch re-run after coming back from SSO keeps the session instead of sending the user to SSO again
|
|
84
|
-
const isPendingSwitchRerun = !!window.sessionStorage.getItem(FRONTEGG_PENDING_SWITCH_TENANT);
|
|
85
|
-
if (errorContext.ssoRequired && !isPendingSwitchRerun) {
|
|
86
|
-
await __redirectToSsoForTenant(errorContext);
|
|
87
|
-
return true;
|
|
88
|
-
}
|
|
89
|
-
if (isSsoEnforcementRetry) {
|
|
90
|
-
return false;
|
|
91
|
-
}
|
|
92
|
-
const currentTenantId = (_store$auth$user = store.auth.user) == null ? void 0 : _store$auth$user.tenantId;
|
|
93
|
-
if (currentTenantId && contextHolder.isSessionPerTenantEnabled()) {
|
|
94
|
-
setTabTenantInSessionStorage(currentTenantId);
|
|
95
|
-
}
|
|
96
|
-
await refreshForTenant(currentTenantId);
|
|
97
|
-
return true;
|
|
98
|
-
};
|
|
99
|
-
|
|
100
46
|
/** @private */
|
|
101
|
-
const __refreshTokenHosted = async ({
|
|
102
|
-
tenantId,
|
|
103
|
-
isSsoEnforcementRetry = false
|
|
104
|
-
} = {}) => {
|
|
47
|
+
const __refreshTokenHosted = async () => {
|
|
105
48
|
const user = store.auth.user;
|
|
106
49
|
if (!(user != null && user.refreshToken)) {
|
|
107
50
|
contextHolder.setAccessToken(null);
|
|
@@ -113,7 +56,7 @@ export default ((store, api, sharedActions) => {
|
|
|
113
56
|
return;
|
|
114
57
|
}
|
|
115
58
|
try {
|
|
116
|
-
const tabTenantId =
|
|
59
|
+
const tabTenantId = getTabTenantFromSessionStorage(store.root.appName);
|
|
117
60
|
const body = _extends({
|
|
118
61
|
grant_type: 'refresh_token',
|
|
119
62
|
refresh_token: user == null ? void 0 : user.refreshToken
|
|
@@ -128,13 +71,6 @@ export default ((store, api, sharedActions) => {
|
|
|
128
71
|
isAuthenticated: true
|
|
129
72
|
});
|
|
130
73
|
} catch (e) {
|
|
131
|
-
const retry = tenantId => __refreshTokenHosted({
|
|
132
|
-
tenantId,
|
|
133
|
-
isSsoEnforcementRetry: true
|
|
134
|
-
});
|
|
135
|
-
if (await __handleSsoEnforcementRefreshError(e, isSsoEnforcementRetry, retry)) {
|
|
136
|
-
return;
|
|
137
|
-
}
|
|
138
74
|
contextHolder.setAccessToken(null);
|
|
139
75
|
contextHolder.setUser(null);
|
|
140
76
|
actions.setAuthState({
|
|
@@ -154,10 +90,7 @@ export default ((store, api, sharedActions) => {
|
|
|
154
90
|
};
|
|
155
91
|
|
|
156
92
|
/** @private */
|
|
157
|
-
const __refreshTokenEmbedded = async ({
|
|
158
|
-
tenantId,
|
|
159
|
-
isSsoEnforcementRetry = false
|
|
160
|
-
} = {}) => {
|
|
93
|
+
const __refreshTokenEmbedded = async () => {
|
|
161
94
|
try {
|
|
162
95
|
const {
|
|
163
96
|
routes,
|
|
@@ -168,7 +101,7 @@ export default ((store, api, sharedActions) => {
|
|
|
168
101
|
user,
|
|
169
102
|
tenants = [],
|
|
170
103
|
activeTenant
|
|
171
|
-
} = await refreshTokenWithRetry(() => api.auth.refreshTokenV3(
|
|
104
|
+
} = await refreshTokenWithRetry(() => api.auth.refreshTokenV3());
|
|
172
105
|
if (isMfaRequired(user, store.root.appName)) {
|
|
173
106
|
const mfaRequiredState = await actions.getMfaRequiredState(user);
|
|
174
107
|
actions.setAuthState(mfaRequiredState);
|
|
@@ -199,13 +132,6 @@ export default ((store, api, sharedActions) => {
|
|
|
199
132
|
});
|
|
200
133
|
}
|
|
201
134
|
} catch (e) {
|
|
202
|
-
const retry = tenantId => __refreshTokenEmbedded({
|
|
203
|
-
tenantId,
|
|
204
|
-
isSsoEnforcementRetry: true
|
|
205
|
-
});
|
|
206
|
-
if (await __handleSsoEnforcementRefreshError(e, isSsoEnforcementRetry, retry)) {
|
|
207
|
-
return;
|
|
208
|
-
}
|
|
209
135
|
contextHolder.setAccessToken(null);
|
|
210
136
|
contextHolder.setUser(null);
|
|
211
137
|
actions.setAuthState({
|
|
@@ -216,9 +142,7 @@ export default ((store, api, sharedActions) => {
|
|
|
216
142
|
};
|
|
217
143
|
|
|
218
144
|
/** @private */
|
|
219
|
-
const __refreshTokenWithNativeTokens = async ({
|
|
220
|
-
isSsoEnforcementRetry = false
|
|
221
|
-
} = {}) => {
|
|
145
|
+
const __refreshTokenWithNativeTokens = async () => {
|
|
222
146
|
try {
|
|
223
147
|
const authApi = api.auth;
|
|
224
148
|
const response = await refreshTokenWithRetry(async () => {
|
|
@@ -232,13 +156,6 @@ export default ((store, api, sharedActions) => {
|
|
|
232
156
|
isAuthenticated: true
|
|
233
157
|
});
|
|
234
158
|
} catch (e) {
|
|
235
|
-
// native tokens can't name a tenant: the retry relies on the tab tenant only
|
|
236
|
-
const retry = () => __refreshTokenWithNativeTokens({
|
|
237
|
-
isSsoEnforcementRetry: true
|
|
238
|
-
});
|
|
239
|
-
if (await __handleSsoEnforcementRefreshError(e, isSsoEnforcementRetry, retry)) {
|
|
240
|
-
return;
|
|
241
|
-
}
|
|
242
159
|
contextHolder.setAccessToken(null);
|
|
243
160
|
contextHolder.setUser(null);
|
|
244
161
|
actions.setAuthState({
|
|
@@ -272,9 +189,9 @@ export default ((store, api, sharedActions) => {
|
|
|
272
189
|
* @private
|
|
273
190
|
*/
|
|
274
191
|
const __handleUnnecessaryEntitlementsUpdate = async updatedUser => {
|
|
275
|
-
var _store$auth$
|
|
192
|
+
var _store$auth$user;
|
|
276
193
|
// @ts-ignore TODO: fix entitlements state type
|
|
277
|
-
const oldEntitlements = (_store$auth$
|
|
194
|
+
const oldEntitlements = (_store$auth$user = store.auth.user) == null ? void 0 : _store$auth$user.entitlements;
|
|
278
195
|
if (isEntitlementsDeeplyEqual(oldEntitlements, updatedUser == null ? void 0 : updatedUser.entitlements)) {
|
|
279
196
|
// set the previous entitlements object
|
|
280
197
|
return _extends({}, updatedUser, {
|
|
@@ -472,6 +389,29 @@ export default ((store, api, sharedActions) => {
|
|
|
472
389
|
callback == null ? void 0 : callback();
|
|
473
390
|
}
|
|
474
391
|
};
|
|
392
|
+
|
|
393
|
+
// v6 parity (takeLeading): a preLogin called while another is in flight is dropped.
|
|
394
|
+
let preLoginInFlight = false;
|
|
395
|
+
let latestPreLoginAttempt = 0;
|
|
396
|
+
|
|
397
|
+
// Read on use: the login box installs onRedirectTo lazily, logout() clears it and the store default is a no-op.
|
|
398
|
+
const redirectToFullPage = url => {
|
|
399
|
+
const onRedirectTo = [store.auth.onRedirectTo, contextHolder.onRedirectTo].find(isUsableRedirect);
|
|
400
|
+
if (onRedirectTo) {
|
|
401
|
+
onRedirectTo(url, {
|
|
402
|
+
refresh: true
|
|
403
|
+
});
|
|
404
|
+
} else {
|
|
405
|
+
window.location.href = url;
|
|
406
|
+
}
|
|
407
|
+
};
|
|
408
|
+
const scheduleSsoRedirect = (ssoRedirectUrl, attempt) => {
|
|
409
|
+
setTimeout(() => {
|
|
410
|
+
if (attempt === latestPreLoginAttempt && store.auth.loginState.step === LoginStep.redirectToSSO) {
|
|
411
|
+
redirectToFullPage(ssoRedirectUrl);
|
|
412
|
+
}
|
|
413
|
+
}, SSO_REDIRECT_DELAY_MS);
|
|
414
|
+
};
|
|
475
415
|
const preLogin = async payload => {
|
|
476
416
|
const {
|
|
477
417
|
email,
|
|
@@ -480,11 +420,17 @@ export default ((store, api, sharedActions) => {
|
|
|
480
420
|
invitationToken,
|
|
481
421
|
callback
|
|
482
422
|
} = payload;
|
|
423
|
+
if (preLoginInFlight) {
|
|
424
|
+
callback == null ? void 0 : callback();
|
|
425
|
+
return;
|
|
426
|
+
}
|
|
427
|
+
preLoginInFlight = true;
|
|
428
|
+
latestPreLoginAttempt += 1;
|
|
429
|
+
const attempt = latestPreLoginAttempt;
|
|
483
430
|
setLoginState({
|
|
484
431
|
loading: true
|
|
485
432
|
});
|
|
486
433
|
try {
|
|
487
|
-
const onRedirectTo = store.auth.onRedirectTo;
|
|
488
434
|
const tenantId = getSearchParam(TENANT_ID_PARAM_KEY);
|
|
489
435
|
const preLoginResult = await api.auth.preLoginV2(_extends({}, email ? {
|
|
490
436
|
email
|
|
@@ -505,9 +451,7 @@ export default ((store, api, sharedActions) => {
|
|
|
505
451
|
setLoginState({
|
|
506
452
|
loading: false
|
|
507
453
|
});
|
|
508
|
-
|
|
509
|
-
refresh: true
|
|
510
|
-
});
|
|
454
|
+
redirectToFullPage(address);
|
|
511
455
|
return;
|
|
512
456
|
}
|
|
513
457
|
let ssoRedirectUrl = address;
|
|
@@ -530,11 +474,7 @@ export default ((store, api, sharedActions) => {
|
|
|
530
474
|
loading: false,
|
|
531
475
|
ssoRedirectUrl
|
|
532
476
|
});
|
|
533
|
-
|
|
534
|
-
onRedirectTo(ssoRedirectUrl, {
|
|
535
|
-
refresh: true
|
|
536
|
-
});
|
|
537
|
-
}, 2000);
|
|
477
|
+
scheduleSsoRedirect(ssoRedirectUrl, attempt);
|
|
538
478
|
}
|
|
539
479
|
} else {
|
|
540
480
|
await ssoPreloginFailed(_extends({}, username ? {
|
|
@@ -558,6 +498,8 @@ export default ((store, api, sharedActions) => {
|
|
|
558
498
|
invitationToken,
|
|
559
499
|
error: e
|
|
560
500
|
}));
|
|
501
|
+
} finally {
|
|
502
|
+
preLoginInFlight = false;
|
|
561
503
|
}
|
|
562
504
|
};
|
|
563
505
|
const postLogin = async payload => {
|
|
@@ -744,7 +686,6 @@ export default ((store, api, sharedActions) => {
|
|
|
744
686
|
if (!keepHostedOAuthState) {
|
|
745
687
|
clearHostedOAuthState();
|
|
746
688
|
}
|
|
747
|
-
window.sessionStorage.removeItem(FRONTEGG_PENDING_SWITCH_TENANT);
|
|
748
689
|
};
|
|
749
690
|
const logout = async payload => {
|
|
750
691
|
const hostedLoginBox = store.auth.hostedLoginBox;
|
|
@@ -1447,10 +1388,7 @@ export default ((store, api, sharedActions) => {
|
|
|
1447
1388
|
};
|
|
1448
1389
|
|
|
1449
1390
|
/** @private */
|
|
1450
|
-
const __refreshTokenHostedSocialLogins = async ({
|
|
1451
|
-
tenantId,
|
|
1452
|
-
isSsoEnforcementRetry = false
|
|
1453
|
-
} = {}) => {
|
|
1391
|
+
const __refreshTokenHostedSocialLogins = async () => {
|
|
1454
1392
|
const {
|
|
1455
1393
|
user: currentUser
|
|
1456
1394
|
} = store.auth;
|
|
@@ -1464,7 +1402,7 @@ export default ((store, api, sharedActions) => {
|
|
|
1464
1402
|
return;
|
|
1465
1403
|
}
|
|
1466
1404
|
try {
|
|
1467
|
-
const tabTenantId =
|
|
1405
|
+
const tabTenantId = getTabTenantFromSessionStorage(store.root.appName);
|
|
1468
1406
|
const body = _extends({
|
|
1469
1407
|
grant_type: 'refresh_token',
|
|
1470
1408
|
refresh_token: currentUser == null ? void 0 : currentUser.refreshToken
|
|
@@ -1479,13 +1417,6 @@ export default ((store, api, sharedActions) => {
|
|
|
1479
1417
|
isAuthenticated: true
|
|
1480
1418
|
});
|
|
1481
1419
|
} catch (e) {
|
|
1482
|
-
const retry = tenantId => __refreshTokenHostedSocialLogins({
|
|
1483
|
-
tenantId,
|
|
1484
|
-
isSsoEnforcementRetry: true
|
|
1485
|
-
});
|
|
1486
|
-
if (await __handleSsoEnforcementRefreshError(e, isSsoEnforcementRetry, retry)) {
|
|
1487
|
-
return;
|
|
1488
|
-
}
|
|
1489
1420
|
contextHolder.setAccessToken(null);
|
|
1490
1421
|
contextHolder.setUser(null);
|
|
1491
1422
|
actions.setAuthState({
|
|
@@ -1495,10 +1426,7 @@ export default ((store, api, sharedActions) => {
|
|
|
1495
1426
|
}
|
|
1496
1427
|
};
|
|
1497
1428
|
/** @private */
|
|
1498
|
-
const __refreshTokenEmbeddedSocialLogins = async ({
|
|
1499
|
-
tenantId,
|
|
1500
|
-
isSsoEnforcementRetry = false
|
|
1501
|
-
} = {}) => {
|
|
1429
|
+
const __refreshTokenEmbeddedSocialLogins = async () => {
|
|
1502
1430
|
try {
|
|
1503
1431
|
const {
|
|
1504
1432
|
routes,
|
|
@@ -1509,7 +1437,7 @@ export default ((store, api, sharedActions) => {
|
|
|
1509
1437
|
user,
|
|
1510
1438
|
tenants = [],
|
|
1511
1439
|
activeTenant
|
|
1512
|
-
} = await refreshTokenWithRetry(() => api.auth.refreshTokenV3(
|
|
1440
|
+
} = await refreshTokenWithRetry(() => api.auth.refreshTokenV3());
|
|
1513
1441
|
if (isMfaRequired(user, store.root.appName)) {
|
|
1514
1442
|
const mfaRequiredState = await actions.getMfaRequiredState(user);
|
|
1515
1443
|
actions.setAuthState(mfaRequiredState);
|
|
@@ -1559,13 +1487,6 @@ export default ((store, api, sharedActions) => {
|
|
|
1559
1487
|
}
|
|
1560
1488
|
}
|
|
1561
1489
|
} catch (e) {
|
|
1562
|
-
const retry = tenantId => __refreshTokenEmbeddedSocialLogins({
|
|
1563
|
-
tenantId,
|
|
1564
|
-
isSsoEnforcementRetry: true
|
|
1565
|
-
});
|
|
1566
|
-
if (await __handleSsoEnforcementRefreshError(e, isSsoEnforcementRetry, retry)) {
|
|
1567
|
-
return;
|
|
1568
|
-
}
|
|
1569
1490
|
contextHolder.setAccessToken(null);
|
|
1570
1491
|
contextHolder.setUser(null);
|
|
1571
1492
|
actions.setAuthState({
|
|
@@ -1612,7 +1533,6 @@ export default ((store, api, sharedActions) => {
|
|
|
1612
1533
|
resetBreachedPassword,
|
|
1613
1534
|
refreshTokenForSocialLogins,
|
|
1614
1535
|
// protected
|
|
1615
|
-
__refreshToken
|
|
1616
|
-
__redirectToSsoForTenant
|
|
1536
|
+
__refreshToken
|
|
1617
1537
|
}, hostedLoginAuthorizeActions(store, api, sharedActions), afterAuthNavigationActions(store, api, sharedActions), handleVerifyMFAResponseActions(store, api, sharedActions), mfaRequiredStateActions(store, api, sharedActions), mfaWithAuthenticatorActions(store, api, sharedActions), mfaWithEmailCodeActions(store, api, sharedActions), mfaWithSMSActions(store, api, sharedActions), mfaWithWebAuthnActions(store, api, sharedActions));
|
|
1618
1538
|
});
|
|
@@ -6,5 +6,6 @@
|
|
|
6
6
|
import { AuthStrategyEnum } from '@frontegg/rest-api';
|
|
7
7
|
import { LoginStep } from './interfaces';
|
|
8
8
|
import { AuthPageRoutes } from '../interfaces';
|
|
9
|
+
export declare const defaultOnRedirectTo: () => undefined;
|
|
9
10
|
export declare const authStrategyLoginStepMap: Record<Exclude<AuthStrategyEnum, AuthStrategyEnum.NoLocalAuthentication | AuthStrategyEnum.WebAuthN>, LoginStep>;
|
|
10
11
|
export declare const defaultFronteggRoutes: AuthPageRoutes;
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { AuthStrategyEnum } from '@frontegg/rest-api';
|
|
7
7
|
import { LoginStep } from './interfaces';
|
|
8
|
+
export const defaultOnRedirectTo = () => void 0;
|
|
8
9
|
export const authStrategyLoginStepMap = {
|
|
9
10
|
[AuthStrategyEnum.Code]: LoginStep.loginWithOtc,
|
|
10
11
|
[AuthStrategyEnum.EmailAndPassword]: LoginStep.loginWithPassword,
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { initialState } from './state';
|
|
2
|
-
import { deepResetState
|
|
3
|
-
import {
|
|
4
|
-
import { FRONTEGG_PENDING_SWITCH_TENANT } from '../../constants';
|
|
2
|
+
import { deepResetState } from '../../helpers';
|
|
3
|
+
import { getCurrentUserTenantsFunction } from '@frontegg/rest-api';
|
|
5
4
|
export default ((store, api, sharedActions) => {
|
|
6
5
|
const actions = sharedActions;
|
|
7
6
|
const setTenantsState = state => {
|
|
@@ -52,15 +51,6 @@ export default ((store, api, sharedActions) => {
|
|
|
52
51
|
}) : actions.setAuthState({
|
|
53
52
|
isLoading: false
|
|
54
53
|
});
|
|
55
|
-
const [isEnforceSsoOnTenantAccessEnabled] = FeatureFlags.getFeatureFlags([ENFORCE_SSO_ON_TENANT_ACCESS_FF], store.root.appName);
|
|
56
|
-
// a switch re-run after coming back from SSO doesn't send the user to SSO again
|
|
57
|
-
const isPendingSwitchRerun = window.sessionStorage.getItem(FRONTEGG_PENDING_SWITCH_TENANT) === tenantId;
|
|
58
|
-
if (isEnforceSsoOnTenantAccessEnabled && isSsoEnforcementError(e) && e.errorContext.ssoRequired && !isPendingSwitchRerun) {
|
|
59
|
-
// saved to finish the switch after the SSO login, which may land in another tenant
|
|
60
|
-
window.sessionStorage.setItem(FRONTEGG_PENDING_SWITCH_TENANT, tenantId);
|
|
61
|
-
await actions.__redirectToSsoForTenant(e.errorContext);
|
|
62
|
-
return;
|
|
63
|
-
}
|
|
64
54
|
callback == null ? void 0 : callback(false, e);
|
|
65
55
|
}
|
|
66
56
|
};
|
package/auth/index.js
CHANGED
|
@@ -37,7 +37,7 @@ import { buildTeamActions, createTeamState } from './TeamState';
|
|
|
37
37
|
import { buildTenantsActions, createTenantsState } from './TenantsState';
|
|
38
38
|
import { buildUsernamesActions, createUsernamesState } from './UsernamesState';
|
|
39
39
|
import { buildUserEmailPolicyActions, createUserEmailPolicyState } from './UsersEmailsPolicyState';
|
|
40
|
-
import { defaultFronteggRoutes } from './LoginState/consts';
|
|
40
|
+
import { defaultFronteggRoutes, defaultOnRedirectTo } from './LoginState/consts';
|
|
41
41
|
import { deepResetState, isProxy } from '../helpers';
|
|
42
42
|
import { buildEntitlementsActions } from './Entitlements';
|
|
43
43
|
import { createProxy } from '../toolkit/proxy';
|
|
@@ -91,7 +91,7 @@ export const createAuthState = _overrideState => {
|
|
|
91
91
|
overrideState = _objectWithoutPropertiesLoose(_ref, _excluded);
|
|
92
92
|
return createProxy(_extends({
|
|
93
93
|
routes: _extends({}, defaultFronteggRoutes, routes),
|
|
94
|
-
onRedirectTo:
|
|
94
|
+
onRedirectTo: defaultOnRedirectTo,
|
|
95
95
|
isAuthenticated: false,
|
|
96
96
|
isLoading: true,
|
|
97
97
|
isSSOAuth: false,
|
package/constants.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
export declare const FRONTEGG_AFTER_AUTH_REDIRECT_URL = "FRONTEGG_AFTER_AUTH_REDIRECT_URL";
|
|
2
|
-
export declare const FRONTEGG_PENDING_SWITCH_TENANT = "FRONTEGG_PENDING_SWITCH_TENANT";
|
|
3
2
|
export declare const HOSTED_LOGIN_VERIFIER_KEY = "HOSTED_LOGIN_VERIFIER_KEY";
|
|
4
3
|
export declare const DEFAULT_RETRY_CONFIG: {
|
|
5
4
|
retryCount: number;
|
package/constants.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
export const FRONTEGG_AFTER_AUTH_REDIRECT_URL = 'FRONTEGG_AFTER_AUTH_REDIRECT_URL';
|
|
2
|
-
export const FRONTEGG_PENDING_SWITCH_TENANT = 'FRONTEGG_PENDING_SWITCH_TENANT';
|
|
3
2
|
export const HOSTED_LOGIN_VERIFIER_KEY = 'HOSTED_LOGIN_VERIFIER_KEY';
|
|
4
3
|
export const DEFAULT_RETRY_CONFIG = {
|
|
5
4
|
retryCount: 3
|
package/helpers/handlers.d.ts
CHANGED
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
import { FronteggApiError
|
|
1
|
+
import { FronteggApiError } from '@frontegg/rest-api';
|
|
2
2
|
export declare const isFronteggApiError: (error: unknown | Error | FronteggApiError) => error is FronteggApiError;
|
|
3
|
-
export declare const isSsoEnforcementError: (error: unknown) => error is FronteggApiError & {
|
|
4
|
-
errorContext: SsoEnforcementErrorContext;
|
|
5
|
-
};
|
|
6
3
|
export declare const isError: (error: any) => error is Error;
|
|
7
4
|
export declare const errorHandler: <T>(error: unknown, fallback?: T) => FronteggApiError | T;
|
package/helpers/handlers.js
CHANGED
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
import { FronteggApiError, GENERIC_ERROR_MESSAGE, GENERIC_ERROR_CODE
|
|
1
|
+
import { FronteggApiError, GENERIC_ERROR_MESSAGE, GENERIC_ERROR_CODE } from '@frontegg/rest-api';
|
|
2
2
|
export const isFronteggApiError = error => Boolean(error == null ? void 0 : error.statusCode);
|
|
3
|
-
|
|
4
|
-
// ER-01079 (disabled user / expired tenant) is not this: it still logs out
|
|
5
|
-
export const isSsoEnforcementError = error => isFronteggApiError(error) && error.errorCode === SSO_REQUIRED_FOR_TENANT_ERROR_CODE;
|
|
6
3
|
export const isError = error => {
|
|
7
4
|
if (error instanceof Error) {
|
|
8
5
|
return true;
|
package/index.js
CHANGED
|
@@ -71,9 +71,5 @@ declare const _default: (store: FronteggState, api: RestApi, sharedActions: Shar
|
|
|
71
71
|
resetBreachedPassword: (payload: import("dist/@frontegg/rest-api").IForgotPassword) => Promise<void>;
|
|
72
72
|
refreshTokenForSocialLogins: () => Promise<void>;
|
|
73
73
|
__refreshToken: () => Promise<void>;
|
|
74
|
-
__redirectToSsoForTenant: ({ tenantId, address }: {
|
|
75
|
-
tenantId: string;
|
|
76
|
-
address: string;
|
|
77
|
-
}) => Promise<void>;
|
|
78
74
|
};
|
|
79
75
|
export default _default;
|
|
@@ -6,7 +6,6 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
6
6
|
});
|
|
7
7
|
exports.default = void 0;
|
|
8
8
|
var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
|
|
9
|
-
var _restApi = require("@frontegg/rest-api");
|
|
10
9
|
var _helpers = require("../helpers");
|
|
11
10
|
var _tenantSelect = require("../helpers/tenantSelect");
|
|
12
11
|
var _constants = require("../../../constants");
|
|
@@ -64,33 +63,6 @@ var _default = (store, api, sharedActions) => {
|
|
|
64
63
|
}, additionalUpdate));
|
|
65
64
|
}
|
|
66
65
|
|
|
67
|
-
/**
|
|
68
|
-
* A switch that needed SSO saved its target tenant (in this tab) before sending the user to SSO.
|
|
69
|
-
* Once logged in again, switch to it once if the login landed in another tenant.
|
|
70
|
-
* @returns true when the switch left the user without a session (MFA step for the target tenant, or logout)
|
|
71
|
-
*/
|
|
72
|
-
async function switchToPendingSsoTenant() {
|
|
73
|
-
var _store$auth$user, _store$auth$user2;
|
|
74
|
-
const [isEnforceSsoOnTenantAccessEnabled] = _restApi.FeatureFlags.getFeatureFlags([_restApi.ENFORCE_SSO_ON_TENANT_ACCESS_FF], store.root.appName);
|
|
75
|
-
const pendingTenantId = window.sessionStorage.getItem(_constants.FRONTEGG_PENDING_SWITCH_TENANT);
|
|
76
|
-
if (!isEnforceSsoOnTenantAccessEnabled || !pendingTenantId || !((_store$auth$user = store.auth.user) != null && _store$auth$user.accessToken)) {
|
|
77
|
-
return false;
|
|
78
|
-
}
|
|
79
|
-
if (store.auth.user.tenantId === pendingTenantId) {
|
|
80
|
-
window.sessionStorage.removeItem(_constants.FRONTEGG_PENDING_SWITCH_TENANT);
|
|
81
|
-
return false;
|
|
82
|
-
}
|
|
83
|
-
// silentReload keeps switchingTenant set, so the switch's own refresh doesn't re-run this navigation
|
|
84
|
-
await actions.switchTenant({
|
|
85
|
-
tenantId: pendingTenantId,
|
|
86
|
-
silentReload: true,
|
|
87
|
-
keepLoginState: true
|
|
88
|
-
});
|
|
89
|
-
// removed only after the switch: a refused re-run must not send the user to SSO again
|
|
90
|
-
window.sessionStorage.removeItem(_constants.FRONTEGG_PENDING_SWITCH_TENANT);
|
|
91
|
-
return !((_store$auth$user2 = store.auth.user) != null && _store$auth$user2.accessToken);
|
|
92
|
-
}
|
|
93
|
-
|
|
94
66
|
/**
|
|
95
67
|
* @param customLoginAuthenticatedUrl custom login authenticated url if exists
|
|
96
68
|
* @returns the authenticated url to redirect to after auth navigation
|
|
@@ -115,15 +87,19 @@ var _default = (store, api, sharedActions) => {
|
|
|
115
87
|
logoutUrl,
|
|
116
88
|
socialLoginCallbackUrl,
|
|
117
89
|
activateUrl,
|
|
118
|
-
activateWithOTCUrl
|
|
90
|
+
activateWithOTCUrl,
|
|
91
|
+
oidcRedirectUrl
|
|
119
92
|
} = routes;
|
|
120
93
|
let finalUrl = urlFromLocalStorage;
|
|
121
94
|
if (!finalUrl || [loginUrl, logoutUrl, socialLoginCallbackUrl, activateUrl, activateWithOTCUrl].includes(finalUrl)) {
|
|
122
95
|
finalUrl = authenticatedUrl;
|
|
123
96
|
}
|
|
97
|
+
|
|
98
|
+
// The OIDC callback's query is the IdP's code and state; the user's own query was saved with the URL.
|
|
99
|
+
const isOidcCallback = !!oidcRedirectUrl && window.location.pathname.endsWith(oidcRedirectUrl);
|
|
124
100
|
const redirectUrl = (0, _helpers.getRedirectUrl)({
|
|
125
101
|
authenticatedUrl: finalUrl,
|
|
126
|
-
includeQueryParam,
|
|
102
|
+
includeQueryParam: includeQueryParam && !isOidcCallback,
|
|
127
103
|
enforceRedirectToSameSite,
|
|
128
104
|
allowedRedirectOrigins
|
|
129
105
|
});
|
|
@@ -194,7 +170,7 @@ var _default = (store, api, sharedActions) => {
|
|
|
194
170
|
* until the resolved-guard, the LD flag, and the option all pass.
|
|
195
171
|
*/
|
|
196
172
|
const shouldRouteToChooseTenant = async () => {
|
|
197
|
-
var _store$auth$tenantSel, _store$auth$
|
|
173
|
+
var _store$auth$tenantSel, _store$auth$user, _store$auth$user$act, _store$auth$tenantsSt;
|
|
198
174
|
const loginState = store.auth.loginState;
|
|
199
175
|
// Guard first so re-entry after the choice is resolved finalizes without re-reading the flag.
|
|
200
176
|
if (loginState.tenantChoiceResolved) {
|
|
@@ -210,7 +186,7 @@ var _default = (store, api, sharedActions) => {
|
|
|
210
186
|
return false; // feature off — never read tenant data
|
|
211
187
|
}
|
|
212
188
|
|
|
213
|
-
const isImpersonation = !!((_store$auth$
|
|
189
|
+
const isImpersonation = !!((_store$auth$user = store.auth.user) != null && (_store$auth$user$act = _store$auth$user.act) != null && _store$auth$user$act.sub);
|
|
214
190
|
if (isImpersonation) {
|
|
215
191
|
return false;
|
|
216
192
|
}
|
|
@@ -288,14 +264,6 @@ var _default = (store, api, sharedActions) => {
|
|
|
288
264
|
}
|
|
289
265
|
try {
|
|
290
266
|
var _window4, _payload$preventRedir;
|
|
291
|
-
const isSessionLostInPendingSwitch = await switchToPendingSsoTenant();
|
|
292
|
-
if (isSessionLostInPendingSwitch) {
|
|
293
|
-
// MFA for the target tenant or a failed refresh: continue on the login page
|
|
294
|
-
store.auth.onRedirectTo(store.auth.routes.loginUrl, {
|
|
295
|
-
preserveQueryParams: true
|
|
296
|
-
});
|
|
297
|
-
return;
|
|
298
|
-
}
|
|
299
267
|
const {
|
|
300
268
|
customLoginAuthenticatedUrl,
|
|
301
269
|
stepUpUrl
|
|
@@ -8,7 +8,6 @@ exports.default = void 0;
|
|
|
8
8
|
var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
|
|
9
9
|
var _helpers = require("../../../helpers");
|
|
10
10
|
var _constants = require("../../../constants");
|
|
11
|
-
var _restApi = require("@frontegg/rest-api");
|
|
12
11
|
var _helpers2 = require("../helpers");
|
|
13
12
|
var _helpers3 = require("../../helpers");
|
|
14
13
|
var _consts = require("../../StepUpState/consts");
|
|
@@ -87,10 +86,7 @@ var _default = (store, api, sharedActions) => {
|
|
|
87
86
|
code_challenge_method: 'S256',
|
|
88
87
|
nonce
|
|
89
88
|
}, additionalParams);
|
|
90
|
-
|
|
91
|
-
// the tenant asked for (SSO for a refused switch or refresh) wins over the resolved and the page's tenant
|
|
92
|
-
const isTenantRequested = isEnforceSsoOnTenantAccessEnabled && !!(additionalParams != null && additionalParams.tenantId);
|
|
93
|
-
if (context.tenantResolver && !isTenantRequested) {
|
|
89
|
+
if (context.tenantResolver) {
|
|
94
90
|
var _context$tenantResolv;
|
|
95
91
|
const resolvedTenantResult = await ((_context$tenantResolv = context.tenantResolver) == null ? void 0 : _context$tenantResolv.call(context));
|
|
96
92
|
if (resolvedTenantResult != null && resolvedTenantResult.tenant) {
|
|
@@ -98,7 +94,7 @@ var _default = (store, api, sharedActions) => {
|
|
|
98
94
|
}
|
|
99
95
|
}
|
|
100
96
|
const tenantId = (0, _helpers2.getSearchParam)(_helpers2.TENANT_ID_PARAM_KEY);
|
|
101
|
-
if (tenantId
|
|
97
|
+
if (tenantId) {
|
|
102
98
|
params['tenantId'] = tenantId;
|
|
103
99
|
}
|
|
104
100
|
if (_toolkit.FronteggNativeModule.isAvailable('closeWindow')) {
|
|
@@ -44,71 +44,14 @@ const _excluded = ["callback", "error"],
|
|
|
44
44
|
_excluded13 = ["callback"],
|
|
45
45
|
_excluded14 = ["callback"],
|
|
46
46
|
_excluded15 = ["callback"];
|
|
47
|
+
const SSO_REDIRECT_DELAY_MS = 2000;
|
|
48
|
+
const isUsableRedirect = onRedirectTo => typeof onRedirectTo === 'function' && onRedirectTo !== _consts2.defaultOnRedirectTo;
|
|
47
49
|
var _default = (store, api, sharedActions) => {
|
|
48
50
|
const actions = sharedActions;
|
|
49
51
|
const contextHolder = _restApi.ContextHolder.for(store.root.appName);
|
|
50
52
|
|
|
51
|
-
/**
|
|
52
|
-
* Sends the user to log in through the tenant's SSO and back to the current page afterwards.
|
|
53
|
-
* @protected
|
|
54
|
-
*/
|
|
55
|
-
const __redirectToSsoForTenant = async ({
|
|
56
|
-
tenantId,
|
|
57
|
-
address
|
|
58
|
-
}) => {
|
|
59
|
-
// on the login page (tenant chooser) keep the destination the login already saved
|
|
60
|
-
if (!window.location.pathname.endsWith(store.auth.routes.loginUrl)) {
|
|
61
|
-
(0, _helpers3.setAfterAuthRedirectUrlForStepUp)();
|
|
62
|
-
}
|
|
63
|
-
if (store.auth.hostedLoginBox) {
|
|
64
|
-
await actions.requestHostedLoginAuthorize({
|
|
65
|
-
prompt: 'login',
|
|
66
|
-
tenantId
|
|
67
|
-
});
|
|
68
|
-
return;
|
|
69
|
-
}
|
|
70
|
-
store.auth.onRedirectTo(address, {
|
|
71
|
-
refresh: true
|
|
72
|
-
});
|
|
73
|
-
};
|
|
74
|
-
/**
|
|
75
|
-
* Handles a token refresh refused because the tenant requires SSO.
|
|
76
|
-
* ssoRequired: true sends the user to SSO. ssoRequired: false renews once more for the tenant of the
|
|
77
|
-
* current token, which keeps the session.
|
|
78
|
-
* @returns true when handled, false when the caller should log out
|
|
79
|
-
* @private
|
|
80
|
-
*/
|
|
81
|
-
const __handleSsoEnforcementRefreshError = async (e, isSsoEnforcementRetry, refreshForTenant) => {
|
|
82
|
-
var _store$auth$user;
|
|
83
|
-
const [isEnforceSsoOnTenantAccessEnabled] = _restApi.FeatureFlags.getFeatureFlags([_restApi.ENFORCE_SSO_ON_TENANT_ACCESS_FF], store.root.appName);
|
|
84
|
-
if (!isEnforceSsoOnTenantAccessEnabled || !(0, _helpers.isSsoEnforcementError)(e)) {
|
|
85
|
-
return false;
|
|
86
|
-
}
|
|
87
|
-
const {
|
|
88
|
-
errorContext
|
|
89
|
-
} = e;
|
|
90
|
-
// the switch re-run after coming back from SSO keeps the session instead of sending the user to SSO again
|
|
91
|
-
const isPendingSwitchRerun = !!window.sessionStorage.getItem(_constants.FRONTEGG_PENDING_SWITCH_TENANT);
|
|
92
|
-
if (errorContext.ssoRequired && !isPendingSwitchRerun) {
|
|
93
|
-
await __redirectToSsoForTenant(errorContext);
|
|
94
|
-
return true;
|
|
95
|
-
}
|
|
96
|
-
if (isSsoEnforcementRetry) {
|
|
97
|
-
return false;
|
|
98
|
-
}
|
|
99
|
-
const currentTenantId = (_store$auth$user = store.auth.user) == null ? void 0 : _store$auth$user.tenantId;
|
|
100
|
-
if (currentTenantId && contextHolder.isSessionPerTenantEnabled()) {
|
|
101
|
-
(0, _restApi.setTabTenantInSessionStorage)(currentTenantId);
|
|
102
|
-
}
|
|
103
|
-
await refreshForTenant(currentTenantId);
|
|
104
|
-
return true;
|
|
105
|
-
};
|
|
106
|
-
|
|
107
53
|
/** @private */
|
|
108
|
-
const __refreshTokenHosted = async ({
|
|
109
|
-
tenantId,
|
|
110
|
-
isSsoEnforcementRetry = false
|
|
111
|
-
} = {}) => {
|
|
54
|
+
const __refreshTokenHosted = async () => {
|
|
112
55
|
const user = store.auth.user;
|
|
113
56
|
if (!(user != null && user.refreshToken)) {
|
|
114
57
|
contextHolder.setAccessToken(null);
|
|
@@ -120,7 +63,7 @@ var _default = (store, api, sharedActions) => {
|
|
|
120
63
|
return;
|
|
121
64
|
}
|
|
122
65
|
try {
|
|
123
|
-
const tabTenantId =
|
|
66
|
+
const tabTenantId = (0, _restApi.getTabTenantFromSessionStorage)(store.root.appName);
|
|
124
67
|
const body = (0, _extends2.default)({
|
|
125
68
|
grant_type: 'refresh_token',
|
|
126
69
|
refresh_token: user == null ? void 0 : user.refreshToken
|
|
@@ -135,13 +78,6 @@ var _default = (store, api, sharedActions) => {
|
|
|
135
78
|
isAuthenticated: true
|
|
136
79
|
});
|
|
137
80
|
} catch (e) {
|
|
138
|
-
const retry = tenantId => __refreshTokenHosted({
|
|
139
|
-
tenantId,
|
|
140
|
-
isSsoEnforcementRetry: true
|
|
141
|
-
});
|
|
142
|
-
if (await __handleSsoEnforcementRefreshError(e, isSsoEnforcementRetry, retry)) {
|
|
143
|
-
return;
|
|
144
|
-
}
|
|
145
81
|
contextHolder.setAccessToken(null);
|
|
146
82
|
contextHolder.setUser(null);
|
|
147
83
|
actions.setAuthState({
|
|
@@ -161,10 +97,7 @@ var _default = (store, api, sharedActions) => {
|
|
|
161
97
|
};
|
|
162
98
|
|
|
163
99
|
/** @private */
|
|
164
|
-
const __refreshTokenEmbedded = async ({
|
|
165
|
-
tenantId,
|
|
166
|
-
isSsoEnforcementRetry = false
|
|
167
|
-
} = {}) => {
|
|
100
|
+
const __refreshTokenEmbedded = async () => {
|
|
168
101
|
try {
|
|
169
102
|
const {
|
|
170
103
|
routes,
|
|
@@ -175,7 +108,7 @@ var _default = (store, api, sharedActions) => {
|
|
|
175
108
|
user,
|
|
176
109
|
tenants = [],
|
|
177
110
|
activeTenant
|
|
178
|
-
} = await (0, _helpers.refreshTokenWithRetry)(() => api.auth.refreshTokenV3(
|
|
111
|
+
} = await (0, _helpers.refreshTokenWithRetry)(() => api.auth.refreshTokenV3());
|
|
179
112
|
if ((0, _helpers3.isMfaRequired)(user, store.root.appName)) {
|
|
180
113
|
const mfaRequiredState = await actions.getMfaRequiredState(user);
|
|
181
114
|
actions.setAuthState(mfaRequiredState);
|
|
@@ -206,13 +139,6 @@ var _default = (store, api, sharedActions) => {
|
|
|
206
139
|
});
|
|
207
140
|
}
|
|
208
141
|
} catch (e) {
|
|
209
|
-
const retry = tenantId => __refreshTokenEmbedded({
|
|
210
|
-
tenantId,
|
|
211
|
-
isSsoEnforcementRetry: true
|
|
212
|
-
});
|
|
213
|
-
if (await __handleSsoEnforcementRefreshError(e, isSsoEnforcementRetry, retry)) {
|
|
214
|
-
return;
|
|
215
|
-
}
|
|
216
142
|
contextHolder.setAccessToken(null);
|
|
217
143
|
contextHolder.setUser(null);
|
|
218
144
|
actions.setAuthState({
|
|
@@ -223,9 +149,7 @@ var _default = (store, api, sharedActions) => {
|
|
|
223
149
|
};
|
|
224
150
|
|
|
225
151
|
/** @private */
|
|
226
|
-
const __refreshTokenWithNativeTokens = async ({
|
|
227
|
-
isSsoEnforcementRetry = false
|
|
228
|
-
} = {}) => {
|
|
152
|
+
const __refreshTokenWithNativeTokens = async () => {
|
|
229
153
|
try {
|
|
230
154
|
const authApi = api.auth;
|
|
231
155
|
const response = await (0, _helpers.refreshTokenWithRetry)(async () => {
|
|
@@ -239,13 +163,6 @@ var _default = (store, api, sharedActions) => {
|
|
|
239
163
|
isAuthenticated: true
|
|
240
164
|
});
|
|
241
165
|
} catch (e) {
|
|
242
|
-
// native tokens can't name a tenant: the retry relies on the tab tenant only
|
|
243
|
-
const retry = () => __refreshTokenWithNativeTokens({
|
|
244
|
-
isSsoEnforcementRetry: true
|
|
245
|
-
});
|
|
246
|
-
if (await __handleSsoEnforcementRefreshError(e, isSsoEnforcementRetry, retry)) {
|
|
247
|
-
return;
|
|
248
|
-
}
|
|
249
166
|
contextHolder.setAccessToken(null);
|
|
250
167
|
contextHolder.setUser(null);
|
|
251
168
|
actions.setAuthState({
|
|
@@ -279,9 +196,9 @@ var _default = (store, api, sharedActions) => {
|
|
|
279
196
|
* @private
|
|
280
197
|
*/
|
|
281
198
|
const __handleUnnecessaryEntitlementsUpdate = async updatedUser => {
|
|
282
|
-
var _store$auth$
|
|
199
|
+
var _store$auth$user;
|
|
283
200
|
// @ts-ignore TODO: fix entitlements state type
|
|
284
|
-
const oldEntitlements = (_store$auth$
|
|
201
|
+
const oldEntitlements = (_store$auth$user = store.auth.user) == null ? void 0 : _store$auth$user.entitlements;
|
|
285
202
|
if ((0, _toolkit.isEntitlementsDeeplyEqual)(oldEntitlements, updatedUser == null ? void 0 : updatedUser.entitlements)) {
|
|
286
203
|
// set the previous entitlements object
|
|
287
204
|
return (0, _extends2.default)({}, updatedUser, {
|
|
@@ -479,6 +396,29 @@ var _default = (store, api, sharedActions) => {
|
|
|
479
396
|
callback == null ? void 0 : callback();
|
|
480
397
|
}
|
|
481
398
|
};
|
|
399
|
+
|
|
400
|
+
// v6 parity (takeLeading): a preLogin called while another is in flight is dropped.
|
|
401
|
+
let preLoginInFlight = false;
|
|
402
|
+
let latestPreLoginAttempt = 0;
|
|
403
|
+
|
|
404
|
+
// Read on use: the login box installs onRedirectTo lazily, logout() clears it and the store default is a no-op.
|
|
405
|
+
const redirectToFullPage = url => {
|
|
406
|
+
const onRedirectTo = [store.auth.onRedirectTo, contextHolder.onRedirectTo].find(isUsableRedirect);
|
|
407
|
+
if (onRedirectTo) {
|
|
408
|
+
onRedirectTo(url, {
|
|
409
|
+
refresh: true
|
|
410
|
+
});
|
|
411
|
+
} else {
|
|
412
|
+
window.location.href = url;
|
|
413
|
+
}
|
|
414
|
+
};
|
|
415
|
+
const scheduleSsoRedirect = (ssoRedirectUrl, attempt) => {
|
|
416
|
+
setTimeout(() => {
|
|
417
|
+
if (attempt === latestPreLoginAttempt && store.auth.loginState.step === _interfaces.LoginStep.redirectToSSO) {
|
|
418
|
+
redirectToFullPage(ssoRedirectUrl);
|
|
419
|
+
}
|
|
420
|
+
}, SSO_REDIRECT_DELAY_MS);
|
|
421
|
+
};
|
|
482
422
|
const preLogin = async payload => {
|
|
483
423
|
const {
|
|
484
424
|
email,
|
|
@@ -487,11 +427,17 @@ var _default = (store, api, sharedActions) => {
|
|
|
487
427
|
invitationToken,
|
|
488
428
|
callback
|
|
489
429
|
} = payload;
|
|
430
|
+
if (preLoginInFlight) {
|
|
431
|
+
callback == null ? void 0 : callback();
|
|
432
|
+
return;
|
|
433
|
+
}
|
|
434
|
+
preLoginInFlight = true;
|
|
435
|
+
latestPreLoginAttempt += 1;
|
|
436
|
+
const attempt = latestPreLoginAttempt;
|
|
490
437
|
setLoginState({
|
|
491
438
|
loading: true
|
|
492
439
|
});
|
|
493
440
|
try {
|
|
494
|
-
const onRedirectTo = store.auth.onRedirectTo;
|
|
495
441
|
const tenantId = (0, _helpers2.getSearchParam)(_helpers2.TENANT_ID_PARAM_KEY);
|
|
496
442
|
const preLoginResult = await api.auth.preLoginV2((0, _extends2.default)({}, email ? {
|
|
497
443
|
email
|
|
@@ -512,9 +458,7 @@ var _default = (store, api, sharedActions) => {
|
|
|
512
458
|
setLoginState({
|
|
513
459
|
loading: false
|
|
514
460
|
});
|
|
515
|
-
|
|
516
|
-
refresh: true
|
|
517
|
-
});
|
|
461
|
+
redirectToFullPage(address);
|
|
518
462
|
return;
|
|
519
463
|
}
|
|
520
464
|
let ssoRedirectUrl = address;
|
|
@@ -537,11 +481,7 @@ var _default = (store, api, sharedActions) => {
|
|
|
537
481
|
loading: false,
|
|
538
482
|
ssoRedirectUrl
|
|
539
483
|
});
|
|
540
|
-
|
|
541
|
-
onRedirectTo(ssoRedirectUrl, {
|
|
542
|
-
refresh: true
|
|
543
|
-
});
|
|
544
|
-
}, 2000);
|
|
484
|
+
scheduleSsoRedirect(ssoRedirectUrl, attempt);
|
|
545
485
|
}
|
|
546
486
|
} else {
|
|
547
487
|
await ssoPreloginFailed((0, _extends2.default)({}, username ? {
|
|
@@ -565,6 +505,8 @@ var _default = (store, api, sharedActions) => {
|
|
|
565
505
|
invitationToken,
|
|
566
506
|
error: e
|
|
567
507
|
}));
|
|
508
|
+
} finally {
|
|
509
|
+
preLoginInFlight = false;
|
|
568
510
|
}
|
|
569
511
|
};
|
|
570
512
|
const postLogin = async payload => {
|
|
@@ -751,7 +693,6 @@ var _default = (store, api, sharedActions) => {
|
|
|
751
693
|
if (!keepHostedOAuthState) {
|
|
752
694
|
(0, _oauthStorage.clearHostedOAuthState)();
|
|
753
695
|
}
|
|
754
|
-
window.sessionStorage.removeItem(_constants.FRONTEGG_PENDING_SWITCH_TENANT);
|
|
755
696
|
};
|
|
756
697
|
const logout = async payload => {
|
|
757
698
|
const hostedLoginBox = store.auth.hostedLoginBox;
|
|
@@ -1454,10 +1395,7 @@ var _default = (store, api, sharedActions) => {
|
|
|
1454
1395
|
};
|
|
1455
1396
|
|
|
1456
1397
|
/** @private */
|
|
1457
|
-
const __refreshTokenHostedSocialLogins = async ({
|
|
1458
|
-
tenantId,
|
|
1459
|
-
isSsoEnforcementRetry = false
|
|
1460
|
-
} = {}) => {
|
|
1398
|
+
const __refreshTokenHostedSocialLogins = async () => {
|
|
1461
1399
|
const {
|
|
1462
1400
|
user: currentUser
|
|
1463
1401
|
} = store.auth;
|
|
@@ -1471,7 +1409,7 @@ var _default = (store, api, sharedActions) => {
|
|
|
1471
1409
|
return;
|
|
1472
1410
|
}
|
|
1473
1411
|
try {
|
|
1474
|
-
const tabTenantId =
|
|
1412
|
+
const tabTenantId = (0, _restApi.getTabTenantFromSessionStorage)(store.root.appName);
|
|
1475
1413
|
const body = (0, _extends2.default)({
|
|
1476
1414
|
grant_type: 'refresh_token',
|
|
1477
1415
|
refresh_token: currentUser == null ? void 0 : currentUser.refreshToken
|
|
@@ -1486,13 +1424,6 @@ var _default = (store, api, sharedActions) => {
|
|
|
1486
1424
|
isAuthenticated: true
|
|
1487
1425
|
});
|
|
1488
1426
|
} catch (e) {
|
|
1489
|
-
const retry = tenantId => __refreshTokenHostedSocialLogins({
|
|
1490
|
-
tenantId,
|
|
1491
|
-
isSsoEnforcementRetry: true
|
|
1492
|
-
});
|
|
1493
|
-
if (await __handleSsoEnforcementRefreshError(e, isSsoEnforcementRetry, retry)) {
|
|
1494
|
-
return;
|
|
1495
|
-
}
|
|
1496
1427
|
contextHolder.setAccessToken(null);
|
|
1497
1428
|
contextHolder.setUser(null);
|
|
1498
1429
|
actions.setAuthState({
|
|
@@ -1502,10 +1433,7 @@ var _default = (store, api, sharedActions) => {
|
|
|
1502
1433
|
}
|
|
1503
1434
|
};
|
|
1504
1435
|
/** @private */
|
|
1505
|
-
const __refreshTokenEmbeddedSocialLogins = async ({
|
|
1506
|
-
tenantId,
|
|
1507
|
-
isSsoEnforcementRetry = false
|
|
1508
|
-
} = {}) => {
|
|
1436
|
+
const __refreshTokenEmbeddedSocialLogins = async () => {
|
|
1509
1437
|
try {
|
|
1510
1438
|
const {
|
|
1511
1439
|
routes,
|
|
@@ -1516,7 +1444,7 @@ var _default = (store, api, sharedActions) => {
|
|
|
1516
1444
|
user,
|
|
1517
1445
|
tenants = [],
|
|
1518
1446
|
activeTenant
|
|
1519
|
-
} = await (0, _helpers.refreshTokenWithRetry)(() => api.auth.refreshTokenV3(
|
|
1447
|
+
} = await (0, _helpers.refreshTokenWithRetry)(() => api.auth.refreshTokenV3());
|
|
1520
1448
|
if ((0, _helpers3.isMfaRequired)(user, store.root.appName)) {
|
|
1521
1449
|
const mfaRequiredState = await actions.getMfaRequiredState(user);
|
|
1522
1450
|
actions.setAuthState(mfaRequiredState);
|
|
@@ -1566,13 +1494,6 @@ var _default = (store, api, sharedActions) => {
|
|
|
1566
1494
|
}
|
|
1567
1495
|
}
|
|
1568
1496
|
} catch (e) {
|
|
1569
|
-
const retry = tenantId => __refreshTokenEmbeddedSocialLogins({
|
|
1570
|
-
tenantId,
|
|
1571
|
-
isSsoEnforcementRetry: true
|
|
1572
|
-
});
|
|
1573
|
-
if (await __handleSsoEnforcementRefreshError(e, isSsoEnforcementRetry, retry)) {
|
|
1574
|
-
return;
|
|
1575
|
-
}
|
|
1576
1497
|
contextHolder.setAccessToken(null);
|
|
1577
1498
|
contextHolder.setUser(null);
|
|
1578
1499
|
actions.setAuthState({
|
|
@@ -1619,8 +1540,7 @@ var _default = (store, api, sharedActions) => {
|
|
|
1619
1540
|
resetBreachedPassword,
|
|
1620
1541
|
refreshTokenForSocialLogins,
|
|
1621
1542
|
// protected
|
|
1622
|
-
__refreshToken
|
|
1623
|
-
__redirectToSsoForTenant
|
|
1543
|
+
__refreshToken
|
|
1624
1544
|
}, (0, _hostedLoginAuthorize.default)(store, api, sharedActions), (0, _afterAuthNavigation.default)(store, api, sharedActions), (0, _handleVerifyMFAResponse.default)(store, api, sharedActions), (0, _mfaRequiredState.default)(store, api, sharedActions), (0, _mfaWithAuthenticator.default)(store, api, sharedActions), (0, _mfaWithEmailCode.default)(store, api, sharedActions), (0, _mfaWithSMS.default)(store, api, sharedActions), (0, _mfaWithWebAuthn.default)(store, api, sharedActions));
|
|
1625
1545
|
};
|
|
1626
1546
|
exports.default = _default;
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.defaultFronteggRoutes = exports.authStrategyLoginStepMap = void 0;
|
|
6
|
+
exports.defaultOnRedirectTo = exports.defaultFronteggRoutes = exports.authStrategyLoginStepMap = void 0;
|
|
7
7
|
var _restApi = require("@frontegg/rest-api");
|
|
8
8
|
var _interfaces = require("./interfaces");
|
|
9
9
|
/**
|
|
@@ -12,6 +12,8 @@ var _interfaces = require("./interfaces");
|
|
|
12
12
|
* please don't import from redux or from other files that import from redux
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
|
+
const defaultOnRedirectTo = () => void 0;
|
|
16
|
+
exports.defaultOnRedirectTo = defaultOnRedirectTo;
|
|
15
17
|
const authStrategyLoginStepMap = {
|
|
16
18
|
[_restApi.AuthStrategyEnum.Code]: _interfaces.LoginStep.loginWithOtc,
|
|
17
19
|
[_restApi.AuthStrategyEnum.EmailAndPassword]: _interfaces.LoginStep.loginWithPassword,
|
|
@@ -7,7 +7,6 @@ exports.default = void 0;
|
|
|
7
7
|
var _state = require("./state");
|
|
8
8
|
var _helpers = require("../../helpers");
|
|
9
9
|
var _restApi = require("@frontegg/rest-api");
|
|
10
|
-
var _constants = require("../../constants");
|
|
11
10
|
var _default = (store, api, sharedActions) => {
|
|
12
11
|
const actions = sharedActions;
|
|
13
12
|
const setTenantsState = state => {
|
|
@@ -58,15 +57,6 @@ var _default = (store, api, sharedActions) => {
|
|
|
58
57
|
}) : actions.setAuthState({
|
|
59
58
|
isLoading: false
|
|
60
59
|
});
|
|
61
|
-
const [isEnforceSsoOnTenantAccessEnabled] = _restApi.FeatureFlags.getFeatureFlags([_restApi.ENFORCE_SSO_ON_TENANT_ACCESS_FF], store.root.appName);
|
|
62
|
-
// a switch re-run after coming back from SSO doesn't send the user to SSO again
|
|
63
|
-
const isPendingSwitchRerun = window.sessionStorage.getItem(_constants.FRONTEGG_PENDING_SWITCH_TENANT) === tenantId;
|
|
64
|
-
if (isEnforceSsoOnTenantAccessEnabled && (0, _helpers.isSsoEnforcementError)(e) && e.errorContext.ssoRequired && !isPendingSwitchRerun) {
|
|
65
|
-
// saved to finish the switch after the SSO login, which may land in another tenant
|
|
66
|
-
window.sessionStorage.setItem(_constants.FRONTEGG_PENDING_SWITCH_TENANT, tenantId);
|
|
67
|
-
await actions.__redirectToSsoForTenant(e.errorContext);
|
|
68
|
-
return;
|
|
69
|
-
}
|
|
70
60
|
callback == null ? void 0 : callback(false, e);
|
|
71
61
|
}
|
|
72
62
|
};
|
package/node/auth/index.js
CHANGED
|
@@ -559,7 +559,7 @@ const createAuthState = _overrideState => {
|
|
|
559
559
|
overrideState = (0, _objectWithoutPropertiesLoose2.default)(_ref, _excluded);
|
|
560
560
|
return (0, _proxy.createProxy)((0, _extends2.default)({
|
|
561
561
|
routes: (0, _extends2.default)({}, _consts.defaultFronteggRoutes, routes),
|
|
562
|
-
onRedirectTo:
|
|
562
|
+
onRedirectTo: _consts.defaultOnRedirectTo,
|
|
563
563
|
isAuthenticated: false,
|
|
564
564
|
isLoading: true,
|
|
565
565
|
isSSOAuth: false,
|
package/node/constants.js
CHANGED
|
@@ -5,11 +5,10 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
});
|
|
6
6
|
var _exportNames = {
|
|
7
7
|
FRONTEGG_AFTER_AUTH_REDIRECT_URL: true,
|
|
8
|
-
FRONTEGG_PENDING_SWITCH_TENANT: true,
|
|
9
8
|
HOSTED_LOGIN_VERIFIER_KEY: true,
|
|
10
9
|
DEFAULT_RETRY_CONFIG: true
|
|
11
10
|
};
|
|
12
|
-
exports.HOSTED_LOGIN_VERIFIER_KEY = exports.
|
|
11
|
+
exports.HOSTED_LOGIN_VERIFIER_KEY = exports.FRONTEGG_AFTER_AUTH_REDIRECT_URL = exports.DEFAULT_RETRY_CONFIG = void 0;
|
|
13
12
|
var _consts = require("./auth/StepUpState/consts");
|
|
14
13
|
Object.keys(_consts).forEach(function (key) {
|
|
15
14
|
if (key === "default" || key === "__esModule") return;
|
|
@@ -36,8 +35,6 @@ Object.keys(_consts2).forEach(function (key) {
|
|
|
36
35
|
});
|
|
37
36
|
const FRONTEGG_AFTER_AUTH_REDIRECT_URL = 'FRONTEGG_AFTER_AUTH_REDIRECT_URL';
|
|
38
37
|
exports.FRONTEGG_AFTER_AUTH_REDIRECT_URL = FRONTEGG_AFTER_AUTH_REDIRECT_URL;
|
|
39
|
-
const FRONTEGG_PENDING_SWITCH_TENANT = 'FRONTEGG_PENDING_SWITCH_TENANT';
|
|
40
|
-
exports.FRONTEGG_PENDING_SWITCH_TENANT = FRONTEGG_PENDING_SWITCH_TENANT;
|
|
41
38
|
const HOSTED_LOGIN_VERIFIER_KEY = 'HOSTED_LOGIN_VERIFIER_KEY';
|
|
42
39
|
exports.HOSTED_LOGIN_VERIFIER_KEY = HOSTED_LOGIN_VERIFIER_KEY;
|
|
43
40
|
const DEFAULT_RETRY_CONFIG = {
|
package/node/helpers/handlers.js
CHANGED
|
@@ -3,14 +3,10 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.
|
|
6
|
+
exports.isFronteggApiError = exports.isError = exports.errorHandler = void 0;
|
|
7
7
|
var _restApi = require("@frontegg/rest-api");
|
|
8
8
|
const isFronteggApiError = error => Boolean(error == null ? void 0 : error.statusCode);
|
|
9
|
-
|
|
10
|
-
// ER-01079 (disabled user / expired tenant) is not this: it still logs out
|
|
11
9
|
exports.isFronteggApiError = isFronteggApiError;
|
|
12
|
-
const isSsoEnforcementError = error => isFronteggApiError(error) && error.errorCode === _restApi.SSO_REQUIRED_FOR_TENANT_ERROR_CODE;
|
|
13
|
-
exports.isSsoEnforcementError = isSsoEnforcementError;
|
|
14
10
|
const isError = error => {
|
|
15
11
|
if (error instanceof Error) {
|
|
16
12
|
return true;
|
package/node/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@frontegg/redux-store",
|
|
3
|
-
"version": "7.129.0
|
|
3
|
+
"version": "7.129.0",
|
|
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.129.0
|
|
10
|
+
"@frontegg/rest-api": "7.129.0",
|
|
11
11
|
"fast-deep-equal": "3.1.3",
|
|
12
12
|
"get-value": "^3.0.1",
|
|
13
13
|
"proxy-compare": "^3.0.0",
|