@frontegg/redux-store 6.155.0-alpha.1 → 6.155.0-alpha.3

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.
Files changed (70) hide show
  1. package/auth/ActivateState/saga.js +3 -2
  2. package/auth/ApiTokensState/index.d.ts +0 -8
  3. package/auth/LoginState/index.d.ts +1 -1
  4. package/auth/LoginState/index.js +1 -1
  5. package/auth/LoginState/interfaces.d.ts +5 -0
  6. package/auth/LoginState/saga.d.ts +3 -17
  7. package/auth/LoginState/saga.js +19 -383
  8. package/auth/LoginState/saga.utils.d.ts +12 -0
  9. package/auth/LoginState/saga.utils.js +47 -0
  10. package/auth/LoginState/sagas/afterAuthNavigation.saga.d.ts +27 -0
  11. package/auth/LoginState/sagas/afterAuthNavigation.saga.js +115 -0
  12. package/auth/LoginState/sagas/handleVerifyMFAResponse.saga.d.ts +54 -0
  13. package/auth/LoginState/sagas/handleVerifyMFAResponse.saga.js +80 -0
  14. package/auth/LoginState/sagas/index.d.ts +7 -0
  15. package/auth/LoginState/sagas/index.js +7 -0
  16. package/auth/LoginState/{mfaRequiredState.saga.d.ts → sagas/mfaRequiredState.saga.d.ts} +3 -3
  17. package/auth/LoginState/{mfaRequiredState.saga.js → sagas/mfaRequiredState.saga.js} +3 -3
  18. package/auth/LoginState/sagas/mfaWithAuthenticator.saga.d.ts +42 -0
  19. package/auth/LoginState/sagas/mfaWithAuthenticator.saga.js +140 -0
  20. package/auth/LoginState/sagas/mfaWithEmailCode.saga.d.ts +73 -0
  21. package/auth/LoginState/sagas/mfaWithEmailCode.saga.js +96 -0
  22. package/auth/LoginState/sagas/mfaWithSMS.saga.d.ts +79 -0
  23. package/auth/LoginState/sagas/mfaWithSMS.saga.js +107 -0
  24. package/auth/LoginState/sagas/mfaWithWebAuthn.saga.d.ts +83 -0
  25. package/auth/LoginState/sagas/mfaWithWebAuthn.saga.js +119 -0
  26. package/auth/LoginState/utils.d.ts +2 -1
  27. package/auth/LoginState/utils.js +6 -1
  28. package/auth/MfaState/interfaces.d.ts +2 -1
  29. package/auth/MfaState/interfaces.js +1 -0
  30. package/auth/MfaState/saga.js +1 -1
  31. package/auth/SignUp/saga.js +1 -1
  32. package/auth/StepUpState/consts.d.ts +17 -0
  33. package/auth/StepUpState/consts.js +20 -0
  34. package/auth/StepUpState/generateStepUpSession.saga.d.ts +14 -0
  35. package/auth/StepUpState/generateStepUpSession.saga.js +102 -0
  36. package/auth/StepUpState/index.d.ts +17 -3
  37. package/auth/StepUpState/index.js +22 -2
  38. package/auth/StepUpState/interfaces.d.ts +9 -0
  39. package/auth/StepUpState/saga.d.ts +125 -11
  40. package/auth/StepUpState/saga.js +95 -70
  41. package/auth/StepUpState/utils.d.ts +15 -3
  42. package/auth/StepUpState/utils.js +24 -10
  43. package/auth/index.d.ts +6 -0
  44. package/auth/interfaces.d.ts +1 -0
  45. package/auth/reducer.d.ts +6 -0
  46. package/index.d.ts +1 -1
  47. package/index.js +2 -2
  48. package/node/auth/ActivateState/saga.js +3 -2
  49. package/node/auth/LoginState/index.js +6 -0
  50. package/node/auth/LoginState/saga.js +54 -410
  51. package/node/auth/LoginState/saga.utils.js +55 -0
  52. package/node/auth/LoginState/sagas/afterAuthNavigation.saga.js +122 -0
  53. package/node/auth/LoginState/sagas/handleVerifyMFAResponse.saga.js +87 -0
  54. package/node/auth/LoginState/sagas/index.js +82 -0
  55. package/node/auth/LoginState/{mfaRequiredState.saga.js → sagas/mfaRequiredState.saga.js} +3 -3
  56. package/node/auth/LoginState/sagas/mfaWithAuthenticator.saga.js +147 -0
  57. package/node/auth/LoginState/sagas/mfaWithEmailCode.saga.js +106 -0
  58. package/node/auth/LoginState/sagas/mfaWithSMS.saga.js +116 -0
  59. package/node/auth/LoginState/sagas/mfaWithWebAuthn.saga.js +128 -0
  60. package/node/auth/LoginState/utils.js +6 -1
  61. package/node/auth/MfaState/interfaces.js +1 -0
  62. package/node/auth/MfaState/saga.js +1 -1
  63. package/node/auth/SignUp/saga.js +1 -1
  64. package/node/auth/StepUpState/consts.js +30 -0
  65. package/node/auth/StepUpState/generateStepUpSession.saga.js +107 -0
  66. package/node/auth/StepUpState/index.js +37 -7
  67. package/node/auth/StepUpState/saga.js +99 -71
  68. package/node/auth/StepUpState/utils.js +26 -14
  69. package/node/index.js +5 -5
  70. package/package.json +2 -2
