Last active
January 6, 2026 21:19
-
-
Save dknauss/08aa4226989fb3e92e086c4a7c2feb33 to your computer and use it in GitHub Desktop.
Return 401 error response for failed WordPress logins.
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
| add_action( 'wp_login_failed', function ():void { | |
| status_header( 401 ); // Generates PHP header("HTTP/1.1 401 Unauthorized"); | |
| wp_die( 'Your login attempt failed.' ); // Kill WP/PHP execution with WSOD + error message. | |
| }); | |
| // By default WordPress handles failed login attempts by reloading the login page and returning a HTTP 200 "OK" response | |
| // with a message that reads "Error: The username/email address or password is incorrect. Please try again." | |
| // | |
| // By returning a HTTP 401 "Unauthorized" response instead, rate limiting tools watching the HTTP access log, like fail2ban | |
| // and mod_security, will pick up on repeated bad login attempts from single IPs and ban them. | |
| // | |
| // Halting PHP execution immediately is a good way to shut the door on all mischief, with the explanation of your choice — | |
| // or none at all. Otherwise, add a filter for the login_errors hook to override the default failed login message. | |
| // | |
| // A more robust approach to defending against brute force login attempts would also handle login requests made over XML-RPC | |
| // and the REST API, which should be restricted or disabled if they're not being used. (Both tend to be available by default.) | |
| // | |
| // Example: https://github.com/amitrahav/WP-401-On-Failed-Login/blob/master/401-on-auth-fail-init.php | |
| // | |
| // "Why is this fence here?" Some Background: WordPress core comitters (and others) have disagreed that 401 (and 403) are the | |
| // correct "modern standard" HTTP response for failed logins and that "all web application frameworks" use 401 (or 403) for | |
| // this purpose. | |
| // | |
| // See WordPress core Trac ticket #25446 to understand why failed logins return HTTP 200 in WordPress, and why this has | |
| // intentionally *not* been changed to 401 (or 403), despite requests to do so. | |
| // https://core.trac.wordpress.org/ticket/25446 | |
| // | |
| // It may be preferable to configure your rate limiting tools to catch HTTP POST requests to wp-login that result in HTTP | |
| // STATUS CODE 200. (This only occurs when a login has failed and the login screen has been refreshed with login_errors | |
| // displayed. Successfully posted logins get a 301 redirect, so they will not be confused with failed logins. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment