Broken User Authentication in APIs: My Full Testing Checklist

Broken User Authentication in APIs: My Full Testing Checklist

Authentication is the front door of any API, and Broken User Authentication is what happens when that door doesn’t lock properly — or locks, but has a spare key hidden under the mat. This is consistently one of the highest-impact vulnerability categories I test for, because a broken authentication flow doesn’t just expose one record like BOLA might; it can hand over entire accounts, or let an attacker skip the login process altogether. In this article, I’ll go through every part of the authentication flow I test, and why each one matters.

What Counts as Broken User Authentication?

Broken User Authentication covers any flaw that lets an attacker:

It’s a broad category by design, because authentication touches so many moving parts: login, registration, password reset, multi-factor authentication, session management, and token handling all fall under it.

Step 1: Testing the Login Endpoint Itself

I start at the most obvious place:

Credential Stuffing and Brute Force Resistance I test whether the login endpoint has any protection against repeated failed attempts — rate limiting, account lockout, or CAPTCHA after a threshold. I also check whether lockout, if present, applies per-account or per-IP, since per-IP-only lockout is trivially bypassed with IP rotation, and per-account-only lockout can be weaponized to lock a victim out of their own account (a denial-of-service variant).

Username Enumeration I compare responses for valid versus invalid usernames/emails, checking for differences in error messages, HTTP status codes, or response timing, since any of these can confirm whether an account exists.

Weak Password Policy Enforcement I test whether the API actually enforces password complexity server-side, or only validates it client-side (in which case I can bypass it entirely by calling the API directly with a weak password like 123456).

Case Sensitivity and Normalization Issues I test if email addresses are compared case-sensitively when they shouldn’t be, potentially allowing account confusion, or if Unicode normalization issues allow visually similar usernames to collide.

Step 2: Testing the Registration Flow

Step 3: Testing Password Reset Flows

Password reset is, in my experience, one of the most frequently broken parts of authentication. I test:

Token Predictability I check whether the reset token is a securely random, sufficiently long string, or something predictable like a sequential number, a timestamp, or a weakly hashed value I could brute-force or reconstruct.

Token Expiration I test whether reset tokens actually expire, and how long they remain valid. I also test whether requesting a new reset token invalidates previously issued ones, since some systems generate a new token but forget to revoke the old one.

Token Binding I test whether a reset token is tied specifically to the account it was issued for, or whether I can request a reset token for my own account and then use it to reset someone else’s password by simply changing the email/user ID parameter alongside it.

Reset Confirmation Logic I check what happens when I submit a password reset request with a valid token but a mismatched or manipulated user identifier in the request body, to see if the server actually cross-validates the token against the account or just trusts whatever account ID is submitted alongside it.

Response Consistency “If this email exists in our system, a reset link has been sent” should be the standard response, regardless of whether the email is actually registered — I flag it when a different message reveals account existence.

Step 4: Testing Multi-Factor Authentication (MFA)

MFA is supposed to be an extra layer, but I’ve found plenty of ways it gets implemented poorly:

MFA Bypass by Direct Endpoint Access I test whether I can skip the MFA verification step entirely by calling the “logged in” endpoints directly after only completing the first authentication factor, checking if the server actually enforces that MFA was completed before issuing a fully privileged session.

OTP Brute Forcing I test whether OTP codes (usually 4-6 digits) are protected by rate limiting. Without it, a 6-digit OTP has only a million possible combinations, which is trivially brute-forceable in a short time with no throttling.

OTP Reuse I test whether a used OTP code can be submitted again and still be accepted, and whether an OTP remains valid after the user has already successfully completed MFA once.

MFA Downgrade I test whether an attacker who has stolen a password can trigger an account recovery flow that skips MFA entirely, effectively downgrading a 2FA-protected account to single-factor.

Backup Code Weaknesses If backup codes are offered as an MFA fallback, I test how many are generated, whether they’re single-use, and whether generating new ones properly invalidates the old set.

Step 5: Testing Session and Token Management

Session Fixation I test whether a session token issued before login remains valid and privileged after a successful login, rather than the server issuing a brand-new session token post-authentication.

Session Invalidation on Logout I test whether a token or session is actually invalidated server-side on logout, or whether it remains usable (especially common with stateless JWTs that have no server-side revocation mechanism).

Session Invalidation on Password Change I test whether changing a password invalidates all other active sessions for that account. If it doesn’t, an attacker who already has a stolen session token retains access even after the legitimate user “secures” their account by changing the password.

Concurrent Session Handling I check whether the API allows unlimited concurrent sessions from different devices/locations without any anomaly detection, and whether there’s any way for a user to view and revoke active sessions.

Token Lifetime I test how long access tokens and refresh tokens remain valid, checking for excessively long-lived tokens that increase the window of opportunity if one is stolen.

Step 6: Testing Third-Party and Social Login (OAuth) Flows

Step 7: Testing “Remember Me” and Persistent Login Tokens

Tools I Use for Authentication Testing

Common Broken Authentication Issues I Keep Finding

  1. No rate limiting or account lockout on login endpoints.
  2. Password reset tokens that don’t expire or aren’t bound to the correct account.
  3. MFA that can be bypassed by directly calling post-login endpoints.
  4. Sessions that remain valid after logout or password change.
  5. Username enumeration through inconsistent error messages.
  6. Weak password policies enforced only on the client side.

How I Recommend Fixing Broken Authentication

Final Thoughts

Authentication is the one part of an API where a single flaw can undo every other security control layered on top of it. I’ve seen APIs with excellent authorization logic, careful input validation, and solid encryption completely undermined by a password reset flow that trusted the wrong parameter. Test authentication end-to-end, not just the login form — the reset flow, MFA, session handling, and token lifecycle all deserve the same scrutiny.

Exit mobile version