Back to blog
OAuthauthentication

OAuth 2.0 PKCE: when protection is disabled without knowing it

Published on 2026-03-307 min readFlorian

PKCE: the protection everyone thinks they have

PKCE (Proof Key for Code Exchange) has become the security standard for OAuth 2.0 flows, especially for SPA and mobile applications. It protects against authorization code interception. The problem: many implementations disable it unknowingly.

How PKCE works

The client generates a random code_verifier and sends its hash (code_challenge) with the authorization request. When exchanging the code for a token, the client sends the original code_verifier. The server verifies the hash matches. An attacker who intercepts the authorization code cannot exchange it without the code_verifier.

The case we found: a healthcare portal

During an audit of a healthcare platform using OAuth for practitioner authentication, we discovered that the PKCE flow was technically implemented but neutralized. The code_verifier was exposed through an unauthenticated endpoint. Concretely, an attacker could retrieve the code_verifier of an ongoing session, intercept the authorization code (via a shared network or malicious extension), and complete the OAuth flow to obtain a valid access token.

The result: complete access to the practitioner's medical records and all their patients. The platform believed it was protected by PKCE — it wasn't.

The 4 most common PKCE implementation errors

1. Server-accessible code_verifier: the code_verifier is supposed to remain exclusively client-side. If your backend stores and exposes it via an API, the protection is nullified.

2. Missing code_challenge_method: without specifying S256 as the challenge method, some OAuth servers accept plain — the code_challenge IS the code_verifier, removing all protection.

3. OAuth server not enforcing PKCE: if the server accepts code exchanges without a code_verifier, PKCE is optional and an attacker can simply ignore it.

4. Predictable code_verifier: using a UUID or timestamp instead of cryptographic random of 43+ characters makes the code_verifier guessable.

How to verify your implementation

  • Intercept your own OAuth flow with browser developer tools
  • Verify code_challenge_method=S256 is present in the authorization request
  • Attempt a code exchange without code_verifier — it should fail
  • Verify no endpoint returns the code_verifier of a session
  • The impact for SMBs

    If your application uses OAuth (Login with Google, Azure AD, Auth0, Keycloak), verify PKCE is actually active. An OAuth flaw gives complete access to the user session — not just one endpoint. Our external review systematically tests OAuth authentication flows.

    Related articles

    Three adjacent analyses to keep exploring the same attack surface.

    Sources

    Written by Florian
    Reviewed on 2026-03-30

    Editorial analysis based on official vendor, project, and regulator documentation.

    Related services

    If this topic maps to a real risk in your stack, these are the most relevant CleanIssue audits.

    Need an external review of your HR SaaS?

    Share your product, stack, and client context. We will come back with the right review scope.

    Discuss your audit