Problem
The error shown when a user is blocked by the rate limiter has three UX problems that make a bad experience worse for legitimate users who simply mistyped their code.
Current message (class-two-factor-core.php line 1858):
ERROR: Too many invalid verification codes, you can try again in %s. This limit protects your account against automated attacks.
1. "ERROR:" prefix
The ERROR: label is the same severity indicator used for authentication failures and system errors. A user who mistyped their code three times is not in an error state — they are temporarily delayed. A softer label or no label at all would be more appropriate.
2. "automated attacks"
This phrase tells a confused, locked-out user that their account is being attacked. For a legitimate user who simply mistyped their verification code several times, this is alarming and inaccurate. The rate limit exists to protect against brute force, but the message is rendered for the person submitting the form, who is almost always the legitimate account holder.
3. Stale countdown
human_time_diff( $last_login + $time_delay ) is evaluated once at POST time and baked into the rendered HTML. The countdown shown ("try again in 2 minutes") does not update as time passes. A user who waits on the page has no way to know the lockout has expired without manually reloading. The message also gives no instruction to reload.
Suggested direction
Something like:
Too many incorrect verification codes. Please wait %s and try again.
Avoids the ERROR: prefix, drops the attack framing, and (with a reload instruction added) gives the user an actionable path forward. The exact wording should consider i18n and the existing translation strings.
Related
- PR #917 — moves the rate-limit gate before provider pre-processing (the fix that surfaces this message to legitimate users more visibly)
Problem
The error shown when a user is blocked by the rate limiter has three UX problems that make a bad experience worse for legitimate users who simply mistyped their code.
Current message (
class-two-factor-core.phpline 1858):1. "ERROR:" prefix
The
ERROR:label is the same severity indicator used for authentication failures and system errors. A user who mistyped their code three times is not in an error state — they are temporarily delayed. A softer label or no label at all would be more appropriate.2. "automated attacks"
This phrase tells a confused, locked-out user that their account is being attacked. For a legitimate user who simply mistyped their verification code several times, this is alarming and inaccurate. The rate limit exists to protect against brute force, but the message is rendered for the person submitting the form, who is almost always the legitimate account holder.
3. Stale countdown
human_time_diff( $last_login + $time_delay )is evaluated once at POST time and baked into the rendered HTML. The countdown shown ("try again in 2 minutes") does not update as time passes. A user who waits on the page has no way to know the lockout has expired without manually reloading. The message also gives no instruction to reload.Suggested direction
Something like:
Avoids the
ERROR:prefix, drops the attack framing, and (with a reload instruction added) gives the user an actionable path forward. The exact wording should consider i18n and the existing translation strings.Related