ClerkSignInPanel returns to the factor chooser when a code is rejected, and the only way forward re-sends the code — so a mistyped code can never be corrected.
_onError resets _strategy to clerk.Strategy.unknown on every error. showCodeInput is _strategy.requiresCode, so on a 422 form_code_incorrect the code field leaves the screen. signIn.needsFirstFactor is still true at that point, so the factor chooser is what the user lands on.
From there the only way forward is to pick the factor again, which re-prepares it: a fresh code is emailed and the one already in their inbox is invalidated. The user types the code they are looking at — which is now the previous one — and it is rejected in turn.
Every retry races the inbox. A single mistyped digit is unrecoverable from inside the app.
Steps to reproduce
- Configure an instance with
email_code as a first factor.
- Sign in with an existing user's identifier. A code arrives.
- Enter it incorrectly — one wrong digit is enough.
- Try to correct it.
Expected results
The code field stays on screen with the error shown against it, and retyping the correct code from the same email completes the sign-in. The code that was emailed is still valid; only the submitted digits were wrong.
Actual results
The code field disappears and the panel shows the factor chooser. Tapping Email code to … sends a new code, silently invalidating the one in the inbox. Entering the code from the email the user has open now fails, because it is the previous one. The cycle repeats indefinitely.
The only escape is to notice that a newer email has arrived and use that one instead — which is not discoverable, and is easy to get wrong when several codes are in the inbox seconds apart.
Root cause
packages/clerk_flutter/lib/src/widgets/authentication/clerk_sign_in_panel.dart, lines 46–51 on main:
void _onError(clerk.ClerkError _) {
setState(() {
_password = _code = '';
_strategy = clerk.Strategy.unknown;
});
}
and line 198:
final showCodeInput = _strategy.requiresCode;
Clearing _strategy is correct for errors that invalidate the chosen factor. It is wrong for form_code_incorrect, where the verification the code was checked against is still valid and retyping is all that is required.
This reaches the same form_code_incorrect as #443, but it is a different defect. #443 makes a correct code fail, by discarding the in-flight SignIn and re-preparing on every submission. This makes an incorrect code unrecoverable. Fixing #443 does not fix this — the loop described here is still reachable with #443's fix applied, which is how it was found.
#443's "Actual results" mentions the panel returning to the factor chooser; at the time that was read as a symptom of the casing defect. It is not — it is this.
Proposed fix
Hold the strategy for a rejected code only, so the panel keeps its position and the code can be retyped. Nothing else changes: the message still surfaces through ClerkErrorListener, and onResend is already on screen for anyone who does want a new code.
PR to follow.
Environment
clerk_flutter / clerk_auth 0.0.18-beta, and main at 1a172b9
- iOS, but the logic is platform-independent
ClerkSignInPanelreturns to the factor chooser when a code is rejected, and the only way forward re-sends the code — so a mistyped code can never be corrected._onErrorresets_strategytoclerk.Strategy.unknownon every error.showCodeInputis_strategy.requiresCode, so on a422 form_code_incorrectthe code field leaves the screen.signIn.needsFirstFactoris still true at that point, so the factor chooser is what the user lands on.From there the only way forward is to pick the factor again, which re-prepares it: a fresh code is emailed and the one already in their inbox is invalidated. The user types the code they are looking at — which is now the previous one — and it is rejected in turn.
Every retry races the inbox. A single mistyped digit is unrecoverable from inside the app.
Steps to reproduce
email_codeas a first factor.Expected results
The code field stays on screen with the error shown against it, and retyping the correct code from the same email completes the sign-in. The code that was emailed is still valid; only the submitted digits were wrong.
Actual results
The code field disappears and the panel shows the factor chooser. Tapping
Email code to …sends a new code, silently invalidating the one in the inbox. Entering the code from the email the user has open now fails, because it is the previous one. The cycle repeats indefinitely.The only escape is to notice that a newer email has arrived and use that one instead — which is not discoverable, and is easy to get wrong when several codes are in the inbox seconds apart.
Root cause
packages/clerk_flutter/lib/src/widgets/authentication/clerk_sign_in_panel.dart, lines 46–51 onmain:and line 198:
Clearing
_strategyis correct for errors that invalidate the chosen factor. It is wrong forform_code_incorrect, where the verification the code was checked against is still valid and retyping is all that is required.Note on #443
This reaches the same
form_code_incorrectas #443, but it is a different defect. #443 makes a correct code fail, by discarding the in-flightSignInand re-preparing on every submission. This makes an incorrect code unrecoverable. Fixing #443 does not fix this — the loop described here is still reachable with #443's fix applied, which is how it was found.#443's "Actual results" mentions the panel returning to the factor chooser; at the time that was read as a symptom of the casing defect. It is not — it is this.
Proposed fix
Hold the strategy for a rejected code only, so the panel keeps its position and the code can be retyped. Nothing else changes: the message still surfaces through
ClerkErrorListener, andonResendis already on screen for anyone who does want a new code.PR to follow.
Environment
clerk_flutter/clerk_auth0.0.18-beta, andmainat 1a172b9