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
code_challenge_method=S256 is present in the authorization requestcode_verifier — it should failcode_verifier of a sessionThe 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.
Authentication: JWT, OAuth, sessions — the flaws we see most
The most frequent implementation mistakes in JWT, OAuth 2.0, and classic sessions, with concrete examples and fixes.
WordPress 6.8: what the move to bcrypt really changes for security
WordPress 6.8 replaced phpass with bcrypt for user passwords and introduced BLAKE2b for several application secrets. Here is what that really changes, and what it does not fix.
Enterprise SSO and HRIS: SAML and SCIM pitfalls that show up in production
SSO integration is where most HRIS products introduce authentication flaws. The points to review from the vendor side.
Sources
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.