69

I'm trying to get my head around how PKCE works in a mobile app and there's something I don't quite understand.

So from what I can gather the client app creates a random cryptographically secure string known as the code-verifier. This is then stored. From this, the app then generates a code challenge. The code challenge is then sent in an API request to a server along with how the challenge was generated e.g S256 or plain. The server stores this challenge along with an appropriate authorization_code for the request in question.

When the client then tries to exchange the code for an access token it also sends the original code-verifier in the request. The server then retrieves the stored challenge and the method originaly used to generate it for this particular code and generates the equivalent s256/plain hash and compares them. If they match, it returns an access token.

What I don't get is how this is supposed to replace a secret in a client app? Surely if you wanted to spoof this you would just take the client_id as normal and generate your own code-verifier and challenge and you're in the same position as if PKCE wasn't required in the first place. What is PKCE actually trying to solve here if the original idea was that it is basically a 'dynamic secret'? My assumption is it's only there if someone happens to be 'listening' into when the auth_code is returned, but if you're using SSL again is this needed? It’s billed as replacing the fact you shouldn’t store a secret in a public app but the fact the client is responsible for generating rather than a server feels like it’s not actually helping there.

2 Answers 2

23

This write-up Okta has on this subject explains this pretty well IMHO.

I believe it's because PKCE is intended for native applications (e.g. Android, iOS, UWP, Electron, etc.) where you leave the security context of your application and go to the browser to authenticate, and rely on the secure return to your application from the browser. You don't necessarily have TLS on the redirect back to your application (in the case of custom schemes, you are relying on the OS to bring the response back to your application) so in the event your authorization code goes somewhere malicious, the receiving app wouldn't be able to get an access token without the dynamic secret.

The merits of a dynamic secret on a public client are obvious here - and the assumption for PKCE is that it is not difficult to intercept the response from the browser to your application.

11
  • 4
    What's the point of hashing the code verifier? Commented Nov 28, 2018 at 19:31
  • 4
    If I had to guess I'd say because you need to pass the code to the authorization endpoint securely, and since you're directing the user to a new application context, you cannot be sure that the code is securely transferred from your application to the browser. So you hash it, and after receiving the authorization code, your application can securely send both codes plainly over TLS directly to the authorization endpoint and the server can compute the hash and compare it against what was initially sent. I hope that makes sense! Read more from the rfc
    – someone1
    Commented Nov 29, 2018 at 14:39
  • 7
    Couldn't a malicious interceptor simply redirect the client with a hashed version of their own dynamic secret? Then capture the authorisation code and make a token request of their own?
    – Raiden616
    Commented Apr 3, 2019 at 7:04
  • 3
    I think the only assumption here was that another app could intercept the authorization code, not that another app could read the outgoing requests and redirect the user on it's own dependent on that
    – Randy
    Commented Nov 7, 2019 at 13:11
  • 3
    Code verifier may help identifying the original requestor, BUT, why is the OAuth server issuing tokens without client secret? Client ID is considered as public knowledge, so any malicious application can use an authorized client's clientID to get access token using pkce?
    – Jimm
    Commented Dec 19, 2020 at 21:54
31

The reason PKCE is important is that on mobile OS, the OS allows apps to register to handle redirect URIs so a malicious app can register and receive redirects with the authorization code for legitimate apps. This is known as an Authorization Code Interception Attack.

Authorization Code Interception Attack

This is described by WSO2 here:

Since multiple applications can be registered as a handler for the specific redirect URI, the vulnerability of this flow, is that a malicious client could also register itself as a handler for the same URI scheme that a legitimate application handles. If this happens, it is a possibility that the operating system will parse the URI to the malicious client. The flow of this attack is illustrated in the following diagram.

In some operating systems such as Android, in step 5 of the flow, the user is prompted to select the application to handle the redirect URI before it is parsed using a "Complete Action Using" activity. This may avoid a malicious application from handling it, as the user can identify and select the legitimate application. However, some operating systems (such as iOS) do not have any such scheme.

To understand this better, here is a diagram and discussion from OpenID. You can see that the mobile System Browser has responsibility to receive the redirect URI and route it to the correct app.

Native app Redirect URI routing

However, because mobile OSes can allow many apps to register for the same redirect URI, a malicious app can register for and receive a legitimate authorization code as shown in this diagram, also by WSO2:

PKCE Malicious App

Attack Mitigation by PKCE

PKCE mitigates this by requiring shared knowledge between the app initiating the OAuth 2.0 request (request auth code) and the one exchanging the auth code for token. In the case of an Auth Code Interception Attack, the malicious app does not have the verifier to complete the token exchange.

5
  • 5
    This all makes sense for mobile apps. Is there any security benefit of Auth Code + PCKE over Implicit code flow when it comes to Single Page Applications running in the browser?
    – jmrah
    Commented Sep 21, 2020 at 1:55
  • 1
    This does not make any sense at all. You say 'mobile OSes can allow many apps to register for the same redirect URI'. Are there any requirements to this? From your explanation, nothing is required. The rogue app (installed on the user's phone) can be listening to the redirect uri for tokens regardless! Commented Mar 17, 2021 at 3:13
  • 2
    PKCE adds information so simply listening to the redirect uri doesn't provide enough information to compromise the user.
    – Grokify
    Commented Mar 18, 2021 at 20:54
  • 2
    @user1034912 With PKCE the access tokens are not transferred via a redirect uri, the legitimate app gets the access token by making an http request to the auth server and providing the auth code gained via the redirect uri and also the secure code verifier it generated at the start of the process.
    – tkburbidge
    Commented Jun 23, 2021 at 19:59
  • 1
    Where this all falls down is if the malicious app is the app that created the code verifier, and subsequently intercepts the redirect as well. From my research it seems "client authentication" is the key (pun intended). The client initiating the whole thing needs to prove it's the real client somehow. Commented Feb 19 at 16:44

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .