From d49b4778c04a3e5647b263377a9ff345937151f0 Mon Sep 17 00:00:00 2001 From: Incorbador Date: Mon, 24 Feb 2025 09:57:06 +0100 Subject: [PATCH 1/4] Add generic fallback handling --- .../login-second-factor/InitScreen.tsx | 6 +- .../components/login/LoginErrorScreenHard.tsx | 25 +++++- .../components/login/LoginErrorScreenSoft.tsx | 23 ++++++ .../src/components/login/LoginInitScreen.tsx | 82 ++++++++----------- .../login/LoginPasskeyReLoginScreen.tsx | 25 +++++- .../connect-react/src/types/situations.ts | 12 +-- packages/web-core/openapi/spec_v2.yaml | 19 ++++- packages/web-core/src/api/v2/api.ts | 35 +++++++- .../web-core/src/services/ConnectService.ts | 6 -- packages/web-core/src/utils/errors/errors.ts | 21 ----- 10 files changed, 157 insertions(+), 97 deletions(-) diff --git a/packages/connect-react/src/components/login-second-factor/InitScreen.tsx b/packages/connect-react/src/components/login-second-factor/InitScreen.tsx index 200eced50..2b98df47b 100644 --- a/packages/connect-react/src/components/login-second-factor/InitScreen.tsx +++ b/packages/connect-react/src/components/login-second-factor/InitScreen.tsx @@ -1,4 +1,4 @@ -import { ConnectUserNotFound, PasskeyChallengeCancelledError, PasskeyLoginSource } from '@corbado/web-core'; +import { PasskeyChallengeCancelledError, PasskeyLoginSource } from '@corbado/web-core'; import type { ConnectLoginStartRsp } from '@corbado/web-core/dist/api/v2'; import log from 'loglevel'; import React, { useEffect, useRef, useState } from 'react'; @@ -79,10 +79,6 @@ const InitScreen = () => { return; } - if (resStart.val instanceof ConnectUserNotFound) { - return handleSituation(LoginSituationCode.PreAuthenticatorUserNotFound); - } - return handleSituation(LoginSituationCode.CboApiNotAvailablePreAuthenticator); } diff --git a/packages/connect-react/src/components/login/LoginErrorScreenHard.tsx b/packages/connect-react/src/components/login/LoginErrorScreenHard.tsx index 622969adf..200529c7c 100644 --- a/packages/connect-react/src/components/login/LoginErrorScreenHard.tsx +++ b/packages/connect-react/src/components/login/LoginErrorScreenHard.tsx @@ -7,7 +7,7 @@ import useShared from '../../hooks/useShared'; import { LoginScreenType } from '../../types/screenTypes'; import { getLoginErrorMessage, LoginSituationCode } from '../../types/situations'; import LoginErrorHard from './base/LoginErrorHard'; -import { connectLoginFinishToComplete } from './LoginInitScreen'; +import { type CboApiFallbackOperationError, connectLoginFinishToComplete } from './LoginInitScreen'; type Props = { previousAssertionOptions: string; @@ -32,6 +32,16 @@ const LoginErrorScreenHard = ({ previousAssertionOptions }: Props) => { return handleSituation(LoginSituationCode.CboApiNotAvailablePreAuthenticator); } + if (resStart.val.assertionOptions.length === 0) { + const data: CboApiFallbackOperationError = { + initFallback: resStart.val.fallbackOperationError.initFallback, + identifierFallback: resStart.val.fallbackOperationError.identifier ?? '', + message: resStart.val.fallbackOperationError.error?.message ?? null, + }; + + return handleSituation(LoginSituationCode.CboApiFallbackOperationError, data); + } + setAssertionOptions(resStart.val.assertionOptions); const resFinish = await getConnectService().loginContinue(resStart.val); @@ -56,7 +66,7 @@ const LoginErrorScreenHard = ({ previousAssertionOptions }: Props) => { } }; - const handleSituation = (situationCode: LoginSituationCode) => { + const handleSituation = (situationCode: LoginSituationCode, data?: unknown) => { const messageCode = `situation: ${situationCode}`; log.debug(messageCode); @@ -92,6 +102,17 @@ const LoginErrorScreenHard = ({ previousAssertionOptions }: Props) => { void getConnectService().recordEventLoginExplicitAbort(assertionOptions); break; + case LoginSituationCode.CboApiFallbackOperationError: { + const { initFallback, identifierFallback, message } = data as CboApiFallbackOperationError; + if (initFallback) { + navigateToScreen(LoginScreenType.Invisible); + fallback(identifierFallback, message); + } + void getConnectService().recordEventLoginError(messageCode); + + setLoading(false); + break; + } } }; diff --git a/packages/connect-react/src/components/login/LoginErrorScreenSoft.tsx b/packages/connect-react/src/components/login/LoginErrorScreenSoft.tsx index 42f89a395..61d6646b3 100644 --- a/packages/connect-react/src/components/login/LoginErrorScreenSoft.tsx +++ b/packages/connect-react/src/components/login/LoginErrorScreenSoft.tsx @@ -7,6 +7,7 @@ import useShared from '../../hooks/useShared'; import { LoginScreenType } from '../../types/screenTypes'; import { getLoginErrorMessage, LoginSituationCode } from '../../types/situations'; import LoginErrorSoft from './base/LoginErrorSoft'; +import type { CboApiFallbackOperationError } from './LoginInitScreen'; import { connectLoginFinishToComplete } from './LoginInitScreen'; type Props = { @@ -30,6 +31,16 @@ const LoginErrorScreenSoft = ({ previousAssertionOptions }: Props) => { return handleSituation(LoginSituationCode.CboApiNotAvailablePreAuthenticator); } + if (resStart.val.assertionOptions.length === 0) { + const data: CboApiFallbackOperationError = { + initFallback: resStart.val.fallbackOperationError.initFallback, + identifierFallback: resStart.val.fallbackOperationError.identifier ?? '', + message: resStart.val.fallbackOperationError.error?.message ?? null, + }; + + return handleSituation(LoginSituationCode.CboApiFallbackOperationError, data); + } + const resFinish = await getConnectService().loginContinue(resStart.val); if (resFinish.err) { if (resFinish.val instanceof PasskeyChallengeCancelledError) { @@ -55,6 +66,7 @@ const LoginErrorScreenSoft = ({ previousAssertionOptions }: Props) => { const message = getLoginErrorMessage(situationCode); switch (situationCode) { + case LoginSituationCode.CboApiNotAvailablePreAuthenticator: case LoginSituationCode.CtApiNotAvailablePostAuthenticator: case LoginSituationCode.CboApiNotAvailablePostAuthenticator: navigateToScreen(LoginScreenType.Invisible); @@ -79,6 +91,17 @@ const LoginErrorScreenSoft = ({ previousAssertionOptions }: Props) => { void getConnectService().recordEventLoginExplicitAbort(previousAssertionOptions); break; } + case LoginSituationCode.CboApiFallbackOperationError: { + const { initFallback, identifierFallback, message } = data as CboApiFallbackOperationError; + if (initFallback) { + navigateToScreen(LoginScreenType.Invisible); + fallback(identifierFallback, message); + } + void getConnectService().recordEventLoginError(messageCode); + + setLoading(false); + break; + } } }; diff --git a/packages/connect-react/src/components/login/LoginInitScreen.tsx b/packages/connect-react/src/components/login/LoginInitScreen.tsx index b7efcbe7d..f8fd81011 100644 --- a/packages/connect-react/src/components/login/LoginInitScreen.tsx +++ b/packages/connect-react/src/components/login/LoginInitScreen.tsx @@ -1,12 +1,4 @@ -import { - ConnectConditionalUIPasskeyDeleted, - ConnectCustomError, - ConnectExistingPasskeysNotAvailable, - ConnectNoPasskeyAvailableError, - ConnectUserNotFound, - PasskeyChallengeCancelledError, - PasskeyLoginSource, -} from '@corbado/web-core'; +import { PasskeyChallengeCancelledError, PasskeyLoginSource } from '@corbado/web-core'; import type { ConnectLoginFinishRsp } from '@corbado/web-core/dist/api/v2'; import log from 'loglevel'; import type { FC } from 'react'; @@ -16,12 +8,17 @@ import useLoginProcess from '../../hooks/useLoginProcess'; import useShared from '../../hooks/useShared'; import { Flags } from '../../types/flags'; import { LoginScreenType } from '../../types/screenTypes'; -import type { PreAuthenticatorCustomErrorData } from '../../types/situations'; import { getLoginErrorMessage, LoginSituationCode } from '../../types/situations'; import { StatefulLoader } from '../../utils/statefulLoader'; import LoginInitLoaded from './base/LoginInitLoaded'; import LoginInitLoading from './base/LoginInitLoading'; +export type CboApiFallbackOperationError = { + initFallback: boolean; + identifierFallback: string; + message: string | null; +}; + export enum LoginInitState { SilentLoading, Loading, @@ -42,8 +39,7 @@ export const connectLoginFinishToComplete = (v: ConnectLoginFinishRsp): string = }; const LoginInitScreen: FC = ({ showFallback = false }) => { - const { config, navigateToScreen, setCurrentIdentifier, setFlags, flags, loadedMs, fallback, fallbackCustom } = - useLoginProcess(); + const { config, navigateToScreen, setCurrentIdentifier, setFlags, flags, loadedMs, fallback } = useLoginProcess(); const { sharedConfig, getConnectService } = useShared(); const [cuiBasedLoading, setCuiBasedLoading] = useState(false); const [identifierBasedLoading, setIdentifierBasedLoading] = useState(false); @@ -160,11 +156,6 @@ const LoginInitScreen: FC = ({ showFallback = false }) => { return handleSituation(LoginSituationCode.ClientPasskeyConditionalOperationCancelled); } - // if a passkey has been deleted, CUI will fail => fallback with message - if (res.val instanceof ConnectConditionalUIPasskeyDeleted) { - return handleSituation(LoginSituationCode.PasskeyNotAvailablePostConditionalAuthenticator); - } - // cuiStarted === true indicates that user has passed the authenticator if (cuiStarted) { return handleSituation(LoginSituationCode.CboApiNotAvailablePostConditionalAuthenticator); @@ -173,6 +164,16 @@ const LoginInitScreen: FC = ({ showFallback = false }) => { return handleSituation(LoginSituationCode.CboApiNotAvailablePreConditionalAuthenticator); } + if (res.val.fallbackOperationError) { + const data: CboApiFallbackOperationError = { + initFallback: res.val.fallbackOperationError.initFallback, + identifierFallback: res.val.fallbackOperationError.identifier ?? '', + message: res.val.fallbackOperationError.error?.message ?? null, + }; + + return handleSituation(LoginSituationCode.CboApiFallbackOperationError, data); + } + try { await config.onComplete(connectLoginFinishToComplete(res.val)); } catch { @@ -191,19 +192,6 @@ const LoginInitScreen: FC = ({ showFallback = false }) => { const resStart = await getConnectService().loginStart(identifier, PasskeyLoginSource.TextField, loadedMs); if (resStart.err) { - if (resStart.val instanceof ConnectUserNotFound) { - return handleSituation(LoginSituationCode.PreAuthenticatorUserNotFound); - } - if (resStart.val instanceof ConnectCustomError) { - return handleSituation(LoginSituationCode.PreAuthenticatorCustomError, resStart.val); - } - if (resStart.val instanceof ConnectExistingPasskeysNotAvailable) { - return handleSituation(LoginSituationCode.PreAuthenticatorExistingPasskeysNotAvailable); - } - if (resStart.val instanceof ConnectNoPasskeyAvailableError) { - return handleSituation(LoginSituationCode.PreAuthenticatorNoPasskeyAvailable); - } - return handleSituation(LoginSituationCode.CboApiNotAvailablePreAuthenticator); } @@ -212,6 +200,16 @@ const LoginInitScreen: FC = ({ showFallback = false }) => { return; } + if (resStart.val.assertionOptions.length === 0) { + const data: CboApiFallbackOperationError = { + initFallback: resStart.val.fallbackOperationError.initFallback, + identifierFallback: resStart.val.fallbackOperationError.identifier ?? '', + message: resStart.val.fallbackOperationError.error?.message ?? null, + }; + + return handleSituation(LoginSituationCode.CboApiFallbackOperationError, data); + } + const res = await getConnectService().loginContinue(resStart.val); if (res.err) { setIdentifierBasedLoading(false); @@ -255,13 +253,10 @@ const LoginInitScreen: FC = ({ showFallback = false }) => { statefulLoader.current.finish(); break; case LoginSituationCode.DeniedByPartialRollout: - case LoginSituationCode.PreAuthenticatorExistingPasskeysNotAvailable: - case LoginSituationCode.PreAuthenticatorNoPasskeyAvailable: automaticFallback(identifier, message); statefulLoader.current.finish(); break; - case LoginSituationCode.PasskeyNotAvailablePostConditionalAuthenticator: case LoginSituationCode.CboApiNotAvailablePostConditionalAuthenticator: case LoginSituationCode.CboApiNotAvailablePreConditionalAuthenticator: case LoginSituationCode.CtApiNotAvailablePostAuthenticator: @@ -280,26 +275,21 @@ const LoginInitScreen: FC = ({ showFallback = false }) => { setIdentifierBasedLoading(false); break; } - case LoginSituationCode.PreAuthenticatorUserNotFound: - setError(message ?? ''); - void getConnectService().recordEventLoginErrorUnexpected(messageCode); - - setIdentifierBasedLoading(false); - break; case LoginSituationCode.ExplicitFallbackByUser: explicitFallback(); void getConnectService().recordEventLoginExplicitAbort(); break; - case LoginSituationCode.PreAuthenticatorCustomError: { - navigateToScreen(LoginScreenType.Invisible); - void getConnectService().recordEventLoginErrorUnexpected(messageCode); - if (!data) { - return fallback(identifier, null); + case LoginSituationCode.CboApiFallbackOperationError: { + const typed = data as CboApiFallbackOperationError; + + if (typed.initFallback) { + return automaticFallback(typed.identifierFallback, typed.message); } - const typed = data as PreAuthenticatorCustomErrorData; - fallbackCustom(identifier, typed.code, typed.message); + setError(message ?? ''); + setIdentifierBasedLoading(false); + break; } } }; diff --git a/packages/connect-react/src/components/login/LoginPasskeyReLoginScreen.tsx b/packages/connect-react/src/components/login/LoginPasskeyReLoginScreen.tsx index a9f4d44c8..1233d766f 100644 --- a/packages/connect-react/src/components/login/LoginPasskeyReLoginScreen.tsx +++ b/packages/connect-react/src/components/login/LoginPasskeyReLoginScreen.tsx @@ -7,7 +7,7 @@ import useShared from '../../hooks/useShared'; import { LoginScreenType } from '../../types/screenTypes'; import { getLoginErrorMessage, LoginSituationCode } from '../../types/situations'; import LoginOneTap from './base/LoginOneTap'; -import { connectLoginFinishToComplete } from './LoginInitScreen'; +import { type CboApiFallbackOperationError, connectLoginFinishToComplete } from './LoginInitScreen'; export const LoginPasskeyReLoginScreen = () => { const { config, navigateToScreen, setCurrentIdentifier, currentIdentifier, loadedMs, fallback } = useLoginProcess(); @@ -32,6 +32,16 @@ export const LoginPasskeyReLoginScreen = () => { return handleSituation(LoginSituationCode.CboApiNotAvailablePreAuthenticator); } + if (resStart.val.assertionOptions.length === 0) { + const data = { + initFallback: resStart.val.fallbackOperationError.initFallback, + identifierFallback: resStart.val.fallbackOperationError.identifier ?? '', + message: resStart.val.fallbackOperationError.error?.message ?? null, + }; + + return handleSituation(LoginSituationCode.CboApiFallbackOperationError, data); + } + const resFinish = await getConnectService().loginContinue(resStart.val); if (resFinish.err) { if (resFinish.val instanceof PasskeyChallengeCancelledError) { @@ -53,7 +63,7 @@ export const LoginPasskeyReLoginScreen = () => { navigateToScreen(LoginScreenType.Init, { prefilledIdentifier: identifier }); }; - const handleSituation = (situationCode: LoginSituationCode) => { + const handleSituation = (situationCode: LoginSituationCode, data?: unknown) => { const messageCode = `situation: ${situationCode}`; log.debug(messageCode); @@ -77,6 +87,17 @@ export const LoginPasskeyReLoginScreen = () => { setLoading(false); break; + case LoginSituationCode.CboApiFallbackOperationError: { + const { initFallback, identifierFallback, message } = data as CboApiFallbackOperationError; + if (initFallback) { + navigateToScreen(LoginScreenType.Invisible); + fallback(identifierFallback, message); + } + void getConnectService().recordEventLoginError(messageCode); + + setLoading(false); + break; + } } }; diff --git a/packages/connect-react/src/types/situations.ts b/packages/connect-react/src/types/situations.ts index 89f9335e9..5c3ad2e24 100644 --- a/packages/connect-react/src/types/situations.ts +++ b/packages/connect-react/src/types/situations.ts @@ -14,6 +14,7 @@ export enum LoginSituationCode { PreAuthenticatorCustomError, PreAuthenticatorExistingPasskeysNotAvailable, PreAuthenticatorNoPasskeyAvailable, + CboApiFallbackOperationError, } export enum AppendSituationCode { @@ -41,11 +42,6 @@ export enum PasskeyListSituationCode { CboApiPasskeysNotSupportedLight, } -export type PreAuthenticatorCustomErrorData = { - code: string; - message: string; -}; - export const getLoginErrorMessage = (code: LoginSituationCode): string | null => { switch (code) { case LoginSituationCode.CboApiNotAvailablePostAuthenticator: @@ -54,12 +50,6 @@ export const getLoginErrorMessage = (code: LoginSituationCode): string | null => case LoginSituationCode.ClientPasskeyOperationCancelledTooManyTimes: return "We couldn't log you in with your passkey due to a system error. Use your password to log in instead."; - case LoginSituationCode.PasskeyNotAvailablePostConditionalAuthenticator: - return 'You previously deleted this passkey. Use your password to log in instead.'; - - case LoginSituationCode.PreAuthenticatorUserNotFound: - return 'There is no account registered to that email address.'; - default: return null; } diff --git a/packages/web-core/openapi/spec_v2.yaml b/packages/web-core/openapi/spec_v2.yaml index d9d8c8f3a..a1a4cd677 100644 --- a/packages/web-core/openapi/spec_v2.yaml +++ b/packages/web-core/openapi/spec_v2.yaml @@ -1254,13 +1254,14 @@ components: required: - assertionOptions - isCDA + - fallbackOperationError properties: assertionOptions: type: string isCDA: type: boolean - error: - $ref: '#/components/schemas/requestError' + fallbackOperationError: + $ref: '#/components/schemas/fallbackOperationError' connectLoginFinishReq: type: object @@ -1289,6 +1290,8 @@ components: type: string signedPasskeyData: type: string + fallbackOperationError: + $ref: '#/components/schemas/fallbackOperationError' connectAppendInitReq: type: object @@ -2093,6 +2096,18 @@ components: message: type: string + fallbackOperationError: + type: object + required: + - initFallback + properties: + initFallback: + type: boolean + identifier: + type: string + error: + $ref: '#/components/schemas/requestError' + responses: '200': description: Operation succeeded diff --git a/packages/web-core/src/api/v2/api.ts b/packages/web-core/src/api/v2/api.ts index e775e1bb1..bdf88351e 100644 --- a/packages/web-core/src/api/v2/api.ts +++ b/packages/web-core/src/api/v2/api.ts @@ -476,6 +476,12 @@ export interface ConnectLoginFinishRsp { * @memberof ConnectLoginFinishRsp */ 'signedPasskeyData': string; + /** + * + * @type {FallbackOperationError} + * @memberof ConnectLoginFinishRsp + */ + 'fallbackOperationError'?: FallbackOperationError; } /** * @@ -618,10 +624,10 @@ export interface ConnectLoginStartRsp { 'isCDA': boolean; /** * - * @type {RequestError} + * @type {FallbackOperationError} * @memberof ConnectLoginStartRsp */ - 'error'?: RequestError; + 'fallbackOperationError': FallbackOperationError; } /** * @@ -829,6 +835,31 @@ export interface EventCreateReq { } +/** + * + * @export + * @interface FallbackOperationError + */ +export interface FallbackOperationError { + /** + * + * @type {boolean} + * @memberof FallbackOperationError + */ + 'initFallback': boolean; + /** + * + * @type {string} + * @memberof FallbackOperationError + */ + 'identifier'?: string; + /** + * + * @type {RequestError} + * @memberof FallbackOperationError + */ + 'error'?: RequestError; +} /** * * @export diff --git a/packages/web-core/src/services/ConnectService.ts b/packages/web-core/src/services/ConnectService.ts index 57afd2a5c..3c23535c9 100644 --- a/packages/web-core/src/services/ConnectService.ts +++ b/packages/web-core/src/services/ConnectService.ts @@ -252,14 +252,8 @@ export class ConnectService { return res; } - if (res.val.error) { - this.clearLastLogin(); - return Err(CorbadoError.fromConnectErrorResponse(res.val.error)); - } - if (!res.val.assertionOptions) { this.clearLastLogin(); - return Err(CorbadoError.noPasskeyAvailable()); } return res; diff --git a/packages/web-core/src/utils/errors/errors.ts b/packages/web-core/src/utils/errors/errors.ts index 82e8bc47b..8b57146f6 100644 --- a/packages/web-core/src/utils/errors/errors.ts +++ b/packages/web-core/src/utils/errors/errors.ts @@ -2,7 +2,6 @@ import type { AxiosError } from 'axios'; import log from 'loglevel'; import type { ErrorRsp } from '../../api/v1'; -import type { RequestError } from '../../api/v2'; /** General Errors */ export type GetProcessError = ProcessNotFound; @@ -84,17 +83,6 @@ export class CorbadoError extends Error { return NonRecoverableError.unhandledBackendError(errorResp.type); } - static fromConnectErrorResponse(error: RequestError): RecoverableError { - switch (error.code) { - case 'user_not_found': - return new ConnectUserNotFound(); - case 'existing_passkeys_not_available': - return new ConnectExistingPasskeysNotAvailable(); - default: - return new ConnectCustomError(error.code, error.message); - } - } - static fromConnectAxiosError(error: AxiosError): RecoverableError | NonRecoverableError { log.debug('axios error', error); @@ -110,15 +98,6 @@ export class CorbadoError extends Error { return NonRecoverableError.unhandledBackendError('no_data_in_response'); } - const url = error.config?.url; - if (error.response.status === 404 && url) { - if (url.endsWith('/connect/login/finish')) { - return new ConnectConditionalUIPasskeyDeleted(); - } - - return new ConnectUserNotFound(); - } - const errorRespRaw = error.response.data as ErrorRsp; log.debug('errorRespRaw', errorRespRaw.error.type); const errorResp = errorRespRaw.error; From 33f87eb37fd95769349b098a4e5ace38d2adbb6b Mon Sep 17 00:00:00 2001 From: Incorbador Date: Mon, 24 Feb 2025 11:32:44 +0100 Subject: [PATCH 2/4] Fix error message --- packages/connect-react/src/components/login/LoginInitScreen.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/connect-react/src/components/login/LoginInitScreen.tsx b/packages/connect-react/src/components/login/LoginInitScreen.tsx index f8fd81011..8988bd995 100644 --- a/packages/connect-react/src/components/login/LoginInitScreen.tsx +++ b/packages/connect-react/src/components/login/LoginInitScreen.tsx @@ -287,7 +287,7 @@ const LoginInitScreen: FC = ({ showFallback = false }) => { return automaticFallback(typed.identifierFallback, typed.message); } - setError(message ?? ''); + setError(typed.message ?? ''); setIdentifierBasedLoading(false); break; } From 7e832507cf2e909e6a8d56b0410d051240a067a9 Mon Sep 17 00:00:00 2001 From: Incorbador Date: Mon, 24 Feb 2025 17:33:43 +0100 Subject: [PATCH 3/4] Stop wrong login error collection --- packages/web-core/src/services/ProcessService.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/web-core/src/services/ProcessService.ts b/packages/web-core/src/services/ProcessService.ts index 69eaea74f..9eed55773 100644 --- a/packages/web-core/src/services/ProcessService.ts +++ b/packages/web-core/src/services/ProcessService.ts @@ -566,7 +566,7 @@ export class ProcessService { ): Promise> { const signedChallenge = await this.#webAuthnService.login(challenge, true); if (signedChallenge.err) { - if (!(signedChallenge.val.ignore && signedChallenge.val instanceof PasskeyChallengeCancelledError)) { + if (!signedChallenge.val.ignore && !(signedChallenge.val instanceof PasskeyChallengeCancelledError)) { await this.recordEventLoginError(challenge); } From fe53ab7b302f04f8d0ba4b1858e13ef0b4851a13 Mon Sep 17 00:00:00 2001 From: Incorbador Date: Tue, 25 Feb 2025 09:05:51 +0100 Subject: [PATCH 4/4] Manage cui loading state --- packages/connect-react/src/components/login/LoginInitScreen.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/connect-react/src/components/login/LoginInitScreen.tsx b/packages/connect-react/src/components/login/LoginInitScreen.tsx index 8988bd995..70c4f92b5 100644 --- a/packages/connect-react/src/components/login/LoginInitScreen.tsx +++ b/packages/connect-react/src/components/login/LoginInitScreen.tsx @@ -288,6 +288,7 @@ const LoginInitScreen: FC = ({ showFallback = false }) => { } setError(typed.message ?? ''); + setCuiBasedLoading(false); setIdentifierBasedLoading(false); break; }