@@ -0,0 +1,115 @@
1
+ import { ContextHolder } from '@frontegg/rest-api';
2
+ import { delay, put, select, call } from 'redux-saga/effects';
3
+ import { loadCustomLoginRoutes } from '../../CustomLoginState/saga';
4
+ import { actions } from '../../reducer';
5
+ import { getPathAndSearchParamsFromUrl, getRedirectUrl } from '../utils';
6
+ import { FRONTEGG_AFTER_AUTH_REDIRECT_URL } from '../../../constants';
7
+ import { isSteppedUp } from '../../StepUpState';
8
+ import { SHOULD_STEP_UP_KEY } from '../../StepUpState/consts';
9
+
10
+ /**
11
+ * @param customLoginAuthenticatedUrl custom login authenticated url if exists
12
+ * @returns the authenticated url to redirect to after auth navigation
13
+ */
14
+ function* getUrlForAfterAuthNavigation(customLoginAuthenticatedUrl) {
15
+ const {
16
+ routes,
17
+ includeQueryParam,
18
+ enforceRedirectToSameSite = false,
19
+ allowedRedirectOrigins = []
20
+ } = yield select(state => state.auth);
21
+ if (customLoginAuthenticatedUrl) {
22
+ return getPathAndSearchParamsFromUrl(customLoginAuthenticatedUrl);
23
+ }
24
+ const {
25
+ authenticatedUrl,
26
+ loginUrl,
27
+ logoutUrl,
28
+ socialLoginCallbackUrl,
29
+ activateUrl
30
+ } = routes;
31
+ let finalUrl = window.localStorage.getItem(FRONTEGG_AFTER_AUTH_REDIRECT_URL);
32
+ if (!finalUrl || [loginUrl, logoutUrl, socialLoginCallbackUrl, activateUrl].includes(finalUrl)) {
33
+ finalUrl = authenticatedUrl;
34
+ }
35
+ return getRedirectUrl({
36
+ authenticatedUrl: finalUrl,
37
+ includeQueryParam,
38
+ enforceRedirectToSameSite,
39
+ allowedRedirectOrigins
40
+ });
41
+ }
42
+ /**
43
+ * Utility to share after auth navigation flow between login and step up
44
+ * @param resetStateAction reset state action
45
+ * @param customLoginAuthenticatedUrl custom login authenticated url if exists
46
+ */
47
+ export function* afterAuthNavigationUtil(resetStateAction, {
48
+ customLoginAuthenticatedUrl,
49
+ forceStepUpUrl
50
+ } = {}) {
51
+ const onRedirectTo = ContextHolder.onRedirectTo;
52
+ let redirectUrl;
53
+ if (forceStepUpUrl) {
54
+ // scenario to get to here: invalid max age, try to step up -> logout, login with magic code/link -> redirect to step up page for email code as the second factor
55
+ // we don't want to remove the FRONTEGG_AFTER_AUTH_REDIRECT_URL when we are in the step up flow
56
+ redirectUrl = forceStepUpUrl;
57
+ } else {
58
+ var _window;
59
+ redirectUrl = yield call(getUrlForAfterAuthNavigation, customLoginAuthenticatedUrl);
60
+ (_window = window) == null ? void 0 : _window.localStorage.removeItem(FRONTEGG_AFTER_AUTH_REDIRECT_URL);
61
+ }
62
+ yield delay(200);
63
+ put(resetStateAction());
64
+ onRedirectTo(redirectUrl, {
65
+ refresh: redirectUrl.startsWith('http')
66
+ });
67
+ }
68
+
69
+ /**
70
+ * After auth navigation for login flow
71
+ * Handling also step up scenario when user silently logout to continue to step up
72
+ */
73
+ export function* afterAuthNavigation() {
74
+ var _window2;
75
+ const {
76
+ routes: {
77
+ customLoginAuthenticatedUrl,
78
+ stepUpUrl
79
+ }
80
+ } = yield select(state => state.auth);
81
+
82
+ // login with magic code, try to step up, no other mfa, invalid max age, force_enroll -> logout, login with first factor, not-stepped up jwt -> navigate to step up
83
+ const shouldStepUp = (_window2 = window) == null ? void 0 : _window2.localStorage.getItem(SHOULD_STEP_UP_KEY);
84
+ const user = yield select(({
85
+ auth
86
+ }) => auth.user);
87
+ if (shouldStepUp) {
88
+ var _window3;
89
+ (_window3 = window) == null ? void 0 : _window3.localStorage.removeItem(SHOULD_STEP_UP_KEY);
90
+ }
91
+ if (stepUpUrl && shouldStepUp && !isSteppedUp(user)) {
92
+ yield call(afterAuthNavigationUtil, actions.resetLoginState, {
93
+ forceStepUpUrl: stepUpUrl
94
+ });
95
+ return;
96
+ }
97
+ let customLoginURL = customLoginAuthenticatedUrl;
98
+ if (!customLoginAuthenticatedUrl) {
99
+ yield call(loadCustomLoginRoutes);
100
+ customLoginURL = yield select(state => {
101
+ var _state$auth$routes;
102
+ return (_state$auth$routes = state.auth.routes) == null ? void 0 : _state$auth$routes.customLoginAuthenticatedUrl;
103
+ });
104
+ }
105
+ yield call(afterAuthNavigationUtil, actions.resetLoginState, {
106
+ customLoginAuthenticatedUrl: customLoginURL
107
+ });
108
+ }
109
+
110
+ /**
111
+ * After auth navigation for step up flow
112
+ */
113
+ export function* afterStepUpAuthNavigation() {
114
+ yield call(afterAuthNavigationUtil, actions.resetStepUpState);
115
+ }
@@ -0,0 +1,54 @@
1
+ import { ILoginResponseV3 } from '@frontegg/rest-api';
2
+ import { AuthState } from '../../interfaces';
3
+ /**
4
+ * Additional steps for after MFA authentication with authenticator app handler for step up flow
5
+ */
6
+ export declare function postHandleVerifyMFAResponseForStepUp(): Generator<import("redux-saga/effects").CallEffect<void>, void, unknown>;
7
+ /**
8
+ * Additional steps for after MFA authentication with authenticator app handler for login flow
9
+ * @param isAuthenticated
10
+ */
11
+ export declare function postHandleVerifyMFAResponseForLogin(isAuthenticated: boolean): Generator<import("redux-saga/effects").SelectEffect | import("redux-saga/effects").CallEffect<boolean[]> | Generator<import("redux-saga/effects").SelectEffect | import("redux-saga/effects").CallEffect<void>, void, {
12
+ routes: {
13
+ customLoginAuthenticatedUrl: any;
14
+ stepUpUrl: any;
15
+ };
16
+ } & import("../../interfaces").User & string> | import("redux-saga/effects").PutEffect<{
17
+ payload: Partial<import("../interfaces").LoginState>;
18
+ type: string;
19
+ }> | import("redux-saga/effects").CallEffect<boolean>, void, (AuthState & {
20
+ step: any;
21
+ } & boolean[] & false) | (AuthState & {
22
+ step: any;
23
+ } & boolean[] & true)>;
24
+ /**
25
+ * Handle after MFA authentication with authenticator app
26
+ * @param payload.user
27
+ * @param payload.tenants
28
+ * @param payload.activeTenant
29
+ * @param isStepUp
30
+ *
31
+ * When using this saga, you should wrap it with try/catch block and handle according to your logic
32
+ */
33
+ export declare function handleVerifyMFAResponse({ user, tenants, activeTenant }: ILoginResponseV3, isStepUp?: boolean): Generator<import("redux-saga/effects").PutEffect<{
34
+ payload: Partial<AuthState>;
35
+ type: string;
36
+ }> | import("redux-saga/effects").CallEffect<void> | import("redux-saga/effects").PutEffect<{
37
+ payload: import("../../interfaces").User;
38
+ type: string;
39
+ }> | import("redux-saga/effects").PutEffect<{
40
+ payload: Partial<import("../..").TenantsState>;
41
+ type: string;
42
+ }> | import("redux-saga/effects").CallEffect<Generator<import("redux-saga/effects").SelectEffect | import("redux-saga/effects").CallEffect<boolean[]> | Generator<import("redux-saga/effects").SelectEffect | import("redux-saga/effects").CallEffect<void>, void, {
43
+ routes: {
44
+ customLoginAuthenticatedUrl: any;
45
+ stepUpUrl: any;
46
+ };
47
+ } & import("../../interfaces").User & string> | import("redux-saga/effects").PutEffect<{
48
+ payload: Partial<import("../interfaces").LoginState>;
49
+ type: string;
50
+ }> | import("redux-saga/effects").CallEffect<boolean>, void, (AuthState & {
51
+ step: any;
52
+ } & boolean[] & false) | (AuthState & {
53
+ step: any;
54
+ } & boolean[] & true)>>, void, unknown>;
@@ -0,0 +1,80 @@
1
+ import { select, put, call } from 'redux-saga/effects';
2
+ import { MFAStep } from '../../MfaState/interfaces';
3
+ import { actions } from '../../reducer';
4
+ import { LoginFlow, LoginStep } from '../interfaces';
5
+ import { shouldShowPromptPasskeys } from '../saga.utils';
6
+ import { afterStepUpAuthNavigation, afterAuthNavigation } from './afterAuthNavigation.saga';
7
+ import { getFeatureFlags } from '../../../helpers';
8
+
9
+ /**
10
+ * Additional steps for after MFA authentication with authenticator app handler for step up flow
11
+ */
12
+ export function* postHandleVerifyMFAResponseForStepUp() {
13
+ yield call(afterStepUpAuthNavigation);
14
+ }
15
+
16
+ /**
17
+ * Additional steps for after MFA authentication with authenticator app handler for login flow
18
+ * @param isAuthenticated
19
+ */
20
+ export function* postHandleVerifyMFAResponseForLogin(isAuthenticated) {
21
+ const {
22
+ loginState
23
+ } = yield select(state => state.auth);
24
+ const {
25
+ step: mfaStep
26
+ } = yield select(state => state.auth.mfaState);
27
+ const [securityCenterLoginFlows] = yield call(getFeatureFlags, ['security-center-show-login-flows']);
28
+ if (loginState.flow === LoginFlow.Login) {
29
+ if (securityCenterLoginFlows && loginState.isBreachedPassword && !isAuthenticated) {
30
+ yield put(actions.setLoginState({
31
+ step: LoginStep.breachedPassword,
32
+ loading: false
33
+ }));
34
+ } else {
35
+ const shouldShowPrompt = yield call(shouldShowPromptPasskeys);
36
+ if (mfaStep === MFAStep.smsVerifyCode && shouldShowPrompt) {
37
+ yield put(actions.setLoginState({
38
+ step: LoginStep.promptPasskeys,
39
+ loading: false
40
+ }));
41
+ } else {
42
+ yield afterAuthNavigation();
43
+ }
44
+ }
45
+ }
46
+ }
47
+
48
+ /**
49
+ * Handle after MFA authentication with authenticator app
50
+ * @param payload.user
51
+ * @param payload.tenants
52
+ * @param payload.activeTenant
53
+ * @param isStepUp
54
+ *
55
+ * When using this saga, you should wrap it with try/catch block and handle according to your logic
56
+ */
57
+ export function* handleVerifyMFAResponse({
58
+ user,
59
+ tenants,
60
+ activeTenant
61
+ }, isStepUp = false) {
62
+ yield put(actions.setUser(user));
63
+ yield put(actions.setTenantsState({
64
+ tenants,
65
+ activeTenant,
66
+ loading: false
67
+ }));
68
+ if (user.id) {
69
+ localStorage.setItem('userId', user.id);
70
+ }
71
+ const isAuthenticated = !!user.accessToken;
72
+ yield put(actions.setState({
73
+ isAuthenticated
74
+ }));
75
+ if (isStepUp) {
76
+ yield call(postHandleVerifyMFAResponseForStepUp);
77
+ return;
78
+ }
79
+ yield call(postHandleVerifyMFAResponseForLogin, isAuthenticated);
80
+ }
@@ -0,0 +1,7 @@
1
+ export * from './afterAuthNavigation.saga';
2
+ export * from './handleVerifyMFAResponse.saga';
3
+ export * from './mfaWithSMS.saga';
4
+ export * from './mfaRequiredState.saga';
5
+ export * from './mfaWithAuthenticator.saga';
6
+ export * from './mfaWithEmailCode.saga';
7
+ export * from './mfaWithWebAuthn.saga';
@@ -0,0 +1,7 @@
1
+ export * from './afterAuthNavigation.saga';
2
+ export * from './handleVerifyMFAResponse.saga';
3
+ export * from './mfaWithSMS.saga';
4
+ export * from './mfaRequiredState.saga';
5
+ export * from './mfaWithAuthenticator.saga';
6
+ export * from './mfaWithEmailCode.saga';
7
+ export * from './mfaWithWebAuthn.saga';
@@ -1,6 +1,6 @@
1
- import { LoginStep, QuickLoginStrategy, LoginFlow } from './interfaces';
2
- import { MFAState } from '../MfaState/interfaces';
3
- import { AuthState } from '../interfaces';
1
+ import { LoginStep, QuickLoginStrategy, LoginFlow } from '../interfaces';
2
+ import { MFAState } from '../../MfaState/interfaces';
3
+ import { AuthState } from '../../interfaces';
4
4
  export declare function getMfaRequiredState(user: any): Generator<import("redux-saga/effects").SelectEffect | import("redux-saga/effects").CallEffect<import("@frontegg/rest-api").IAllowedToRememberMfaDevice>, {
5
5
  user: undefined;
6
6
  isAuthenticated: boolean;
@@ -1,9 +1,9 @@
1
1
  import _extends from "@babel/runtime/helpers/esm/extends";
2
2
  import { call, select } from 'redux-saga/effects';
3
3
  import { api } from '@frontegg/rest-api';
4
- import { getMfaStepForEnrolledUsers, getMfaStepForNotEnrolledUsers } from './utils';
5
- import { LoginStep, LoginFlow } from './interfaces';
6
- // Separated file due to circular dependency
4
+ import { getMfaStepForEnrolledUsers, getMfaStepForNotEnrolledUsers } from '../utils';
5
+ import { LoginStep, LoginFlow } from '../interfaces';
6
+ // Separated folder due to circular dependency
7
7
 
8
8
  export function* getMfaRequiredState(user) {
9
9
  let step = LoginStep.loginWithTwoFactor;
@@ -0,0 +1,42 @@
1
+ import { PayloadAction } from '@reduxjs/toolkit';
2
+ import { ILoginWithMfa, ILoginResponseV3 } from '@frontegg/rest-api';
3
+ import { AuthState } from '../../interfaces';
4
+ import { SetLoadingAction } from '../interfaces';
5
+ import { WithCallback } from '../../../interfaces';
6
+ /**
7
+ * Utility function to handle MFA authentication with authenticator app
8
+ * @param payload MFA with authenticator action payload
9
+ * @param setLoadingAction set loading action
10
+ * @param isStepUp true if this is a step up authentication
11
+ * @returns
12
+ */
13
+ export declare function mfaWithAuthenticator({ callback, ...loginWithMfaPayload }: WithCallback<ILoginWithMfa>, setLoadingAction: SetLoadingAction, isStepUp: boolean): Generator<import("redux-saga/effects").CallEffect<void> | import("redux-saga/effects").CallEffect<ILoginResponseV3> | import("redux-saga/effects").PutEffect<import("redux").Action<any>> | import("redux-saga/effects").CallEffect<{
14
+ isAuthenticated: boolean;
15
+ }> | import("redux-saga/effects").CallEffect<Generator<import("redux-saga/effects").SelectEffect | import("redux-saga/effects").CallEffect<boolean[]> | Generator<import("redux-saga/effects").SelectEffect | import("redux-saga/effects").CallEffect<void>, void, {
16
+ routes: {
17
+ customLoginAuthenticatedUrl: any;
18
+ stepUpUrl: any;
19
+ };
20
+ } & import("../../interfaces").User & string> | import("redux-saga/effects").PutEffect<{
21
+ payload: Partial<import("../interfaces").LoginState>;
22
+ type: string;
23
+ }> | import("redux-saga/effects").CallEffect<boolean>, void, (AuthState & boolean[] & false) | (AuthState & boolean[] & true)>>, void, ILoginResponseV3 & Partial<AuthState>>;
24
+ /**
25
+ * Login with MFA with authenticator app - external saga
26
+ * @param payload.mfaToken
27
+ * @param payload.mfaDevices
28
+ * @param payload.rememberDevice
29
+ * @param payload.invitationToken
30
+ * @param payload.callback - The callback function to be called after the request is done
31
+ */
32
+ export declare function loginWithMfa({ payload }: PayloadAction<WithCallback<ILoginWithMfa>>): Generator<Generator<import("redux-saga/effects").CallEffect<void> | import("redux-saga/effects").CallEffect<ILoginResponseV3> | import("redux-saga/effects").PutEffect<import("redux").Action<any>> | import("redux-saga/effects").CallEffect<{
33
+ isAuthenticated: boolean;
34
+ }> | import("redux-saga/effects").CallEffect<Generator<import("redux-saga/effects").SelectEffect | import("redux-saga/effects").CallEffect<boolean[]> | Generator<import("redux-saga/effects").SelectEffect | import("redux-saga/effects").CallEffect<void>, void, {
35
+ routes: {
36
+ customLoginAuthenticatedUrl: any;
37
+ stepUpUrl: any;
38
+ };
39
+ } & import("../../interfaces").User & string> | import("redux-saga/effects").PutEffect<{
40
+ payload: Partial<import("../interfaces").LoginState>;
41
+ type: string;
42
+ }> | import("redux-saga/effects").CallEffect<boolean>, void, (AuthState & boolean[] & false) | (AuthState & boolean[] & true)>>, void, ILoginResponseV3 & Partial<AuthState>>, void, unknown>;
@@ -0,0 +1,140 @@
1
+ import _objectWithoutPropertiesLoose from "@babel/runtime/helpers/esm/objectWithoutPropertiesLoose";
2
+ import _extends from "@babel/runtime/helpers/esm/extends";
3
+ const _excluded = ["callback"];
4
+ import { select, put, call } from 'redux-saga/effects';
5
+ import { api } from '@frontegg/rest-api';
6
+ import { actions } from '../../reducer';
7
+ import { LoginFlow, LoginStep } from '../interfaces';
8
+ import { shouldShowPromptPasskeys, afterAuthenticationStateUpdate } from '../saga.utils';
9
+ import { afterAuthNavigation, afterStepUpAuthNavigation } from './afterAuthNavigation.saga';
10
+ import { getFeatureFlags } from '../../../helpers';
11
+ import { errorHandler } from '../../../utils';
12
+
13
+ /**
14
+ * @param tenants
15
+ * @param isAuthenticated
16
+ * @param isStepUp
17
+ * @returns additional update object for the afterAuthenticationStateUpdate saga as part of MFA auth with authenticator app
18
+ */
19
+ function* buildPostAuthStateUpdate(tenants, isAuthenticated, isStepUp) {
20
+ const {
21
+ loginState
22
+ } = yield select(state => state.auth);
23
+ let additionalUpdate = {};
24
+ if (!isStepUp) {
25
+ const step = loginState.flow === LoginFlow.Login ? LoginStep.success : loginState.step;
26
+ additionalUpdate = {
27
+ loginState: {
28
+ flow: loginState.flow,
29
+ quickLoginToRegister: loginState.quickLoginToRegister,
30
+ loading: false,
31
+ step,
32
+ error: undefined,
33
+ tenants
34
+ }
35
+ };
36
+ }
37
+ return _extends({}, additionalUpdate, {
38
+ isAuthenticated
39
+ });
40
+ }
41
+
42
+ /**
43
+ * Handle after MFA authentication with authenticator app for login
44
+ */
45
+ function* postLoginMfaAuthenticator(isAuthenticated, callback) {
46
+ const {
47
+ loginState
48
+ } = yield select(state => state.auth);
49
+ if (loginState.flow !== LoginFlow.Login) return;
50
+ const [securityCenterLoginFlows] = yield call(getFeatureFlags, ['security-center-show-login-flows']);
51
+ if (securityCenterLoginFlows && loginState.isBreachedPassword && !isAuthenticated) {
52
+ yield put(actions.setLoginState({
53
+ step: LoginStep.breachedPassword,
54
+ loading: false
55
+ }));
56
+ } else {
57
+ const shouldShowPrompt = yield call(shouldShowPromptPasskeys);
58
+ if (shouldShowPrompt) {
59
+ yield put(actions.setLoginState({
60
+ step: LoginStep.promptPasskeys,
61
+ loading: false
62
+ }));
63
+ } else {
64
+ yield afterAuthNavigation();
65
+ }
66
+ }
67
+ callback == null ? void 0 : callback(true);
68
+ }
69
+
70
+ /**
71
+ * Handle after MFA authentication with authenticator app for step up
72
+ */
73
+ function* postStepUpMfaAuthenticator(callback) {
74
+ yield afterStepUpAuthNavigation();
75
+ callback == null ? void 0 : callback(true);
76
+ }
77
+
78
+ /**
79
+ * Utility function to handle MFA authentication with authenticator app
80
+ * @param payload MFA with authenticator action payload
81
+ * @param setLoadingAction set loading action
82
+ * @param isStepUp true if this is a step up authentication
83
+ * @returns
84
+ */
85
+ export function* mfaWithAuthenticator(_ref, setLoadingAction, isStepUp) {
86
+ let {
87
+ callback
88
+ } = _ref,
89
+ loginWithMfaPayload = _objectWithoutPropertiesLoose(_ref, _excluded);
90
+ yield put(setLoadingAction({
91
+ loading: true,
92
+ error: undefined
93
+ }));
94
+ try {
95
+ const {
96
+ user,
97
+ tenants = [],
98
+ activeTenant
99
+ } = yield call(api.auth.loginWithMfaV2, loginWithMfaPayload);
100
+ const isAuthenticated = !!user.accessToken;
101
+ const additionalUpdate = yield call(buildPostAuthStateUpdate, tenants, isAuthenticated, isStepUp);
102
+ yield call(afterAuthenticationStateUpdate, {
103
+ user,
104
+ tenants,
105
+ activeTenant
106
+ }, additionalUpdate);
107
+ if (user.id) {
108
+ localStorage.setItem('userId', user.id);
109
+ }
110
+ yield put(setLoadingAction({
111
+ loading: false,
112
+ error: undefined
113
+ }));
114
+ if (isStepUp) {
115
+ yield call(postStepUpMfaAuthenticator, callback);
116
+ return;
117
+ }
118
+ yield call(postLoginMfaAuthenticator, isAuthenticated, callback);
119
+ } catch (e) {
120
+ yield put(setLoadingAction({
121
+ loading: false,
122
+ error: errorHandler(e)
123
+ }));
124
+ callback == null ? void 0 : callback(false, e);
125
+ }
126
+ }
127
+
128
+ /**
129
+ * Login with MFA with authenticator app - external saga
130
+ * @param payload.mfaToken
131
+ * @param payload.mfaDevices
132
+ * @param payload.rememberDevice
133
+ * @param payload.invitationToken
134
+ * @param payload.callback - The callback function to be called after the request is done
135
+ */
136
+ export function* loginWithMfa({
137
+ payload
138
+ }) {
139
+ yield mfaWithAuthenticator(payload, actions.setLoginState, false);
140
+ }
@@ -0,0 +1,73 @@
1
+ import { PayloadAction } from '@reduxjs/toolkit';
2
+ import { IPreVerifyMFA, IPreVerifyMFAEmailCodeResponse, IVerifyMFAEmailCode, ILoginResponseV3 } from '@frontegg/rest-api';
3
+ import { WithCallback } from '../../../interfaces';
4
+ import { SetLoadingAction } from '../interfaces';
5
+ /**
6
+ * Shared logic for MFA Email code pre-verify step
7
+ * @param payload.callback callback function to be called after the verification is done
8
+ * @param payload.mfaToken
9
+ * @param setLoadingAction loading setter action (e.g. actions.setLoginState)
10
+ */
11
+ export declare function preVerifyMFAEmailCode({ callback, ...payload }: WithCallback<IPreVerifyMFA>, setLoadingAction: SetLoadingAction): Generator<import("redux-saga/effects").PutEffect<import("redux").Action<any>> | import("redux-saga/effects").CallEffect<IPreVerifyMFAEmailCodeResponse>, void, IPreVerifyMFAEmailCodeResponse>;
12
+ /**
13
+ * Shared logic for MFA Email code verify step
14
+ * @param payload.otcToken
15
+ * @param payload.callback callback function to be called after the verification is done with true for success, o.w false
16
+ * @param payload.code 6 digits code input by the user
17
+ */
18
+ export declare function verifyMFAEmailCode({ callback, ...payload }: WithCallback<IVerifyMFAEmailCode>, setLoadingAction: SetLoadingAction): Generator<import("redux-saga/effects").CallEffect<ILoginResponseV3> | import("redux-saga/effects").PutEffect<import("redux").Action<any>> | Generator<import("redux-saga/effects").PutEffect<{
19
+ payload: Partial<import("../..").AuthState>;
20
+ type: string;
21
+ }> | import("redux-saga/effects").CallEffect<void> | import("redux-saga/effects").PutEffect<{
22
+ payload: import("../..").User;
23
+ type: string;
24
+ }> | import("redux-saga/effects").PutEffect<{
25
+ payload: Partial<import("../..").TenantsState>;
26
+ type: string;
27
+ }> | import("redux-saga/effects").CallEffect<Generator<import("redux-saga/effects").SelectEffect | import("redux-saga/effects").CallEffect<boolean[]> | Generator<import("redux-saga/effects").SelectEffect | import("redux-saga/effects").CallEffect<void>, void, {
28
+ routes: {
29
+ customLoginAuthenticatedUrl: any;
30
+ stepUpUrl: any;
31
+ };
32
+ } & import("../..").User & string> | import("redux-saga/effects").PutEffect<{
33
+ payload: Partial<import("../interfaces").LoginState>;
34
+ type: string;
35
+ }> | import("redux-saga/effects").CallEffect<boolean>, void, (import("../..").AuthState & {
36
+ step: any;
37
+ } & boolean[] & false) | (import("../..").AuthState & {
38
+ step: any;
39
+ } & boolean[] & true)>>, void, unknown>, void, ILoginResponseV3>;
40
+ /**
41
+ * Pre verify step for MFA Email login
42
+ * @param payload.mfaToken
43
+ * @param payload.callback callback function to be called after the verification is done
44
+ */
45
+ export declare function preVerifyMFAEmailCodeForLogin({ payload }: PayloadAction<WithCallback<IPreVerifyMFA>>): Generator<Generator<import("redux-saga/effects").PutEffect<import("redux").Action<any>> | import("redux-saga/effects").CallEffect<IPreVerifyMFAEmailCodeResponse>, void, IPreVerifyMFAEmailCodeResponse>, void, unknown>;
46
+ /**
47
+ * Verify step for MFA Email login
48
+ * @param payload.otcToken
49
+ * @param payload.callback callback function to be called after the verification is done with true for success, o.w false
50
+ * @param payload.code 6 digits code input by the user
51
+ */
52
+ export declare function verifyMFAEmailCodeForLogin({ payload }: PayloadAction<WithCallback<IVerifyMFAEmailCode>>): Generator<Generator<import("redux-saga/effects").CallEffect<ILoginResponseV3> | import("redux-saga/effects").PutEffect<import("redux").Action<any>> | Generator<import("redux-saga/effects").PutEffect<{
53
+ payload: Partial<import("../..").AuthState>;
54
+ type: string;
55
+ }> | import("redux-saga/effects").CallEffect<void> | import("redux-saga/effects").PutEffect<{
56
+ payload: import("../..").User;
57
+ type: string;
58
+ }> | import("redux-saga/effects").PutEffect<{
59
+ payload: Partial<import("../..").TenantsState>;
60
+ type: string;
61
+ }> | import("redux-saga/effects").CallEffect<Generator<import("redux-saga/effects").SelectEffect | import("redux-saga/effects").CallEffect<boolean[]> | Generator<import("redux-saga/effects").SelectEffect | import("redux-saga/effects").CallEffect<void>, void, {
62
+ routes: {
63
+ customLoginAuthenticatedUrl: any;
64
+ stepUpUrl: any;
65
+ };
66
+ } & import("../..").User & string> | import("redux-saga/effects").PutEffect<{
67
+ payload: Partial<import("../interfaces").LoginState>;
68
+ type: string;
69
+ }> | import("redux-saga/effects").CallEffect<boolean>, void, (import("../..").AuthState & {
70
+ step: any;
71
+ } & boolean[] & false) | (import("../..").AuthState & {
72
+ step: any;
73
+ } & boolean[] & true)>>, void, unknown>, void, ILoginResponseV3>, void, unknown>;
@@ -0,0 +1,96 @@
1
+ import _objectWithoutPropertiesLoose from "@babel/runtime/helpers/esm/objectWithoutPropertiesLoose";
2
+ const _excluded = ["callback"],
3
+ _excluded2 = ["callback"];
4
+ import { call, put } from 'redux-saga/effects';
5
+ import { api } from '@frontegg/rest-api';
6
+ import { errorHandler } from '../../../utils';
7
+ import { MFAStep } from '../../MfaState/interfaces';
8
+ import { actions } from '../../reducer';
9
+ import { handleVerifyMFAResponse } from './handleVerifyMFAResponse.saga';
10
+ /**
11
+ * Shared logic for MFA Email code pre-verify step
12
+ * @param payload.callback callback function to be called after the verification is done
13
+ * @param payload.mfaToken
14
+ * @param setLoadingAction loading setter action (e.g. actions.setLoginState)
15
+ */
16
+ export function* preVerifyMFAEmailCode(_ref, setLoadingAction) {
17
+ let {
18
+ callback
19
+ } = _ref,
20
+ payload = _objectWithoutPropertiesLoose(_ref, _excluded);
21
+ yield put(setLoadingAction({
22
+ loading: true,
23
+ error: undefined
24
+ }));
25
+ try {
26
+ const data = yield call(api.auth.preVerifyMFAEmailCode, payload);
27
+ yield put(actions.setMfaState({
28
+ otcToken: data.otcToken,
29
+ step: MFAStep.emailVerifyCode
30
+ }));
31
+ yield put(setLoadingAction({
32
+ loading: false,
33
+ error: undefined
34
+ }));
35
+ callback == null ? void 0 : callback(true);
36
+ } catch (e) {
37
+ yield put(setLoadingAction({
38
+ error: errorHandler(e)
39
+ }));
40
+ callback == null ? void 0 : callback(null);
41
+ }
42
+ }
43
+
44
+ /**
45
+ * Shared logic for MFA Email code verify step
46
+ * @param payload.otcToken
47
+ * @param payload.callback callback function to be called after the verification is done with true for success, o.w false
48
+ * @param payload.code 6 digits code input by the user
49
+ */
50
+ export function* verifyMFAEmailCode(_ref2, setLoadingAction) {
51
+ let {
52
+ callback
53
+ } = _ref2,
54
+ payload = _objectWithoutPropertiesLoose(_ref2, _excluded2);
55
+ yield put(setLoadingAction({
56
+ loading: true
57
+ }));
58
+ try {
59
+ const data = yield call(api.auth.verifyMFAEmailCodeV2, payload);
60
+ yield handleVerifyMFAResponse(data);
61
+ yield put(setLoadingAction({
62
+ loading: false,
63
+ error: undefined
64
+ }));
65
+ callback == null ? void 0 : callback(true);
66
+ } catch (e) {
67
+ yield put(setLoadingAction({
68
+ loading: false,
69
+ error: errorHandler(e)
70
+ }));
71
+ callback == null ? void 0 : callback(null);
72
+ }
73
+ }
74
+
75
+ /**
76
+ * Pre verify step for MFA Email login
77
+ * @param payload.mfaToken
78
+ * @param payload.callback callback function to be called after the verification is done
79
+ */
80
+ export function* preVerifyMFAEmailCodeForLogin({
81
+ payload
82
+ }) {
83
+ yield preVerifyMFAEmailCode(payload, actions.setLoginState);
84
+ }
85
+
86
+ /**
87
+ * Verify step for MFA Email login
88
+ * @param payload.otcToken
89
+ * @param payload.callback callback function to be called after the verification is done with true for success, o.w false
90
+ * @param payload.code 6 digits code input by the user
91
+ */
92
+ export function* verifyMFAEmailCodeForLogin({
93
+ payload
94
+ }) {
95
+ yield verifyMFAEmailCode(payload, actions.setLoginState);
96
+ }