From e484b878b19ad2f8f4a2226b5fdb82f58b47c0e2 Mon Sep 17 00:00:00 2001 From: Bryce Kalow Date: Wed, 1 May 2024 14:45:10 -0500 Subject: [PATCH 1/2] fix(elements): Prevent multiple verification codes from being sent at once --- .changeset/violet-lobsters-scream.md | 5 +++++ .../machines/sign-in/verification.machine.ts | 19 +++++++++++++++---- .../react/sign-in/context/router.context.ts | 2 ++ 3 files changed, 22 insertions(+), 4 deletions(-) create mode 100644 .changeset/violet-lobsters-scream.md diff --git a/.changeset/violet-lobsters-scream.md b/.changeset/violet-lobsters-scream.md new file mode 100644 index 00000000000..f533bcefc06 --- /dev/null +++ b/.changeset/violet-lobsters-scream.md @@ -0,0 +1,5 @@ +--- +'@clerk/elements': patch +--- + +Fixes a bug where multiple verification codes were sent at once. diff --git a/packages/elements/src/internals/machines/sign-in/verification.machine.ts b/packages/elements/src/internals/machines/sign-in/verification.machine.ts index 9be31fab59a..d439ddb8f02 100644 --- a/packages/elements/src/internals/machines/sign-in/verification.machine.ts +++ b/packages/elements/src/internals/machines/sign-in/verification.machine.ts @@ -34,9 +34,11 @@ type Parent = ActorRefFrom; export type PrepareFirstFactorInput = WithParams & { parent: Parent; + resendable: boolean; }; export type PrepareSecondFactorInput = WithParams & { parent: Parent; + resendable: boolean; }; export type AttemptFirstFactorInput = { parent: Parent; fields: FormFields; currentFactor: SignInFirstFactor | null }; @@ -171,6 +173,7 @@ const SignInVerificationMachine = setup({ src: 'prepare', input: ({ context }) => ({ parent: context.parent, + resendable: context.resendable, params: context.currentFactor as SignInFirstFactor | null, }), onDone: { @@ -267,10 +270,14 @@ const SignInVerificationMachine = setup({ export const SignInFirstFactorMachine = SignInVerificationMachine.provide({ actors: { prepare: fromPromise(async ({ input }) => { - const { params, parent } = input; + const { params, parent, resendable } = input; const clerk = parent.getSnapshot().context.clerk; - if (!params?.strategy || params.strategy === 'password') { + // If a prepare call has already been fired recently, don't re-send + const currentVerificationExpiration = clerk.client.signIn.firstFactorVerification.expireAt; + const needsPrepare = resendable || !currentVerificationExpiration || currentVerificationExpiration < new Date(); + + if (!params?.strategy || params.strategy === 'password' || !needsPrepare) { return Promise.resolve(clerk.client.signIn); } @@ -359,12 +366,16 @@ export const SignInFirstFactorMachine = SignInVerificationMachine.provide({ export const SignInSecondFactorMachine = SignInVerificationMachine.provide({ actors: { prepare: fromPromise(({ input }) => { - const { params, parent } = input; + const { params, parent, resendable } = input; const clerk = parent.getSnapshot().context.clerk; + // If a prepare call has already been fired recently, don't re-send + const currentVerificationExpiration = clerk.client.signIn.secondFactorVerification.expireAt; + const needsPrepare = resendable || !currentVerificationExpiration || currentVerificationExpiration < new Date(); + assertIsDefined(params); - if (params.strategy !== 'phone_code') { + if (params.strategy !== 'phone_code' || !needsPrepare) { return Promise.resolve(clerk.client.signIn); } diff --git a/packages/elements/src/react/sign-in/context/router.context.ts b/packages/elements/src/react/sign-in/context/router.context.ts index d02bb085b37..69537cdec04 100644 --- a/packages/elements/src/react/sign-in/context/router.context.ts +++ b/packages/elements/src/react/sign-in/context/router.context.ts @@ -35,6 +35,8 @@ export function useSignInRouteRegistration< isMounted.current = true; return () => { + if (isMounted.current) return; + routerRef.send({ type: 'ROUTE.UNREGISTER', id, From aa11e087d6ba2fefb1c9d95856daef675c148d21 Mon Sep 17 00:00:00 2001 From: Bryce Kalow Date: Wed, 1 May 2024 14:47:16 -0500 Subject: [PATCH 2/2] Update packages/elements/src/react/sign-in/context/router.context.ts --- packages/elements/src/react/sign-in/context/router.context.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/elements/src/react/sign-in/context/router.context.ts b/packages/elements/src/react/sign-in/context/router.context.ts index 69537cdec04..d02bb085b37 100644 --- a/packages/elements/src/react/sign-in/context/router.context.ts +++ b/packages/elements/src/react/sign-in/context/router.context.ts @@ -35,8 +35,6 @@ export function useSignInRouteRegistration< isMounted.current = true; return () => { - if (isMounted.current) return; - routerRef.send({ type: 'ROUTE.UNREGISTER', id,