further the displayed message can be hidden from api calls but show to the user.
The UI has to get the information from the backend somehow in order to distinguish wrong from expired.
The back-end responding differently based on status reveals information.
You say unlikely. I say it depends on how valuable you are as a target.
Edit:
password lockout makes brute force a thing of the past
OK so I just hammer your login endpoint for each user I've found until all your users are logged out.
Then I continue doing this every day until you stop using password lockouts.
ban my IP
Great, I have 8 VPN subscriptions and thousands of potential IPs, let's go for broke here.
manually trying to guess is even worse.
When targeting a single user, sure, but at scale the tables turn. One of your users uses a weak password, or a re-used password.
you likely would have more success with just trying the list of most common passwords.
Yeah this was just an example, I'm not trying to give a tutorial.
You got the supposed user name list from the 404/403 which is not related to being clear about the error for the user I am talking about.
Sorry if this didnt land, but I had hoped my payload thing demonstrated the whole "if the different statuses are distinguishable from one another, you're leaking information" thing.
further the displayed message can be hidden from api calls but show to the user.
Cool but the UI has to know which message to display. No matter how you spin it. You can return 418 "I'm a teapot" responses for expired passwords, and 403 for wrong passwords, and 404 for no user found, but the principle is the same. You are leaking information about the users by responding differently.
it does not need to be plain text as we are talking about user usability.
Sure, it could be no text, and I could still scrape information, so long as the responses are different between statuses.