Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/lib/src/features/clerk/hooks/use-auth-with-identifier.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 };
Expand Down
50 changes: 20 additions & 30 deletions src/lib/src/features/clerk/hooks/use-otp-verification.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,23 +17,19 @@ export function useOtpVerification(): UseOtpVerificationReturn {
const { getSessionToken } = useGetSessionToken();
const [isVerifying, setIsVerifying] = useState(false);

const sendSignInOtpCode = async (strategy: OtpStrategy): Promise<void> => {
const codeFactor = signIn?.supportedFirstFactors?.find(
const sendSignInOtpCode = async (strategy: OtpStrategy, isSecondFactor: boolean = false): Promise<void> => {
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}`);
}
};

Expand All @@ -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);

Expand Down Expand Up @@ -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 };
}
}

Expand Down
8 changes: 7 additions & 1 deletion src/lib/src/features/clerk/types/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
PhoneNumberResource,
SetActive,
SignInResource,
SignInStatus,
SignOut,
SignUpCreateParams,
SignUpResource,
Expand All @@ -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 = {
Expand Down Expand Up @@ -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<void>;
sendOtpCode: (params: { strategy: OtpStrategy; isSignUp: boolean; isSecondFactor?: boolean }) => Promise<void>;

/**
* Verifies the OTP code entered by the user.
Expand All @@ -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
Expand All @@ -198,6 +203,7 @@ export interface UseOtpVerificationReturn {
strategy: OtpStrategy;
isSignUp: boolean;
tokenTemplate?: string;
isSecondFactor?: boolean;
}) => Promise<AuthorizationFinishedReturn>;

/** Indicates whether the OTP verification process is currently in progress. `true` or `false` */
Expand Down
Loading