They should require PKCE whenever they use OAuth authorization code flow, including confidential clients. OAuth 2.1 treats PKCE as mandatory because code interception remains a realistic threat, and the verifier binding provides an extra control that the basic grant does not supply on its own.
Why PKCE belongs on every authorization code flow
PKCE is not a special case for mobile or public clients. It is the control that binds the authorization response to the party that started the flow, which matters whenever an authorization code could be intercepted, replayed, or exchanged by a different client. That is why modern guidance moves PKCE from “recommended” to default for the authorization code grant.
For practitioners, the important shift is that PKCE reduces reliance on client secrecy as the only protection. Even when a client can authenticate itself, the code verifier still adds proof that the token request is tied to the original authorization request, which closes a gap left by the basic authorization code flow.
That is also why current guidance treats PKCE as part of the normal hardening baseline for OAuth deployments, not as an optional enhancement for a narrow client type. The control is cheap to adopt, widely supported, and directly addresses the interception class of failures that continues to show up in real integrations, especially where redirects, browsers, and multiple app components are involved. See RFC 9700: Best Current Practice for OAuth 2.0 Security for the current security direction.
What PKCE changes that the grant alone does not
The authorization code grant gives the client a short-lived code, but the grant by itself does not prove that the token request came from the same client instance that initiated the login. PKCE adds that proof by requiring the original client to present a matching verifier when redeeming the code.
In practice, that means the threat model shifts from “whoever sees the code can use it” to “only the party that knows the verifier can redeem the code.” This is the reason PKCE is useful even when you already use client authentication, because the two controls cover different failure modes. Client authentication proves the application’s identity to the authorization server; PKCE binds the code exchange to the original authorization request.
OAuth 2.1 reflects that reality by making PKCE mandatory for authorization code flows. That is not only a mobile-app decision, it is a response to the fact that code interception is still a realistic attack path across browsers, redirects, embedded apps, native apps, and some confidential-client integrations. The core grant remains valuable, but PKCE is what makes it robust enough for current deployments. The base protocol is defined in RFC 6749: The OAuth 2.0 Authorization Framework.
When “confidential client” is not a reason to skip it
Teams sometimes assume that a confidential client already has enough protection because it can hold a client secret. That assumption is too narrow. A client secret helps authenticate the application, but it does not stop an intercepted authorization code from being redeemed elsewhere if the attacker can reach the token endpoint first or reuse a captured response through a compromised path.
PKCE is therefore worth requiring even for confidential clients wherever authorization code flow is used. The control is additive: it does not replace client authentication, it strengthens the exchange by binding the code to the original requester. That makes it useful in distributed architectures, brokered login paths, hybrid apps, and modern front-end plus back-end splits where the authorization response may pass through more than one component before token redemption.
For organisations standardising OAuth usage, the practical rule is simple: treat PKCE as mandatory for every authorization code deployment unless you have a very specific legacy exception that you are actively managing. In most modern estates, there is no good reason to rely on the grant alone when the verifier can be added with little operational cost.
Standards & Framework Alignment
This section maps relevant standards and security frameworks to the operational risks and controls described in this guidance.
NIST SP 800-53 Rev 5 provides the primary governance reference for this topic.
| Framework | Control / Reference | Relevance |
|---|---|---|
| NIST SP 800-53 Rev 5 | IA-5 — Authenticator Management | PKCE adds binding and exchange protections to the authentication step of the code flow. |
| Recommendation — Manage OAuth exchange secrets and verifiers so intercepted codes cannot be redeemed. | ||
Practitioner Guidance
What to prioritise: Require PKCE wherever the authorization code flow exists, then document any exceptions as technical debt with an expiry date. The main operational decision is not whether PKCE is “nice to have”, but whether you are willing to accept code interception as an avoidable residual risk.
What to verify: Confirm that your authorization server rejects code redemption without a valid verifier, that the code challenge method is enforced consistently, and that clients cannot silently fall back to a weaker exchange path. If you support mixed client types, verify the strongest baseline across all of them, not just the easiest one to configure.
Common mistake: Treating client authentication as a substitute for PKCE. They address different controls, and the safer implementation is to use both when the grant is authorization code. The question is not whether the client can identify itself, it is whether the code can still be used by the wrong party if it leaks.
Practitioner takeaway: If you use authorization code flow, PKCE should be the default control, not a special-case option, because it materially reduces the blast radius of code interception without weakening the rest of the OAuth model.
Related resources from NHI Mgmt Group
- When should organisations require signed commits for production code?
- Should organisations use refresh tokens in authorization code flows?
- What should organisations do before moving authorization out of application code?
- How do organisations decide between OAuth Authorization Code flow and Client Credentials?