clerk / clerk/javascript

[@clerk/react v6] <SignIn> sends duplicate email_code on second-factor (MFA) step, distinct from #8463

Open
#9,287 2 comments 2 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
TypeScript
Stars
1.8k
Forks
472
Avg merge
2d 11h
Merged PRs (30d)
189

Description

Reproduction
  1. Instance has password as first factor, email_code as the (only) required second factor / MFA strategy.
  2. Render prebuilt <SignIn routing="path" path="/sign-in" signUpUrl="/sign-up" /> (no custom flow).
  3. Submit correct password. First factor passes cleanly (no duplicate here).
  4. Sign-in transitions to needs_second_factor. Two email_code verification emails arrive ~1 second apart; the first code is invalidated by the second.
Dashboard log evidence (single sign_in_id, single client)
sign_in.attempt_first_factor.passed       strategy=password         (T+0.0s)
sign_in.email_address.verification_code_sent                        (T+0.0s)  <- code #1
sign_in.prepare_second_factor.passed      strategy=email_code, new verification_id (T+0.0s)
sign_in.email_address.verification_code_sent                        (T+1.0s)  <- code #2, invalidates #1

Same sign_in_id, same client_id, same IP across all four events — this is one browser tab, one attempt, not a remount/refresh or a second tab.

Why this looks like a sibling of #8463, not a duplicate report

#8463 (closed, "fixed in Core 3") and #8684/#4324 are about prepareFirstFactor / SignUp.create() re-sending a code on remount or because create() already prepares under the hood before an explicit prepare call fires again.

This reproduces on @clerk/react@6.12.9 (Core 3, current latest), with no remount involved — it's the transition from first-factor success straight into the second-factor (MFA) step, in a single mount. It looks like the same class of bug (backend/widget both send a code for the same verification step) but on the prepareSecondFactor code path specifically, which doesn't appear to have been covered by the Core 3 fix for the first-factor case.

Expected behavior

When a sign-in transitions to needs_second_factor and email_code is the strategy, <SignIn> should resume on whatever verification the backend already prepared for that transition (if any) rather than unconditionally calling prepareSecondFactor() again. A second code should only be sent when the user explicitly clicks "Resend."

Environment
  • @clerk/react: 6.12.9
  • React: 19, Vite 6
  • pk_test_* instance, password + email_code (as second factor/MFA) enabled
  • Reproduces in Chrome (desktop), consistently, every sign-in attempt requiring the second factor
Related
  • #8463 (first-factor/remount case, closed as fixed in Core 3 — this is a different code path)
  • #8684, #4324 (SignUp / prepareFirstFactor variants of the same "double prepare" pattern)

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the prebuilt @clerk/react flow and the transition from needs_second_factor after password success. Trace where prepareSecondFactor() is called and compare it with the backend-prepared verification shown in the dashboard events. Reproduce with password plus email_code MFA, then confirm that only an explicit Resend sends another code.

Written by the indexing model from the issue text.

Assessment

Tech stack
react, typescript
Domain
authentication, frontend
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
50/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.