Skip to content

A rejected email code cannot be corrected: ClerkSignInPanel drops to the factor chooser, and retrying re-sends the code #448

Description

@dbeattie71

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

  1. Configure an instance with email_code as a first factor.
  2. Sign in with an existing user's identifier. A code arrives.
  3. Enter it incorrectly — one wrong digit is enough.
  4. 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.

Note on #443

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

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions