<UserProfile />: SMS "Set as default" shows the raw reverification error instead of launching reverification, and has no effect while an authenticator app is enrolled
Maintainers usually reply within 1 day
Nobody has claimed this yet.
Assessment
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Newbie friendliness
- 50/100
- Issue type
- Bug
- Clarity
- Mostly clear
- Activity status
- Active
- Tech stack
- react, typescript
- Domain
- authentication, frontend
Research direction
Start with packages/ui/src/components/UserProfile/MfaSection.tsx, then trace determineStartingSignInSecondFactor in packages/ui/src/components/SignIn/utils.ts and UserVerificationFactorTwo.tsx. Reproduce with both TOTP and SMS enabled, outside the reverification window. Done means the SMS action has consistent reverification, default-state display, and sign-in or reverification factor selection behavior.
Written by the indexing model from the issue text.
Description
Preliminary Checks
- I have reviewed the documentation: https://clerk.com/docs
- I have searched for existing issues: https://github.com/clerk/javascript/issues
- I have not already reached out to Clerk support via email or Discord
- This issue is not a question, general help request, or anything other than a bug report directly related to Clerk.
Reproduction
No hosted reproduction. The behaviour is in the prebuilt <UserProfile /> and <SignIn /> components themselves, and needs no custom code. Every source line is linked below. You can reproduce it in any app that renders <UserProfile /> on an instance with Authenticator application and SMS verification code MFA enabled; the steps are at the end.
Publishable key
Not provided. The problem isn't specific to our instance, and it shows up on any instance with the MFA settings above.
Description
In the MFA section of the prebuilt <UserProfile />, the "Set as default" action on an SMS second factor behaves inconsistently. Below, we separate what we observed at runtime from what we confirmed only by reading Clerk's source. We did not create a test instance or test user to execute the source-confirmed parts.
1. Runtime-confirmed: "Set as default" doesn't launch reverification, and shows the raw error instead
Observed: a signed-in user opens <UserProfile /> → Security and chooses ⋯ → Set as default on an SMS MFA phone number. The card shows the raw error:
You need to provide additional verification to perform this operation.
No reverification modal opens, the action isn't retried, and the user is stuck. We saw this in production with clerk-js 5.127.2 and an unmodified <UserProfile /> (only two appearance classes passed; no custom pages or localization).
Cause (source-confirmed): the action calls makeDefaultSecondFactor() directly, without useReverification:
MfaSection.tsx:175@ clerk-js 5.127.2:onClick: () => phone.makeDefaultSecondFactor().catch(err => handleError(err, [], card.setError))- The same line is on
main:packages/ui/.../MfaSection.tsx:175
As far as we can tell, the other sensitive mutations in UserProfile/ are wrapped in useReverification: creating phone, email, TOTP, backup codes and passkeys; changing the primary email/phone; changing the password; revoking a session; deleting the user; and the removals via RemoveResourceForm. So this looks like an omission.
2. Source-confirmed: with an authenticator app enrolled, the authenticator is always "Default", yet SMS rows keep offering "Set as default"
:35:showTOTP = secondFactors.includes('totp') && user.totpEnabled:72: the authenticator-app row always renders thebadge__default("Default") badge.:88:const isDefault = !showTOTP && phone.defaultSecondFactor;. While TOTP is enrolled, no SMS row can show "Default", whatever itsdefaultSecondFactorvalue.:172–175: "Set as default" is offered whenever!isDefault. So every SMS row keeps offering it, including after the action has succeeded.
3. Source-confirmed: prebuilt sign-in always starts on TOTP before phone code, so defaultSecondFactor doesn't make SMS the first second-factor screen
SignIn/utils.ts:99–115@ 5.127.2 (main:packages/ui/.../SignIn/utils.ts:100):determineStartingSignInSecondFactorreturns thetotpfactor whenever one exists, and only then falls back tophone_code. It doesn't consultdefaultSecondFactor.- The reverification modal uses the same function (
UserVerificationFactorTwo.tsx:49).
So for a user with an authenticator app and a verified SMS factor, from the source: even when "Set as default" succeeds (default_second_factor: true), the badge stays on the authenticator app and sign-in still opens on the authenticator-code step. As we read it, defaultSecondFactor only orders phone numbers against each other, and nothing in the UI says so. The PhoneNumber reference describes makeDefaultSecondFactor() as marking the number as the default second factor for MFA, which suggests a stronger effect.
4. Questions and requests
Is this intentional?
- If yes: please don't show "Set as default" on SMS rows as if it changes the user's preferred MFA method. For example, hide it while an authenticator app is enrolled, or explain what it does.
- If not:
- wrap
makeDefaultSecondFactor()inuseReverification, so the user gets the reverification flow and the action retries; - make the displayed "Default" state consistent with the user's actual default second factor;
- have the prebuilt
<SignIn />(and the reverification modal) honour the user's preferred/default second factor, or provide a supported configuration for SMS-vs-TOTP priority.
- wrap
Steps to reproduce (development instance, test user)
- Enable MFA with Authenticator application and SMS verification code; keep the default reverification window.
- Sign up a test user, enrol an authenticator app, then add and verify an SMS second factor.
- Open
<UserProfile />→ Security. The authenticator app shows Default, and the SMS row's ⋯ menu shows Set as default. - Item 1: once the session is outside the reverification window, choose ⋯ → Set as default on the SMS row.
- Expected: the reverification modal opens, and the action retries.
- Actual (as observed by us): the raw error above.
- Items 2–3: right after a fresh sign-in, choose ⋯ → Set as default on the SMS row, then sign out and back in.
- Expected: SMS shows Default, and sign-in starts with SMS; or the action isn't offered.
- Expected per the source (not executed by us): the request succeeds, but the badge stays on the authenticator app, the action is still offered, and sign-in starts on the authenticator-code step.
Environment
@clerk/clerk-js (loaded in the browser): 5.127.2 (the same code is on v5 latest and on main e34a5cc262 / packages/ui)
@clerk/nextjs: 6.39.4
@clerk/clerk-react: 5.61.7
@clerk/shared: 3.47.6
Components: prebuilt <UserProfile /> and <SignIn />, no customisation beyond appearance classes
- Dominant language
- TypeScript
- Stars
- 1.8k
- Forks
- 477
- Avg merge
- 2d 25m
- Merged PRs (30d)
- 267
Getting set up
- No Dockerfile or Docker Compose file
- Has a pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from clerk/javascript
-
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
clerk/javascript#10026 · 1 comment ·
Maintainers usually reply within 1 day
-
@clerk/nextjs: onBeforeSetActive never settles when invalidateCacheAction rejects (e.g. after a redeploy), so setActive and signOut hang foreverPossibly taken A pull request linked to this issue is open or already merged. Open
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
clerk/javascript#9987 · 1 comment ·
Maintainers usually reply within 1 day
-
Difficulty 3/5 1-2 days Newbie friendliness 65/100
clerk/javascript#10011 ·
Maintainers usually reply within 1 day
-
M2M Token only authentication in Clerk MiddlewarePossibly taken @wobsoriano claimed this 7 days ago. Openneeds-triage
clerk/javascript#9981 · 1 assignee ·
Maintainers usually reply within 1 day
-
Difficulty 3/5 1-2 days Newbie friendliness 72/100
clerk/javascript#9972 ·
Maintainers usually reply within 1 day
All issues in clerk/javascript
Similar issues
-
enhancement
Difficulty 2/5 1-3 hours Newbie friendliness 74/100
Maintainers usually reply within 1 day
-
[Bug] remember() with special characters in namespace hangs until timeout instead of returning 400Openbug
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
MystenLabs/MemWal#1133 · 1 comment ·
Maintainers usually reply within 1 day
-
bug user-priority/P2
Difficulty 1/5 Under an hour Newbie friendliness 92/100
Maintainers usually reply within 1 day
-
Difficulty 2/5 Under an hour Newbie friendliness 88/100
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 88/100
Effect-TS/effect#8881 · 1 comment ·
Maintainers usually reply within 1 day