Missing the Point in Securing OAuth 2.0
Having a confidential client is less important than one would think. On the other hand, mitigating authorization code injection attacks should be prioritized as much as possible

Before reading: If you need to brush up on OAuth 2.0, and in particular the Authorization Code Grant flow, the material in An Illustrated Guide to OAuth and OpenID Connect is excellent.
Authorization Code Grant with PKCE Flow with a Public Client
If you read the official OAuth 2.0 documentation, you likely will walk away thinking that using the Authorization Code Grant with PKCE flow with a Public Client is a recommendation. You would not be wrong.
Note: PKCE is an acronym for Proof Key for Code Exchange. Also, historically, the Authorization Code Grant with PKCE flow has been relegated to mobile applications; more recently it has been extended to single-page applications (SPA).
The Authorization Code grant type is used by confidential and public clients to exchange an authorization code for an access token.
After the user returns to the client via the redirect URL, the application will get the authorization code from the URL and use it to request an access token.
It is recommended that all clients use the PKCE extension with this flow as well to provide better security.
— OAuth 2.0 — OAuth 2.0
PKCE (RFC 7636) is an extension to the Authorization Code flow to prevent several attacks and to be able to securely perform the OAuth exchange from public clients.
— OAuth 2.0 — PKCE for OAuth 2.0
Note: As a proof of concept, one can download a fully functional React web application (public client) that implements the authorization code grant with PKCE.
Confidential v.s. Public Client
So what is the difference between a confidential and public client?
OAuth defines two client types, based on their ability to
authenticate securely with the authorization server (i.e., the ability to
maintain the confidentiality of their client credentials):1.) Confidential
Clients capable of maintaining the confidentiality of their
credentials (e.g., client implemented on a secure server with
restricted access to the client credentials), or capable of secure
client authentication using other means.2.) Public
Clients incapable of maintaining the confidentiality of their
credentials (e.g., clients executing on the device used by the
resource owner, such as an installed native application or a web
browser-based application), and incapable of secure client
authentication via any other means.
— IETF— RFC 6749-The OAuth 2.0 Authorization Framework
At this point, you are likely thinking:
How can any solution involving a public client, given that there is such a thing as a confidential client, be a recommendation?
The key to answering this is to understand the potential attacks on OAuth 2.0 resources, and their mitigation strategies, as described in OAuth 2.0 Security Best Current Practice draft-ietf-oauth-security-topics-15.
Attacks and Mitigation Strategies
The first observation is that none of the attack mitigation strategies involve restricting oneself to using confidential clients.
Second, one will observe that a principal concern involves attacks on the redirect back from the authorization server in the authorization code grant flow. This concern is equally relevant whether one is using a confidential or public client. The recommended mitigation strategy in either case is PKCE.
Note: The other historically used OAuth 2.0 flow, Implicit Flow, is no longer recommended.
The two often cited relevant attacks are Cross-Site Request Forgery (CSRF) and Authorization Code Injection.
Note: The Authorization Code Injection attack is often referred to as the Replay attack.
Cross Site Request Forgery (CSRF)
An attacker might attempt to inject a request to the redirect URI of the legitimate client on the victim’s device, e.g., to cause the client to access resources under the attacker’s control. This is a variant of an attack known as Cross-Site Request Forgery (CSRF).
— IETF — OAuth 2.0 Security Best Current Practice draft-ietf-oauth-security-topics-15
The scenario can be visualized as follows:

- (Step 1) The resource owner is tricked into navigating to a malicious third party website
- (Steps 1–5) The malicious third party performs the first portion of a legitimate authorization code grant for a resource under their control; producing a malicious authorization code
- (Step 5) The malicious third party redirects the resource owner back to the client with the malicious authorization code
- (Step 6–8 not shown) Without any countermeasures, the resource owner will finish up the authorization code grant to obtain tokens for a resource under the control of the malicious third party.
Here we see that PKCE is a countermeasure:
The traditional countermeasures are CSRF tokens that are bound to the
user agent and passed in the “state” parameter to the authorization
server as described in [RFC6819]. The same protection is provided by
PKCE or the OpenID Connect “nonce” value.
— IETF — OAuth 2.0 Security Best Current Practice draft-ietf-oauth-security-topics-15
More specifically, with PKCE, the step to obtain the tokens from the authorization code requires passing a randomly generated one-time validator string is only known by the resource owner’s client (not the malicious third party). Because the malicious authorization code could not have been created using this validator, the authorization server will fail to return the tokens in this step.
Note: As with most things in security, the qualification is that while not impossible, it is it highly unlikely the malicious third party has access to the validator string.
Authorization Code Injection
In an authorization code injection attack, the attacker attempts to inject a stolen authorization code into the attacker’s own session with the client. The aim is to associate the attacker’s session at the client with the victim’s resources or identity.
— IETF — OAuth 2.0 Security Best Current Practice draft-ietf-oauth-security-topics-15
The scenario can be visualized as follows:

- (Step 1–5) The resource owner performs the first portion of a legitimate authorization code grant flow; producing an authorization code for his resource
- (Step 5) The malicious third party prevents the resource owner’s client from receiving the authorization code and injects it into his own client
- (Step 6–8) Without any countermeasures, the malicious third party finishes up the authorization code grant flow to obtain tokens for the resource owner’s resource; thus gaining access to the resource
Here, again, we see that PKCE is a countermeasure:
The PKCE parameter “code_challenge” along with the corresponding “code_verifier” as specified in [RFC7636] can be used as a countermeasure.
— IETF — OAuth 2.0 Security Best Current Practice draft-ietf-oauth-security-topics-15
In this case, because the malicious third party does not likely have access to the resource owner client’s validator string, he cannot exchange the stolen authorization code for tokens (thus does not gain access to the resource owner’s resource).
Conclusion
After examining the attacks and mitigation strategies for OAuth 2.0, it turns out that having a confidential client is not a requirement for securing OAuth 2.0 . On the other hand, preventing the effects of malicious manipulation of the Authorization Code is a requirement, with PKCE being the recommended countermeasure.