7

If I was developing a web app client that would be served statically, I would need to either use the implicit grant flow (which is no longer advisable) or use the authorization code grant flow with PKCE. Given that I'm developing a web app client that will be served dynamically by a server, it's possible for me to utilize an authorization code grant flow in OAuth 2.0 without using PKCE -- the callback and subsequent token request will be handled server-side and the client secret can be stored securely on the server.

However, it would still be possible for me to utilize PKCE in this case (the server can generate the necessary code verifier instead of the client app). So my question is, is there any advantage to using one approach over the other (providing the client secret vs utilize PKCE). Is one more secure than the other in this context?

Daniel Rearden
  • 171
  • 1
  • 5

2 Answers2

5

It boils down to whether there is a chance your authorization code might leak.

PKCE is about preventing leaked "authorization code"s from being useful. When you ask for an authorization code, PKCE requires you to send the hash of a nonce. When you redeem the code, you must provide the original nonce.

This means that a malicious actor (XSS or CSRF vulnerability) observing the authorization code request and response cannot redeem the code, as they don't know the nonce.

Edit: Additionally, the client_secret means that only your server can redeem authorization codes. But, anyone can send messages to your server! If the authorization code has been leaked, then that means you don't know who is sending your server the authorization code -- is it the person who initially asked for it or some eavesdropping app? Without checking the nonce, your server may end up using its client_secret to redeem authorization codes for an eavesdropper.

jnnnnn
  • 151
  • 4
  • 1
    Thanks. That makes sense, but then if we're already using a client secret, even if the authorization code is compromised the attacker still won't be able to do anything with it. Having both mechanisms seems redundant. Just wondering if one is better than the other. – Daniel Rearden Oct 11 '19 at 07:10
  • see edit above :) – jnnnnn Oct 11 '19 at 07:23
  • Have a look at this video which explains the issues with PKCE: https://www.youtube.com/watch?v=_zWovo2zv6k&ab_channel=PingIdentityTV – David Brossard Dec 03 '20 at 23:11
  • 1
    I'm sorry, but are you sure that the `code_verifier` and `nonce` are actually identical? – Faither Feb 08 '21 at 14:30
  • @F8ER `code_verifier` and `nonce` are not the same. See this [article by Daniel Fett "PKCE vs. Nonce: Equivalent or Not?"](https://danielfett.de/2020/05/16/pkce-vs-nonce-equivalent-or-not/). In OpenID Connect, you could use both together. – katexochen Feb 16 '21 at 11:14
  • @MatthijsMelissen, the attacker never sees the *unhashed* nonce, and so cannot call redirect_uri successfully. Perhaps a diagram explains it better: https://jnnnnn.github.io/oauth-pkce.svg – jnnnnn May 21 '22 at 00:09
  • @jnnnnn You're right, and I don't like leaving incorrect information up so I've deleted my comment above. – Matthijs Melissen May 21 '22 at 00:38
  • @jnnnnn Actually I am still unsure about 'PKCE is about preventing leaked "authorization code"s from being useful.' What prevents an attacker from calling a redirect_uri using a stolen authorization code? – Matthijs Melissen May 21 '22 at 01:00
  • Thinking about it a bit longer, there are two distinct scenarios, which both are impossible. The attacker cannot call redirect_uri on the victim’s device (through csrf) because he would need to know the state. The attacker also cannot call redirect_uri on his own device, as the authorization server will only accept the stolen code together with the victim’s code verifier, which the attacker does not have. – Matthijs Melissen May 21 '22 at 14:09
1

Following the OAuth 2.0 Security Best Current Practice, you should use PKCE:

Clients MUST prevent injection (replay) of authorization codes into the authorization response by attackers. Public clients MUST use PKCE [RFC7636] to this end. For confidential clients, the use of PKCE [RFC7636] is RECOMMENDED.

If you have any reason not to use PKCE, the use of OpenID Connect "nonce" can be an alternative.

With additional precautions, described in Section 4.5.3.2, confidential clients MAY use the OpenID Connect "nonce" parameter and the respective Claim in the ID Token [OpenID] instead.

This applies to both public clients/native apps/SPAs as well as confidential clients.

Note: Although PKCE was designed as a mechanism to protect native apps, this advice applies to all kinds of OAuth clients, including web applications.

katexochen
  • 303
  • 1
  • 8