Public clients need PKCE because they cannot safely store long-lived client secrets. PKCE adds a proof step that binds the authorization request to the token exchange, reducing the value of intercepted codes. It is especially important for mobile apps, desktop apps, and single-page applications, where secret exposure would otherwise undermine the trust boundary.
Why This Matters for Security Teams
Public clients are built for environments where secrecy is hard to guarantee. Mobile apps, browser-based single-page apps, and desktop software can be reverse engineered, inspected, or instrumented, so embedding a client secret creates a false sense of trust. PKCE changes the threat model by binding the authorization request to the token exchange, which limits the value of intercepted authorization codes and reduces code injection or replay risk.
This matters because modern auth failures often happen at the handoff between browser, app, and identity provider, not inside a neat perimeter. Security teams that assume a public client can be protected like a backend service often discover the weakness only after a code interception or redirect manipulation has already been exploited. That pattern is visible in real-world software compromise reporting such as the Gemini CLI Breach — Silent Code Execution, where trust in local execution paths became part of the attack surface.
For control design, the lesson aligns with hardening guidance in NIST SP 800-53 Rev 5 Security and Privacy Controls. In practice, many security teams encounter this weakness only after an intercepted code or misrouted redirect has already been used, rather than through intentional testing.
How It Works in Practice
PKCE, or Proof Key for Code Exchange, adds a challenge-response step to the authorization code flow. The client generates a high-entropy verifier, derives a challenge, and sends only the challenge with the authorization request. Later, when it redeems the code, it must present the original verifier. If an attacker steals the code but not the verifier, the token exchange fails. This is why PKCE is now the standard pattern for public clients, even when they also use modern identity protections such as exact redirect URI matching and short authorization code lifetimes.
In practical terms, PKCE is not a substitute for good client registration and redirect hygiene. It complements them. Teams should still treat public clients as unable to keep secrets, use per-app redirect URI allowlists, and avoid relying on long-lived shared credentials. Where browser flows are involved, PKCE should be paired with anti-CSRF state handling and, when appropriate, modern session protections. Guidance in ISO/IEC 27001:2022 Information Security Management supports this kind of layered control thinking rather than a single compensating mechanism.
NHIMG research on widespread secret exposure shows why this matters operationally: the Ultimate Guide to NHIs reports that 79% of organisations have experienced secrets leaks, with 77% causing tangible damage. PKCE is valuable because it removes the need to trust a secret that public clients cannot safely protect in the first place.
- Use PKCE for mobile, desktop, SPA, and other public clients by default.
- Generate a fresh verifier per authorization attempt and keep it short-lived.
- Validate redirect URIs exactly and reject broad wildcard patterns.
- Keep authorization codes brief and single-use to reduce replay value.
- Prefer server-side confidential clients when the application can safely keep secrets.
These controls tend to break down in legacy identity stacks that cannot validate PKCE consistently across embedded browsers, custom redirect handlers, or cross-device login flows because the protocol integration points are too fragmented.
Common Variations and Edge Cases
Tighter PKCE enforcement often increases integration overhead, so organisations have to balance stronger code-exchange binding against compatibility with older apps and identity platforms. That tradeoff is real, especially in mixed estates where some clients are confidential server apps and others are public clients that cannot protect secrets at all.
Current guidance suggests using the code challenge method recommended by the identity provider, typically the stronger SHA-256 variant, but there is no universal standard for every legacy scenario. For device flows, embedded webviews, and cross-device sign-in, implementation details matter more than the label “public client.” Teams should verify that the authorization server consistently rejects code redemption without a valid verifier, and that refresh token issuance is constrained by device posture and session policy where supported.
NHIMG research shows why complacency is costly: the Twitter Source Code Breach underscores how exposed code paths and weak internal controls can widen access far beyond the original design intent. In authentication design, the same principle applies. A public client should be assumed inspectable, copyable, and replayable unless the protocol explicitly prevents that outcome.
FRAMEWORK_REFS—
[
{
“framework_code”: “NIST-CSF”,
“control_ref”: “PR.AC-4”,
“relevance_note”: “PKCE strengthens access enforcement for public-client auth flows.”,
“framework_summary”: “Require PKCE and exact redirect validation wherever public clients exchange authorization codes.”
},
{
“framework_code”: “NIST-800-63”,
“control_ref”: “OIDC/OAuth federation guidance”,
“relevance_note”: “Public-client protections align with secure federation and token issuance practices.”,
“framework_summary”: “Treat public clients as unable to hold secrets and use proof-based code redemption.”
},
{
“framework_code”: “NIST-AIRMF”,
“control_ref”: null,
“relevance_note”: “Risk management applies to choosing stronger auth controls for exposed client environments.”,
“framework_summary”: “Assess client exposure and adopt PKCE where secret protection is infeasible.”
},
{
“framework_code”: “OWASP-NHI”,
“control_ref”: “NHI-02”,
“relevance_note”: “Secret exposure risk is central to public-client authentication design.”,
“framework_summary”: “Avoid embedding reusable secrets in clients that can be inspected or copied.”
},
{
“framework_code”: “ZT-NIST-207”,
“control_ref”: null,
“relevance_note”: “PKCE supports request-level trust decisions instead of perimeter assumptions.”,
“framework_summary”: “Validate each token exchange independently rather than trusting the client environment.”
}
]
Related resources from NHI Mgmt Group
- Why is it crucial to adopt new authentication methods in MCP usage?
- Why do biometric checks help reduce account takeover risk in modern authentication flows?
- Why do usernames, passwords, and one-time codes create weak assurance in modern authentication flows?
- Why does passwordless authentication matter for organisations with frequent user sign-ins?