twobotechnologies

Topic guide · 3 min read

OAuth downgrade attacks

Short answer

An OAuth downgrade attack makes a client or authorization server use a weaker option than intended, such as dropping PKCE, switching the code_challenge_method to plain, falling back to the implicit flow, or confusing which server issued a response; servers stop them by enforcing PKCE and allowed flows per client, and clients by never offering weaker fallbacks and checking the iss parameter.

Key takeaways

  • RFC 9700 requires authorization servers to reject a code_verifier when the authorization request had no code_challenge.
  • Register each client's allowed grant types and response types; reject anything else.
  • Clients that use several authorization servers should check the iss response parameter (RFC 9207) to stop mix-up attacks.

Security protocols tend to accumulate options for compatibility, and every option is a possible downgrade. OAuth 2.0 has several: grant types, response types, PKCE methods and the choice of server itself. An attacker who can influence which option is used can sometimes steer a flow to the weakest one.

Which downgrades matter in OAuth?

PKCE removal, PKCE method downgrade, flow downgrade to implicit, and mix-up between authorization servers.

Attack What the attacker changes Defense
PKCE downgrade Strips code_challenge from the request Server rejects code_verifier if no challenge was sent; or requires PKCE
Method downgrade code_challenge_method=plain Server allows only S256; client never sends plain
Flow downgrade response_type=token instead of code Server restricts response types per client
Mix-up Makes the client send a code to the wrong server Client checks iss in the response (RFC 9207); distinct redirect URIs per server
Client auth downgrade Weaker client authentication method Server registers one method per client

How does PKCE downgrade work?

If a server accepts both PKCE and non-PKCE requests for a client, an attacker can obtain a code without a challenge and then try to inject it into a victim's flow.

RFC 9700 section 4.8 describes the attack and the fix: if there was no code_challenge in the authorization request, the server must reject a token request that contains a code_verifier. Servers that simply require PKCE for every authorization code request get this protection automatically. The OAuth 2.1 draft requires PKCE throughout.

How do mix-up attacks work?

A client that talks to several authorization servers is tricked into sending a code or token from one server to another, controlled by the attacker.

The defense from RFC 9207 is small: the authorization server includes its iss identifier in the redirect, and the client checks it equals the server it started with. Clients can also use a distinct redirect URI per server. Single-server clients are less exposed but lose nothing by checking.

What should the authorization server enforce?

Per-client registration of everything that could be downgraded.

  1. Allowed grant types and response types.
  2. PKCE required, S256 only, for all clients if possible.
  3. One client authentication method per client.
  4. Exact redirect URIs.
  5. iss returned in authorization responses, and advertised in metadata.

What should the client do?

Offer only the strong option, fail closed, and validate the response.

  • Always send S256 PKCE; never fall back to plain or to no PKCE on error.
  • Never fall back to implicit.
  • Check state and iss before redeeming the code. See the state parameter in OAuth 2.0.

Paste your authorization request into the Authorization URL Builder; it flags implicit response types, missing PKCE and plain challenges. The OAuth security guide covers the wider threat list.

Questions

What is a PKCE downgrade attack?

An attacker removes the code_challenge from an authorization request, so the code is issued without PKCE, then redeems it in a way the server fails to tie back to the original client. RFC 9700 section 4.8 describes it and requires servers to mitigate it.

Is code_challenge_method=plain a downgrade?

It weakens PKCE because the verifier itself travels through the browser. RFC 7636 allows plain only when the client cannot do SHA-256. Servers may refuse plain, and many do.

Sources

More guides in this section