An automated bot attack on a mobile app does not use your app. It calls your login API directly, thousands of times a minute, at 3am. Four controls make speed the losing move: rate limiting per user or IP, Entra ID smart lockout plus MFA, identical answers for wrong passwords and unknown users, and an alert on the rate of 401s.
Nobody is typing. A script is, and it does 8,000 attempts a minute.
Why automated bot attacks are a different problem
Automated attacks are not clever. They are fast and cheap, and they run at 3am because that is when nobody responds. A script downloads your app package, unpacks it, lists every endpoint it can find, and starts working through password lists pulled from other companies’ breaches, patiently, for as long as it takes, without ever getting tired or bored.
So everything about your answer has to assume nobody is awake.

How does rate limiting stop a bot attack?
This is the control that changes the maths. At 8,000 tries a minute, a password list harvested from someone else’s breach is exhausted in a few hours, but at 10 tries a minute the same list takes years to get through, and an attacker who pays for compute by the hour simply moves on to an easier target. Speed was the whole plan.
builder.Services.AddRateLimiter(o =>
o.AddFixedWindowLimiter("login", w => {
w.PermitLimit = 10;
w.Window = TimeSpan.FromMinutes(1);
}));
Partition by user or by IP, not globally, or one attacker rate-limits your real customers. ASP.NET Core rate limiting covers the partitioned limiters. In Azure API Management, use rate-limit-by-key with the subscription or caller IP. Front Door WAF also has a rate-limit rule, and blocking there costs nothing at all, the same edge layer covered in the five-layer request flow.
Smart lockout and MFA: make a right guess useless
Microsoft Entra ID has smart lockout on by default. It knows familiar from unfamiliar locations, so it does not lock out your real user while blocking the bot. Add MFA through Conditional Access and a correct password on its own stops being enough.
Credential stuffing works because people reuse passwords. MFA is what makes reuse survivable.
Defender for Cloud: let Azure be awake instead of you
Alert on the rate of 401s and 403s, not just on errors. A spike in 401s is somebody trying keys. It is the earliest signal you will ever get. Wire the alert to a phone, not an inbox. Inboxes sleep.
The CAPTCHA mistake
Adding a CAPTCHA and calling it done. It feels like a fix. A CAPTCHA protects a web form. The bot is not using your web form; it is calling the same API your app calls, straight from a server, which is why the five-step API article puts every control at the API.
One more thing worth doing
Return the same response, and the same timing, for “no such user” and “wrong password”. Different responses let the script enumerate which of your users exist. A list of real accounts is worth more than the guesses.
Key takeaways
- Automated attacks win on volume and persistence, not cleverness. Assume the attack runs unattended, all night.
- Rate limiting, partitioned by user or IP, changes the economics of the attack instead of just logging it.
- Entra ID smart lockout plus MFA neutralises a correct guess, which rate limiting alone does not.
- Alert on the rate of 401 and 403 responses; a spike is the earliest sign an attack is under way.
- A CAPTCHA protects a UI the bot never has to use. The control belongs at the API.
