PKCE or “pixy” is a safeguard that was required after it was discovered that the authorization code grant was susceptible to an attack known as the authorization code interception attack. Which is basically an attack where an adversary has the potential to eavesdrop on an authorization code. It should be highlighted that this is also applicable to the hybrid grant flow since hybrid grant can be thought of as “partially” authorization code grant.
What does PKCE protect against?
Authorization code interception, this is when a malicious application intercepts the authorization code returned from the authorization endpoint, this code can be then used to obtain an access token from the token endpoint. For the most part, authorization code interception exploits an apparent weakness in most operating systems in how they handle redirections to applications that register a URI scheme. This is how authorization code grant works on native applications (iOS, Android, Windows Phone etc):
- The application is registered in the OS as a handler for any requests that match a URI scheme. You can imagine, (for the purposes of this blogpost) that the app “com.twitter.app://” is the URI scheme for Twitter’s native applications. This means that the legitimate Twitter application (that registered the scheme) will launch whenever a URL beginning with the scheme is invoked by the browser.
- When authentication is required, the application jumps out of its application context and into a browser context and loads the appropriate page of the identity provider. The user authenticates herself and approves any consent required for the identity provider to issue the code to the browser.
- The code gets issued to the browser.
- After successful authentication the identity provider redirects the user to the redirect url supplied by the application, the redirect url for the native application is typically a URL that contains the URI scheme (eg “com.twitter.app://authorization?code=foo&state=bar&nonce=baz”). The browser queries the OS to get a list of applications configured to handle the URI scheme. The OS then passes this URL to the registered application(s) so that they can parse the code out of the URL
- The malicious application gets the code and can then use it to gain an access token from the token endpoint of the identity provider.
- The malicious application receives the access token since it supplied a valid authorization code.
Since multiple applications can be registered as a handler for a specific URI scheme, you can see how a malicious application can get authorization code by just telling the OS that it can handle a particular URI scheme (eg “com.twitter.app://”).
So how does PKCE work?
PKCE works by letting the client set up materials to let the authorization server know how to associate the code with a particular set of materials. In some ways this is quite similar to Proof of Possession but this is narrowed down to the interaction between the client and the authorization server.
In PKCE the client sends an additional two parameters when requesting an authorization code, a code challenge and a code callenge method. The code challenge is a value derived from a cryptographically random string called the code verifier. The code verifier along with the code challenge method is used to bind the issued authorization code to the authorization request.
A. The client creates and records a secret named the “code_verifier” and derives a transformed version “t(code_verifier)” along with the transformation method “t_m” also known as the “code_challenge_method“.
B. Authorization Endpoint responds as per usual but associates the “t(code_verifier)” and the “t_m” with the issued code.
C. Client sends authorization code in the access token request and includes the “code_verifier” secret generated at (A).
D. Authorization server transforms “code_verifier” and compares it to “t(code_verifier)” aka “code_challenge” derived from (B). Access is denied if they are not equal.
An attacker who intercepts the authorization code at (B) is unable to redeem it for an access token, as they are not in possession of the “code_verifier” secret.
We saw how there is a problem with doing authorization on mobile operating systems. PKCE is a way to mitigate the authorization code interception attack by letting the legitimate client request a code by binding it to a value. The authorization server will not issue an access token with a given code if the value binding cannot be determined, thus eliminating the possibility for interceptors exchanging codes for access tokens.