From 6a8418193dfca1d17ff8ad87d54636a05ca2938f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=B0=D1=81=D0=B8=D0=BB=D0=B8=D0=B9=20=D0=95=D0=BB?= =?UTF-8?q?=D0=B8=D1=81=D0=B5=D0=B5=D0=B2?= Date: Wed, 4 Mar 2026 09:30:40 +0600 Subject: [PATCH 1/2] feat: add handling clinet trust case --- .../clerk/hooks/use-auth-with-identifier.ts | 2 + .../clerk/hooks/use-otp-verification.ts | 50 ++++++++----------- src/lib/src/features/clerk/types/types.ts | 7 ++- 3 files changed, 28 insertions(+), 31 deletions(-) diff --git a/src/lib/src/features/clerk/hooks/use-auth-with-identifier.ts b/src/lib/src/features/clerk/hooks/use-auth-with-identifier.ts index 2204d77..adb3fe5 100644 --- a/src/lib/src/features/clerk/hooks/use-auth-with-identifier.ts +++ b/src/lib/src/features/clerk/hooks/use-auth-with-identifier.ts @@ -108,6 +108,8 @@ export function useAuthWithIdentifier< if (authAttempt?.status === 'complete' && 'createdSessionId' in authAttempt) { return handleSignInWithPassword(authAttempt as SignInResource, isSignUp, tokenTemplate); + } else { + return { isSuccess: false, signIn, signUp, status: authAttempt?.status, error: null }; } } catch (error) { return { error, signIn, signUp }; diff --git a/src/lib/src/features/clerk/hooks/use-otp-verification.ts b/src/lib/src/features/clerk/hooks/use-otp-verification.ts index 83034c9..166217a 100644 --- a/src/lib/src/features/clerk/hooks/use-otp-verification.ts +++ b/src/lib/src/features/clerk/hooks/use-otp-verification.ts @@ -17,23 +17,19 @@ export function useOtpVerification(): UseOtpVerificationReturn { const { getSessionToken } = useGetSessionToken(); const [isVerifying, setIsVerifying] = useState(false); - const sendSignInOtpCode = async (strategy: OtpStrategy): Promise => { - const codeFactor = signIn?.supportedFirstFactors?.find( + const sendSignInOtpCode = async (strategy: OtpStrategy, isSecondFactor: boolean = false): Promise => { + const codeFactors = isSecondFactor ? signIn?.supportedSecondFactors : signIn?.supportedFirstFactors; + const prepareFactor = isSecondFactor ? signIn?.prepareSecondFactor : signIn?.prepareFirstFactor; + const codeFactor = codeFactors?.find( (factor): factor is EmailCodeFactor | PhoneCodeFactor => factor.strategy === strategy, ); if (codeFactor && 'emailAddressId' in codeFactor) { - await signIn?.prepareFirstFactor({ - strategy: 'email_code', - emailAddressId: codeFactor.emailAddressId, - }); + await prepareFactor?.({ strategy: 'email_code', emailAddressId: codeFactor.emailAddressId }); } else if (codeFactor && 'phoneNumberId' in codeFactor) { - await signIn?.prepareFirstFactor({ - strategy: 'phone_code', - phoneNumberId: codeFactor.phoneNumberId, - }); + await prepareFactor?.({ strategy: 'phone_code', phoneNumberId: codeFactor.phoneNumberId }); } else { - throw new Error('No code factor found for strategy: ' + strategy); + throw new Error(`No ${isSecondFactor ? 'second ' : ''}factor found for strategy: ${strategy}`); } }; @@ -42,15 +38,21 @@ export function useOtpVerification(): UseOtpVerificationReturn { await signUp.prepareVerification({ strategy }); }; - const sendOtpCode: UseOtpVerificationReturn['sendOtpCode'] = async ({ strategy, isSignUp }) => { + const sendOtpCode: UseOtpVerificationReturn['sendOtpCode'] = async ({ strategy, isSignUp, isSecondFactor }) => { if (isSignUp) { await sendSignUpOtpCode(strategy); } else { - await sendSignInOtpCode(strategy); + await sendSignInOtpCode(strategy, !!isSecondFactor); } }; - const verifyCode: UseOtpVerificationReturn['verifyCode'] = async ({ code, strategy, tokenTemplate, isSignUp }) => { + const verifyCode: UseOtpVerificationReturn['verifyCode'] = async ({ + code, + strategy, + tokenTemplate, + isSignUp, + isSecondFactor, + }) => { try { setIsVerifying(true); @@ -81,30 +83,18 @@ export function useOtpVerification(): UseOtpVerificationReturn { }; } } else { - const completeSignIn = await signIn?.attemptFirstFactor({ - strategy, - code, - }); + const attemptSignIn = isSecondFactor ? signIn?.attemptSecondFactor : signIn?.attemptFirstFactor; + const completeSignIn = await attemptSignIn?.({ strategy, code }); if (completeSignIn?.status === 'complete') { await setActive?.({ session: completeSignIn.createdSessionId }); const sessionToken = (await getSessionToken({ tokenTemplate })).sessionToken; if (sessionToken) { - return { - sessionToken, - signIn, - signUp, - isSuccess: true, - }; + return { sessionToken, signIn, signUp, isSuccess: true }; } - return { - sessionToken: null, - signIn, - signUp, - isSuccess: false, - }; + return { sessionToken: null, signIn, signUp, isSuccess: false }; } } diff --git a/src/lib/src/features/clerk/types/types.ts b/src/lib/src/features/clerk/types/types.ts index 084519c..50a01e6 100644 --- a/src/lib/src/features/clerk/types/types.ts +++ b/src/lib/src/features/clerk/types/types.ts @@ -5,6 +5,7 @@ import { PhoneNumberResource, SetActive, SignInResource, + SignInStatus, SignOut, SignUpCreateParams, SignUpResource, @@ -25,6 +26,8 @@ type WithTokenFailureReturn = BaseFailureReturn & { sessionToken?: null }; type WithSignInReturn = { /** Provides access to SignIn object: https://clerk.com/docs/references/javascript/sign-in */ signIn?: SignInResource; + /** The current status of the sign-in. */ + status?: SignInStatus; }; type WithSignUpReturn = { @@ -178,7 +181,7 @@ export interface UseOtpVerificationReturn { * * @returns A Promise that resolves once the OTP has been successfully sent, or rejects if sending fails. */ - sendOtpCode: (params: { strategy: OtpStrategy; isSignUp: boolean }) => Promise; + sendOtpCode: (params: { strategy: OtpStrategy; isSignUp: boolean; isSecondFactor?: boolean }) => Promise; /** * Verifies the OTP code entered by the user. @@ -188,6 +191,7 @@ export interface UseOtpVerificationReturn { * @param params.strategy - The strategy used to send the code (`'email_code'` or `'phone_code'`). * @param params.tokenTemplate - (Optional) The name of the token template to use when retrieving the session token. * @param isSignUp - Indicates whether the OTP flow is used for sign-up (true) or sign-in (false) + * @param isSecondFactor - Indicates whether the OTP flow is used for a second factor verification (true) or not (false) * * @returns A Promise that resolves to: * - `{ isSuccess: true, sessionToken: string, signIn?, signUp? }` on success @@ -198,6 +202,7 @@ export interface UseOtpVerificationReturn { strategy: OtpStrategy; isSignUp: boolean; tokenTemplate?: string; + isSecondFactor?: boolean; }) => Promise; /** Indicates whether the OTP verification process is currently in progress. `true` or `false` */ From 8ba0b46cb3ea4e5e202fe3b927afa3df62a12527 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=B0=D1=81=D0=B8=D0=BB=D0=B8=D0=B9=20=D0=95=D0=BB?= =?UTF-8?q?=D0=B8=D1=81=D0=B5=D0=B5=D0=B2?= Date: Wed, 4 Mar 2026 09:36:55 +0600 Subject: [PATCH 2/2] refactor: extend types of send otp code method --- src/lib/src/features/clerk/types/types.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/lib/src/features/clerk/types/types.ts b/src/lib/src/features/clerk/types/types.ts index 50a01e6..e701df1 100644 --- a/src/lib/src/features/clerk/types/types.ts +++ b/src/lib/src/features/clerk/types/types.ts @@ -178,6 +178,7 @@ export interface UseOtpVerificationReturn { * - `'email_code'` – send code via email * - `'phone_code'` – send code via SMS * @param isSignUp - Indicates whether the OTP flow is used for sign-up (true) or sign-in (false) + * @param isSecondFactor - (Optional) Indicates whether the OTP flow is used for a second factor verification (true) or not (false) * * @returns A Promise that resolves once the OTP has been successfully sent, or rejects if sending fails. */ @@ -191,7 +192,7 @@ export interface UseOtpVerificationReturn { * @param params.strategy - The strategy used to send the code (`'email_code'` or `'phone_code'`). * @param params.tokenTemplate - (Optional) The name of the token template to use when retrieving the session token. * @param isSignUp - Indicates whether the OTP flow is used for sign-up (true) or sign-in (false) - * @param isSecondFactor - Indicates whether the OTP flow is used for a second factor verification (true) or not (false) + * @param isSecondFactor - (Optional) Indicates whether the OTP flow is used for a second factor verification (true) or not (false) * * @returns A Promise that resolves to: * - `{ isSuccess: true, sessionToken: string, signIn?, signUp? }` on success