Improve rate-limit UX: calm error message and hide resend button during lockout#921
Open
dknauss wants to merge 3 commits into
Open
Improve rate-limit UX: calm error message and hide resend button during lockout#921dknauss wants to merge 3 commits into
dknauss wants to merge 3 commits into
Conversation
Bumps the npm_and_yarn group with 1 update in the / directory: [basic-ftp](https://github.com/patrickjuchli/basic-ftp). Updates `basic-ftp` from 5.2.2 to 5.3.0 - [Release notes](https://github.com/patrickjuchli/basic-ftp/releases) - [Changelog](https://github.com/patrickjuchli/basic-ftp/blob/master/CHANGELOG.md) - [Commits](patrickjuchli/basic-ftp@v5.2.2...v5.3.0) --- updated-dependencies: - dependency-name: basic-ftp dependency-version: 5.3.0 dependency-type: indirect dependency-group: npm_and_yarn ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…n during lockout Addresses WordPress#918 and WordPress#920. The rate-limit error message previously read "ERROR: Too many invalid verification codes... This limit protects your account against automated attacks." For a legitimate user who mistyped their code, this is alarming and inaccurate. Replaced with a calm, actionable message that tells the user to wait and reload. The email provider's authentication_page() now checks is_user_rate_limited() before rendering the Resend Code button or the "A verification code has been sent" prompt. Showing an interactive resend button during a lockout misled users into thinking it would work; clicking it only returned the rate-limit error again. The button is hidden until the lockout expires. The rate-limit check in authentication_page() also prevents token regeneration while locked out, which complements the existing test added in the rate-limit gate PR. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message. To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook. |
This was referenced Jul 3, 2026
Seeded demo: 4 failed verification attempts 1 second ago, shows the rate-limit error message in context. Landing page: /wp-login.php?action=two_factor_demo Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Companion to PR #917. Addresses #918 and #920.
What changed
Error message wording (
class-two-factor-core.php)Before:
After:
The old message used an
ERROR:severity prefix appropriate for system failures, not a temporary delay. "Automated attacks" frames a lockout caused by mistyped codes as a security incident, which is alarming and inaccurate for the legitimate user almost always reading it. The new message is calm, drops the attack framing, and tells the user what to do (wait and reload).Resend Code button (
providers/class-two-factor-email.php)authentication_page()now checksTwo_Factor_Core::is_user_rate_limited()before rendering the resend button and the "A verification code has been sent" prompt. While rate-limited, both are suppressed.Showing an interactive resend button during a lockout implied it would work. Clicking it only returned the same rate-limit error. The button reappears normally once the lockout expires.
The rate-limit check in
authentication_page()also prevents token regeneration while locked out — a user without a token will not receive a new email until the lockout expires and they reload.Tests
Three new tests, all passing against the full suite (192 tests):
test_rate_limit_error_message_is_calm_and_actionable— asserts noERROR:prefix and no "automated attacks"test_authentication_page_hides_resend_button_when_rate_limited— assertsINPUT_NAME_RESEND_CODEabsent from outputtest_authentication_page_does_not_send_email_when_rate_limited_and_no_token— asserts no email sent when called without a token during lockoutNot addressed here
Issue #919 (the "if this wasn't you, reset your password" warning that addresses two mutually exclusive audiences) is a separate concern affecting all providers and will be a separate PR.
Closes #918
Closes #920
🤖 Assisted by Claude Code
Try in Playground
What you'll see: The 2FA email code entry form showing the new rate-limit error message — no
ERROR:prefix, no "automated attacks" framing. The Resend Code button and "A verification code has been sent" notice are both absent (suppressed while locked out).What to test manually:
Technical: The demo installs the plugin directly from this PR branch (
dknauss/two-factor@ux/rate-limit-messaging) via a GitHub archive zip through the Playground CORS proxy — you're seeing the live patch code. A mu-plugin shim creates a demo user with Email 2FA enabled, records 4 failed attempts with an active rate limit, and renders the login form at/wp-login.php?action=two_factor_demowithout going through a real login flow.