Broken Authentication in SaaS APIs: JWT Vulnerabilities and Session Flaws

OWASP API Security Top 10 ranks Broken Authentication as the second most critical API risk class. In practice it covers everything from weak token signing to credential stuffing exposure. The specific issues that show up most often in B2B SaaS pentests are narrower — and more fixable — than the category name implies.

AuthenticationJWTAPI SecurityOWASPSaaS

What the category actually covers

Broken Object Level Authorization (BOLA) and Broken Authentication are often confused. BOLA is about whether the API checks that the authenticated user owns the specific object they're requesting. Broken Authentication is about whether the API correctly establishes who the user is in the first place — the identity layer itself.

That includes: token signing and validation, session lifecycle, credential transmission, account enumeration exposure, and rate limiting on authentication endpoints. The failure modes range from catastrophic (an attacker can forge any identity) to serious-but-subtle (an attacker can determine valid usernames at scale and mount targeted credential attacks).

In B2B SaaS pentests, the most common findings aren't the dramatic ones. The alg:none bypass and unsigned token acceptance are rare in production systems in 2026 — most JWT libraries handle this correctly by default. What comes up consistently are implementation-level errors that developers introduce when customizing standard patterns.

JWT implementation errors that appear in real engagements

JSON Web Tokens are the dominant authentication mechanism for SaaS APIs, and they introduce a specific set of failure modes that don't exist with server-side session approaches.

Algorithm confusion. JWT headers include an algfield specifying how the token was signed. If a server accepts both RS256 (asymmetric, signed with private key) and HS256 (symmetric, HMAC), an attacker can take a valid RS256 token, modify the header to specify HS256, re-sign the token using the server's public key (which is often publicly available), and submit it as valid. The server then validates the HS256 signature using the public key — which the attacker also knows — and accepts the forged token.

The fix is to enforce a single allowed algorithm server-side, hardcoded in the verification logic, and reject tokens whose algheader doesn't match. Never trust the algorithm specified in the token header.

Missing expiration validation. JWTs contain an expclaim specifying when they expire. Generating tokens with this claim is table stakes, but the more common failure is on the verification side: the library call validates the signature but doesn't enforce expiration by default, or the developer disabled expiration checks while debugging and never re-enabled them. Tokens that never expire mean a single stolen token gives permanent access.

Weak signing secrets. When HS256 is used, the security of the token depends entirely on the strength of the HMAC secret. Secrets like secret, changeme, jwt_secret, or the application name are regularly found in environment configuration and can be cracked offline against a captured token with tools like hashcat or jwt-cracker. An attacker who recovers the signing secret can forge tokens for any user ID, including admin accounts.

During pentests, testing this requires capturing a valid token, running it against a wordlist offline, and checking whether the recovered secret allows signature generation. It's a passive test — no brute-force traffic sent to the application.

Token claims treated as trusted without re-validation. A JWT carries claims — user ID, roles, tenant ID, subscription tier. Once the signature is verified, many applications read these claims directly and act on them without re-checking current state in the database. If a user is suspended, their token still works until expiration. If their role is downgraded, their old token retains the previous role. In B2B SaaS, this extends to subscription gating: a user who downgrades can retain premium-tier access for the full token lifetime.

There's a design tradeoff here — the stateless nature of JWTs is part of their value. The common resolution is short-lived tokens (15-30 minutes) combined with token revocation for high-stakes events (password change, subscription downgrade, account suspension).

Session management issues beyond JWTs

Some SaaS products use server-side sessions — either alongside JWTs for specific flows or as the primary mechanism. These introduce a different set of failure modes.

Session fixation. If a session identifier assigned before authentication remains the same after login, an attacker who can set a session cookie (through a separate vulnerability) can fixate a known session ID and then take it over once the victim authenticates. The fix is to regenerate the session ID on every privilege change — specifically, immediately after successful login.

Insufficient session invalidation on logout.Many implementations delete the session cookie client-side on logout but don't invalidate the session server-side. The original session token, if captured, remains usable. This is consistently tested during pentests by capturing the session identifier before logout, performing logout, and replaying the captured token to check if the API still responds.

Predictable session identifiers.Session tokens generated with weak randomness sources or sequential IDs allow enumeration. Modern frameworks handle this correctly by default, but custom implementations or legacy code paths sometimes don't. The test is straightforward: generate many sessions and analyze the entropy and structure of the identifiers.

Credential endpoint exposure

Authentication endpoints — login, password reset, account lookup — are high-value targets for information disclosure and rate limiting failures.

User enumeration through response differentiation.If a login endpoint returns "user not found" for a non-existent email and "incorrect password" for a valid email with the wrong password, an attacker can enumerate valid accounts at scale. The same enumeration is possible through response timing differences even when error messages are identical — checking a valid email typically takes longer because it requires a database lookup and password hash comparison.

Password reset flows introduce additional enumeration surface: endpoints that confirm "if this email exists, a reset link has been sent" but behave differently for valid versus invalid addresses.

No rate limiting on authentication endpoints. Without per-IP or per-account rate limiting on the login endpoint, credential stuffing attacks can run against a known user list at high velocity. The practical threshold: 10,000 credentials against a valid account list takes minutes with no throttling. Effective mitigations include per-IP rate limiting, exponential backoff after failed attempts, CAPTCHA after N failures, and velocity alerts in logging infrastructure.

OAuth and SSO implementation gaps

B2B SaaS products increasingly use OAuth 2.0 and SSO as primary authentication paths, and these introduce their own failure modes.

Missing state parameter validation. The OAuth stateparameter is a CSRF mitigation — the application generates a random value, includes it in the authorization request, and validates that the same value comes back in the callback. If this validation is absent or predictable, an attacker can craft an authorization URL that, when visited by a victim, links the victim's account to the attacker's OAuth identity. This is a login CSRF — the victim is logged in as the attacker, exposing everything they do in the application.

Redirect URI validation failures. OAuth callback URLs should be validated against an explicit allowlist of registered URIs. Partial matching — validating that the redirect URI starts with a trusted domain — can be bypassed by registering a subdomain or using path traversal. An open redirect vulnerability on the trusted domain can also redirect the code to an attacker-controlled endpoint.

Token leakage in implicit flow. The implicit OAuth flow delivers access tokens directly in the redirect URL fragment. This exposes tokens in browser history, referrer headers, and server logs. The authorization code flow with PKCE is the correct pattern for public clients and eliminates this exposure.

How to test your own implementation

For teams doing internal security review before an engagement, these are the highest-yield tests to run:

Capture a valid JWT and decode the header. Verify the alg value matches what your server is configured to accept. Attempt to generate a valid token with the alg field changed to none — your verification should reject it. If using RS256, verify that HS256 tokens signed with the public key are rejected.

Set your system clock forward past the token's exp value and retry API calls. They should fail with 401. If they succeed, expiration validation is not enforced.

Test your login endpoint for enumeration. Submit requests for non-existent emails and valid emails with wrong passwords. Compare response bodies, HTTP status codes, and response times. They should be indistinguishable.

Check rate limiting: submit 50 failed login attempts from the same IP and verify throttling engages. Check whether the limit resets after a short wait or requires manual review for lockout scenarios.

If you use OAuth, verify that your state parameter is generated with sufficient entropy, bound to the user's session, and validated on callback. Attempt to replay a previously used state value — it should be rejected.

Concerned about authentication flaws in your API?

We test JWT implementations, session management, and credential handling as part of every web and API pentest.

Provecore Security

Exploitation-led web and API penetration testing for B2B SaaS teams. Every finding is proven exploitable with a working proof of concept.