@frontegg/redux-store 7.131.0-alpha.1 → 7.131.0-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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, restoreTabTenantUnlessSsoCallback } from '../../helpers';
6
+ import { getUri, getUrlDerivedStepUp, isSteppedUp, isOnLoginCodeCallbackRoute, 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) => {
@@ -27,6 +27,10 @@ export default ((store, api, sharedActions) => {
27
27
  response = await api.auth.silentOAuthRefreshTokenV2();
28
28
  } catch (error) {
29
29
  var _store$auth$user, _error$errorContext;
30
+ // on the hosted login callback the page finishes the login with its code: fail as with the flag off
31
+ if (isOnLoginCodeCallbackRoute(store)) {
32
+ throw error;
33
+ }
30
34
  // the tenant requires SSO: hosted login for that tenant, not the plain one the caller falls back to
31
35
  if (await actions.__redirectToSsoIfRequired(error)) {
32
36
  return;
@@ -33,7 +33,21 @@ declare const _default: (store: FronteggState, api: RestApi, sharedActions: Shar
33
33
  requestHostedLoginAuthorize: (additionalParams?: Record<string, string>) => Promise<void>;
34
34
  requestHostedLoginAuthorizeV2: (payload?: {
35
35
  additionalParams?: Record<string, string>;
36
- shouldRedirectToLogin?: boolean;
36
+ shouldRedirectToLogin
37
+ /**
38
+ * Handles a hosted (OAuth) token refresh refused because the tenant requires SSO.
39
+ * ssoRequired: true sends the user to SSO, like login. ssoRequired: false renews once more for the tenant of the
40
+ * current token, which keeps the session: OAuth doesn't use up the refresh token on this refusal.
41
+ * @returns true when handled, false when the caller should log out
42
+ * @private
43
+ */
44
+ ? /**
45
+ * Handles a hosted (OAuth) token refresh refused because the tenant requires SSO.
46
+ * ssoRequired: true sends the user to SSO, like login. ssoRequired: false renews once more for the tenant of the
47
+ * current token, which keeps the session: OAuth doesn't use up the refresh token on this refusal.
48
+ * @returns true when handled, false when the caller should log out
49
+ * @private
50
+ */: boolean;
37
51
  firstTime?: boolean;
38
52
  loginDirectAction?: import("../interfaces").LoginDirectAction;
39
53
  }) => Promise<void>;
@@ -33,7 +33,7 @@ import { SHOULD_STEP_UP_KEY } from '../../StepUpState/consts';
33
33
  import { FronteggNativeModule, isEntitlementsDeeplyEqual } from '../../../toolkit';
34
34
  import { REQUEST_NAME, UserVerifiedOriginTypes } from '../../interfaces';
35
35
  import { authStrategyLoginStepMap, defaultOnRedirectTo } from '../consts';
36
- import { isMfaRequired, isOnAuthPageRoute, isOnOidcCallbackRoute, isResetPasswordRequired, restoreTabTenantUnlessSsoCallback, setAfterAuthRedirectUrlForStepUp } from '../../helpers';
36
+ import { isMfaRequired, isOnAuthPageRoute, isOnLoginCodeCallbackRoute, isResetPasswordRequired, restoreTabTenantUnlessSsoCallback, setAfterAuthRedirectUrlForStepUp } from '../../helpers';
37
37
  import { MFAStep } from '../../MfaState/interfaces';
38
38
  import { SamlVendors } from '../../SSOState/interfaces';
39
39
  import { DEFAULT_RETRY_CONFIG } from '../../../constants';
@@ -129,7 +129,8 @@ export default ((store, api, sharedActions) => {
129
129
  */
130
130
  const __handleSsoEnforcementRefreshError = async (e, isSsoEnforcementRetry, refreshForTenant) => {
131
131
  var _store$auth$user;
132
- if (!isEnforceSsoOnTenantAccessEnabled(store.root.appName) || !isSsoEnforcementError(e)) {
132
+ // on a login callback the page finishes the login with its code: log out as with the flag off, no new SSO trip
133
+ if (!isEnforceSsoOnTenantAccessEnabled(store.root.appName) || !isSsoEnforcementError(e) || isOnLoginCodeCallbackRoute(store)) {
133
134
  return false;
134
135
  }
135
136
  if (await __redirectToSsoIfRequired(e)) {
@@ -246,8 +247,8 @@ export default ((store, api, sharedActions) => {
246
247
  }
247
248
  } catch (e) {
248
249
  // 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))) {
250
+ // a login callback, where the page itself completes the login
251
+ if (isEnforceSsoOnTenantAccessEnabled(store.root.appName) && !isOnLoginCodeCallbackRoute(store) && (await __redirectToSsoIfRequired(e))) {
251
252
  return;
252
253
  }
253
254
  contextHolder.setAccessToken(null);
@@ -94,12 +94,11 @@ export default ((store, api, sharedActions) => {
94
94
  }
95
95
  callback == null ? void 0 : callback(true);
96
96
  } catch (e) {
97
- callback == null ? void 0 : callback(false);
98
-
99
97
  // the session's tenant requires SSO: its SSO login steps the user up, instead of logging them out
100
98
  if (await actions.__redirectToSsoIfRequired(e)) {
101
99
  return;
102
100
  }
101
+ callback == null ? void 0 : callback(false);
103
102
  await __handleStepUpError(e);
104
103
  }
105
104
  };
package/auth/helpers.d.ts CHANGED
@@ -9,10 +9,11 @@ export declare const isResetPasswordRequired: (user: ILoginResponse, appName: st
9
9
  export declare const mapMetaDataObjectToActions: (obj: any, path?: string[]) => CommitChangeDto[];
10
10
  export declare const getUri: (urlStrategy: FronteggState["root"]["urlStrategy"]) => string;
11
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.
12
+ * On the OIDC or hosted login callback the page still has to finish the login with its code: a refresh refused before
13
+ * that is not a reason to go to SSO again. On the OIDC callback the IdP would send the user straight back here, forever;
14
+ * on the hosted callback a new hosted login would replace the PKCE verifier the code exchange needs.
14
15
  */
15
- export declare const isOnOidcCallbackRoute: (store: FronteggState) => boolean;
16
+ export declare const isOnLoginCodeCallbackRoute: (store: FronteggState) => boolean;
16
17
  /**
17
18
  * After a switch refused for SSO the tab points at the SSO tenant. Its SSO login comes back on a callback route and
18
19
  * keeps it; any other page load means the user didn't finish that login, so the tab goes back to its tenant.
package/auth/helpers.js CHANGED
@@ -2,7 +2,7 @@ import _objectWithoutPropertiesLoose from "@babel/runtime/helpers/esm/objectWith
2
2
  import _extends from "@babel/runtime/helpers/esm/extends";
3
3
  const _excluded = ["phoneNumber", "email", "username"],
4
4
  _excluded2 = ["authenticatedUrl"];
5
- import { ContextHolder, restoreTabTenantBeforeSsoSwitch, isEnforceSsoOnTenantAccessEnabled } from '@frontegg/rest-api';
5
+ import { ContextHolder, restoreTabTenantBeforeSsoSwitch } from '@frontegg/rest-api';
6
6
  import { defaultFronteggRoutes } from './LoginState/consts';
7
7
  export * from './Entitlements/helpers';
8
8
  export * from './LoginState/helpers';
@@ -67,15 +67,18 @@ const getCurrentRoutes = urlStrategy => {
67
67
  };
68
68
 
69
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.
70
+ * On the OIDC or hosted login callback the page still has to finish the login with its code: a refresh refused before
71
+ * that is not a reason to go to SSO again. On the OIDC callback the IdP would send the user straight back here, forever;
72
+ * on the hosted callback a new hosted login would replace the PKCE verifier the code exchange needs.
72
73
  */
73
- export const isOnOidcCallbackRoute = store => {
74
+ export const isOnLoginCodeCallbackRoute = store => {
74
75
  var _store$root$urlStrate;
75
76
  const {
76
- oidcRedirectUrl
77
+ oidcRedirectUrl,
78
+ hostedLoginRedirectUrl
77
79
  } = _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));
80
+ const currentRoutes = getCurrentRoutes((_store$root$urlStrate = store.root.urlStrategy) != null ? _store$root$urlStrate : 'path');
81
+ return [oidcRedirectUrl, hostedLoginRedirectUrl].some(route => !!route && currentRoutes.some(currentRoute => currentRoute.endsWith(route)));
79
82
  };
80
83
 
81
84
  /**
@@ -84,7 +87,9 @@ export const isOnOidcCallbackRoute = store => {
84
87
  */
85
88
  export const restoreTabTenantUnlessSsoCallback = store => {
86
89
  var _store$root$urlStrate2;
87
- if (!isEnforceSsoOnTenantAccessEnabled(store.root.appName) || !ContextHolder.for(store.root.appName).isSessionPerTenantEnabled()) {
90
+ // Flags load in parallel with the first refresh. Recover an existing marker
91
+ // before choosing that refresh's tenant, even if flags are not available yet.
92
+ if (!ContextHolder.for(store.root.appName).isSessionPerTenantEnabled()) {
88
93
  return;
89
94
  }
90
95
  const {
package/index.js CHANGED
@@ -1,4 +1,4 @@
1
- /** @license Frontegg v7.131.0-alpha.1
1
+ /** @license Frontegg v7.131.0-alpha.2
2
2
  *
3
3
  * This source code is licensed under the MIT license found in the
4
4
  * LICENSE file in the root directory of this source tree.
@@ -34,6 +34,10 @@ var _default = (store, api, sharedActions) => {
34
34
  response = await api.auth.silentOAuthRefreshTokenV2();
35
35
  } catch (error) {
36
36
  var _store$auth$user, _error$errorContext;
37
+ // on the hosted login callback the page finishes the login with its code: fail as with the flag off
38
+ if ((0, _helpers3.isOnLoginCodeCallbackRoute)(store)) {
39
+ throw error;
40
+ }
37
41
  // the tenant requires SSO: hosted login for that tenant, not the plain one the caller falls back to
38
42
  if (await actions.__redirectToSsoIfRequired(error)) {
39
43
  return;
@@ -136,7 +136,8 @@ var _default = (store, api, sharedActions) => {
136
136
  */
137
137
  const __handleSsoEnforcementRefreshError = async (e, isSsoEnforcementRetry, refreshForTenant) => {
138
138
  var _store$auth$user;
139
- if (!(0, _restApi.isEnforceSsoOnTenantAccessEnabled)(store.root.appName) || !(0, _helpers.isSsoEnforcementError)(e)) {
139
+ // on a login callback the page finishes the login with its code: log out as with the flag off, no new SSO trip
140
+ if (!(0, _restApi.isEnforceSsoOnTenantAccessEnabled)(store.root.appName) || !(0, _helpers.isSsoEnforcementError)(e) || (0, _helpers3.isOnLoginCodeCallbackRoute)(store)) {
140
141
  return false;
141
142
  }
142
143
  if (await __redirectToSsoIfRequired(e)) {
@@ -253,8 +254,8 @@ var _default = (store, api, sharedActions) => {
253
254
  }
254
255
  } catch (e) {
255
256
  // 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))) {
257
+ // a login callback, where the page itself completes the login
258
+ if ((0, _restApi.isEnforceSsoOnTenantAccessEnabled)(store.root.appName) && !(0, _helpers3.isOnLoginCodeCallbackRoute)(store) && (await __redirectToSsoIfRequired(e))) {
258
259
  return;
259
260
  }
260
261
  contextHolder.setAccessToken(null);
@@ -100,12 +100,11 @@ var _default = (store, api, sharedActions) => {
100
100
  }
101
101
  callback == null ? void 0 : callback(true);
102
102
  } catch (e) {
103
- callback == null ? void 0 : callback(false);
104
-
105
103
  // the session's tenant requires SSO: its SSO login steps the user up, instead of logging them out
106
104
  if (await actions.__redirectToSsoIfRequired(e)) {
107
105
  return;
108
106
  }
107
+ callback == null ? void 0 : callback(false);
109
108
  await __handleStepUpError(e);
110
109
  }
111
110
  };
@@ -9,13 +9,13 @@ var _exportNames = {
9
9
  isResetPasswordRequired: true,
10
10
  mapMetaDataObjectToActions: true,
11
11
  getUri: true,
12
- isOnOidcCallbackRoute: true,
12
+ isOnLoginCodeCallbackRoute: true,
13
13
  restoreTabTenantUnlessSsoCallback: true,
14
14
  prepareIdentifiersForSignup: true,
15
15
  isOnAuthPageRoute: true,
16
16
  isAuthRoute: true
17
17
  };
18
- exports.restoreTabTenantUnlessSsoCallback = exports.prepareIdentifiersForSignup = exports.mapMetaDataObjectToActions = exports.isResetPasswordRequired = exports.isOnOidcCallbackRoute = exports.isOnAuthPageRoute = exports.isMfaRequired = exports.isAuthRoute = exports.getUri = void 0;
18
+ exports.restoreTabTenantUnlessSsoCallback = exports.prepareIdentifiersForSignup = exports.mapMetaDataObjectToActions = exports.isResetPasswordRequired = exports.isOnLoginCodeCallbackRoute = exports.isOnAuthPageRoute = exports.isMfaRequired = exports.isAuthRoute = exports.getUri = void 0;
19
19
  var _objectWithoutPropertiesLoose2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutPropertiesLoose"));
20
20
  var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
21
21
  var _restApi = require("@frontegg/rest-api");
@@ -122,25 +122,30 @@ const getCurrentRoutes = urlStrategy => {
122
122
  };
123
123
 
124
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.
125
+ * On the OIDC or hosted login callback the page still has to finish the login with its code: a refresh refused before
126
+ * that is not a reason to go to SSO again. On the OIDC callback the IdP would send the user straight back here, forever;
127
+ * on the hosted callback a new hosted login would replace the PKCE verifier the code exchange needs.
127
128
  */
128
- const isOnOidcCallbackRoute = store => {
129
+ const isOnLoginCodeCallbackRoute = store => {
129
130
  var _store$root$urlStrate;
130
131
  const {
131
- oidcRedirectUrl
132
+ oidcRedirectUrl,
133
+ hostedLoginRedirectUrl
132
134
  } = (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));
135
+ const currentRoutes = getCurrentRoutes((_store$root$urlStrate = store.root.urlStrategy) != null ? _store$root$urlStrate : 'path');
136
+ return [oidcRedirectUrl, hostedLoginRedirectUrl].some(route => !!route && currentRoutes.some(currentRoute => currentRoute.endsWith(route)));
134
137
  };
135
138
 
136
139
  /**
137
140
  * After a switch refused for SSO the tab points at the SSO tenant. Its SSO login comes back on a callback route and
138
141
  * keeps it; any other page load means the user didn't finish that login, so the tab goes back to its tenant.
139
142
  */
140
- exports.isOnOidcCallbackRoute = isOnOidcCallbackRoute;
143
+ exports.isOnLoginCodeCallbackRoute = isOnLoginCodeCallbackRoute;
141
144
  const restoreTabTenantUnlessSsoCallback = store => {
142
145
  var _store$root$urlStrate2;
143
- if (!(0, _restApi.isEnforceSsoOnTenantAccessEnabled)(store.root.appName) || !_restApi.ContextHolder.for(store.root.appName).isSessionPerTenantEnabled()) {
146
+ // Flags load in parallel with the first refresh. Recover an existing marker
147
+ // before choosing that refresh's tenant, even if flags are not available yet.
148
+ if (!_restApi.ContextHolder.for(store.root.appName).isSessionPerTenantEnabled()) {
144
149
  return;
145
150
  }
146
151
  const {
package/node/index.js CHANGED
@@ -1,4 +1,4 @@
1
- /** @license Frontegg v7.131.0-alpha.1
1
+ /** @license Frontegg v7.131.0-alpha.2
2
2
  *
3
3
  * This source code is licensed under the MIT license found in the
4
4
  * LICENSE file in the root directory of this source tree.
package/package.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "@frontegg/redux-store",
3
- "version": "7.131.0-alpha.1",
3
+ "version": "7.131.0-alpha.2",
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.1",
10
+ "@frontegg/rest-api": "7.131.0-alpha.2",
11
11
  "fast-deep-equal": "3.1.3",
12
12
  "get-value": "^3.0.1",
13
13
  "proxy-compare": "^3.0.0",