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..e701df1 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 = { @@ -175,10 +178,11 @@ 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. */ - 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 +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 - (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 @@ -198,6 +203,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` */