PKCE Becomes Mandatory for OAuth Public Clients as RFC 9700 and OAuth 2.1 Close Authorization Code Interception Risks

PKCE, or Proof Key for Code Exchange, was introduced in RFC 7636 to prevent code interception attacks in OAuth 2.0 flows used by mobile and single-page applications. The mechanism generates a code_verifier and derives a code_challenge using S256 hashing to bind the authorization code to the original client session. Without PKCE, malicious apps on the same device can hijack custom URI schemes like myapp://callback and exchange stolen codes for access tokens. RFC 9700, published in January 2025, now mandates PKCE for public clients and recommends it for confidential ones while requiring S256 over the weaker plain method. The upcoming OAuth 2.1 draft further embeds PKCE into the core authorization code flow and removes implicit and resource owner password credentials grants. Major providers including Auth0, Okta, and Microsoft Entra ID show varying default support, highlighting the need for explicit S256 implementation. The standard also protects against code injection attacks even when client secrets are present.

SecuritylabTranslated from Russian

Read at source

The OAuth authorization code grant was designed to avoid exposing user passwords to applications by issuing short-lived codes instead of tokens directly. However, public clients such as native mobile apps and single-page applications cannot securely store a client_secret, leaving intercepted codes vulnerable to exchange for tokens.

PKCE (Proof Key for Code Exchange), defined in RFC 7636, solves this by requiring the client to generate a high-entropy code_verifier (43–128 characters) and send its SHA-256 hash as code_challenge during the initial authorization request. The authorization server stores the challenge and later verifies it against the verifier supplied at the token endpoint.

Why mobile apps cannot rely on client secrets

Server-side applications keep secrets in environment variables, but native Android or iOS apps can be decompiled and browser-based applications expose all source code. Even protected storage like iOS Keychain or Android Keystore can be bypassed on jailbroken or rooted devices, making any embedded secret effectively public.

The attack PKCE was created to stop

Multiple applications can register the same custom URI scheme such as myapp://callback. When the authorization server redirects the code, the operating system may deliver it to a malicious app that quietly declared the same scheme in its manifest. RFC 7636 notes that such code interception attacks have been observed in the wild.

How PKCE works in practice

The client creates a code_verifier using a cryptographically secure random generator, computes the code_challenge as BASE64URL(SHA256(verifier)), and includes it with code_challenge_method=S256. At token exchange the original verifier is sent over a secure channel; the server recomputes the hash and rejects any mismatch with an invalid_grant error.

The plain method offers only limited protection and is deprecated in favor of S256, which is mandatory to implement on servers. Omitting the method parameter defaults to plain, silently weakening security.

Three distinct threats often confused

  • Code interception: malicious app steals the real user code via URI scheme collision.
  • Code injection: attacker supplies its own code to bind a victim session to the attacker account; PKCE blocks this even for confidential clients.
  • Downgrade: server accepts requests without a challenge, disabling verification entirely.

PKCE does not replace other safeguards

The state parameter still protects against CSRF, and nonce in OpenID Connect ensures ID token freshness. RFC 9700 allows relying on PKCE for CSRF protection only after confirming server support. PKCE also does not protect issued access tokens; sender-constrained mechanisms such as DPoP (RFC 9449) or mutual TLS (RFC 8705) address that layer.

Current status in 2025–2026

RFC 9700 (BCP) already requires PKCE for public clients and recommends it for confidential clients. The OAuth 2.1 draft (draft-ietf-oauth-v2-1-15) integrates PKCE into the core flow and removes implicit and ROPC grants. Providers differ in defaults: Auth0 and Okta enforce S256, while Microsoft Entra ID still documents both methods.

Even AI agent authorization frameworks such as the Model Context Protocol are adopting OAuth 2.1 with PKCE for HTTP transports where static secrets are impractical.

Meridian digestThe week's most consequential security stories, distilled into one briefing.See the digest

More in Vulnerabilities & Exploits

Telegram for Android Patches Voice Call Vulnerability Enabling Code Execution
Yandex Patches Millions of Stations After eMudhra Certificate Keys Compromised
Cisco ASA and FTD Face DoS Vulnerability in SSL VPN Already Exploited in the Wild