Require it for both. Public clients need PKCE because they cannot rely on a client secret, but confidential clients still benefit because PKCE ties the authorization request to the token request. That reduces the impact of intercepted codes and narrows the assumptions a token endpoint must make about the caller.
Why PKCE Belongs in Every Authorization Code Flow
pkce is not just a public-client workaround. It strengthens the authorization code flow itself by adding a proof step that binds the token exchange to the original request. That matters whenever an authorization code could be intercepted, replayed, or confused across channels, because the code alone is no longer enough to complete the exchange.
For organisations standardising OAuth, the practical question is not whether the client can keep a secret, but whether the authorization request should carry its own one-time binding. Treating PKCE as universal reduces variation across client types and avoids making security depend on assumptions that are easy to get wrong in mixed estates.
For a broader implementation view, OAuth 2.0 and OpenID Connect Guide for Identity Teams covers how PKCE fits into the authorization code flow, while RFC 9700 formalises current best current practice for hardening OAuth deployments.
Why Confidential Clients Still Benefit
Confidential clients can authenticate at the token endpoint, but that does not eliminate the value of PKCE. Client authentication answers “who is calling the token endpoint”, while PKCE answers “is this token request tied to the same authorization request that started the flow”. Those are different checks, and organisations should not treat one as a substitute for the other.
That distinction becomes important when an attacker can obtain an authorization code through redirect interception, log exposure, browser compromise, or a weak integration path. PKCE narrows the assumptions the token endpoint must make and reduces the blast radius if a code escapes its intended channel, even when the client itself remains well authenticated.
When you design OAuth for APIs or mixed client estates, RFC 7523 on JWT-based client authentication and RFC 8707 on resource indicators are useful complements because they tighten different parts of the flow, but neither replaces code-to-request binding.
How to Set the Policy Without Creating Exceptions
The clean policy is to require PKCE for all authorization code clients and make any exception explicit, narrow, and time-bound. A partial policy, such as “public client only”, creates implementation drift, because teams then have to classify client types correctly, maintain exception logic, and remember which integrations are covered by which rule.
That drift is where failures usually appear. If PKCE is optional for some confidential clients, teams will eventually inherit legacy integrations, reverse proxies, hybrid app patterns, or brokered flows that are difficult to classify cleanly. A universal requirement removes that ambiguity and keeps the control tied to the protocol step that needs protection.
For protocol guidance and deployment hardening, the OAuth guidance in RFC 9700: Best Current Practice for OAuth 2.0 Security is the most direct external reference, and MCP Security Guide shows why binding and token-handling discipline matter in tool-using architectures that still depend on OAuth flows.
Standards & Framework Alignment
This section maps relevant standards and security frameworks to the operational risks and controls described in this guidance.
OWASP ASVS provides the primary governance reference for this topic.
| Framework | Control / Reference | Relevance |
|---|---|---|
| OWASP ASVS | V10 — OAuth and OIDC | ASVS covers OAuth/OIDC flow security, including proper authorization-code protections. |
| Recommendation — Verify OAuth/OIDC implementations enforce PKCE and reject insecure fallback paths. | ||
Practitioner Guidance
Decision rule: If a client uses the authorization code flow, require PKCE by default regardless of whether it is public or confidential. Treat client authentication as an additional control, not a replacement for request binding.
What to verify: Confirm that your authorization server rejects code exchanges that do not present the original PKCE verifier where PKCE was required, and that your SDKs do not silently downgrade to non-PKCE flows during fallback handling.
Common mistake: Teams often assume confidential clients are “safe enough” because they have a secret. In practice, secret-based authentication does not address intercepted authorization codes, so the control gap remains unless PKCE is also enforced.
Practitioner takeaway: The strongest operating model is consistency, require PKCE everywhere the authorization code flow is used, then layer client authentication on top of it where the client type supports it.
Related resources from NHI Mgmt Group
- Why do confidential OAuth clients still benefit from PKCE?
- Why do public clients need PKCE in modern authentication flows?
- How should organisations respond when a spear phishing breach exposes highly confidential documents before the leak becomes public?
- When should organisations require human approval for an AI agent action?