PKCE — An Introduction — Part II
In the previous article, I gave an overview of what PKCE is. If you have landed here directly, please make sure to give a read of Part I.
So where are we? Some upgraded railway station in a suburb. Yeah, that is what PKCE is, an upgraded OAuth Flow for Single Page Apps. Before diving into the detail of what PKCE is and why PKCE should be used, we will discuss a bit detail about how the Auth World looked like before it has been upgraded.
There are plenty of articles out there to know about identity. If you are interested in learning from the basics, I would recommend watching this one https://auth0.com/docs/videos/learn-identity-series.
I will provide some terminologies so we don’t get lost in the Auth World. In the way of securing applications we can classify the applications as follows.
- Web Application.
- Single Page Application.
- Mobile Apps (iOS, Android Apps).
- Machine-to-Machine Applications.
In this article, I will focus on the first two.
What is OAuth 2.0?
OAuth 2.0 is an authorization framework that enables third-party application to get a temporary limited authorization to access a protected resource on behalf of the user.
hmm.. I think I get it. But it is still not clear.
Let me explain a bit. You login to your gmail account with your username and password. Take a peek at the url in the browser. The url looks something like this https://accounts.google.com. Once you have logged-in, you can view all of your emails. So you are looking at first-hand.
Let’s say you login to an Application called
Example App, and it shows your last 10 emails from your gmail account. In order for the application to show the emails, it has to retrieve them from your gmail account. But your gmail is protected by your Google Account (email address and password). How can the application access your emails? Do you have to share your password with them? Definitely Not.
Passwords are not meant to be shared. Why trust an app? What will they do with your password? We have no control over it. If you share it with them, since its your username and password, Google cannot distinguish between you or the application accessing it. It’s too insecure.
But we have seen Applications showing up the emails on their own website. How are they doing that? This is when OAuth comes into picture. OAuth has defined protocols on how third-party applications can gain access to the resource server, in our case Gmail. We don’t need to share our username or password.
Then how do these Applications gain access? You will be prompted to login to your google account (First Party holding your credentials). The url is still https://accounts.google.com. So no worries. You are still entering your credentials with google.
After successful login, a consent screen from Google appears, requesting your consent to authorize the third party application
Example Appto access the resource (Gmail) on your behalf. If you say yes, Google will issue a
token/code with limited scopes (E.g. to read only emails but not delete it). The scopes will be displayed on the consent screen like below.
For example, the above screen is requesting access to view your profile and email address. Google as Authorization Server (Because it authorizes the third party app, it is called authorization server) will only allow access to these defined scopes with the third party app
In the case above, no emails, contacts or google drive documents are shared with the third party. Just the profile and email address. You don’t need to worry about it.
Google has APIs (https://developers.google.com/apis-explorer) for all the services it is offering. All it needs is an access token to access the API. So, when you provide consent to allow third party apps to access your data, Google (Authorization Server) will share the token/code (If its a code, it will be exchanged later for a token. I will explain later why we needed this extra step) with requested privileges to the application.
From what we have seen so far, the Authorization Server (Google)provides access tokens to access the protected resources (Gmail). The access tokens are acting on our behalf. So if some other application gets hold of the access tokens, there is no way of telling whether the intended application or malicious application accessing it. So the authorization server has to ensure maximum security that the token gets to the hands of the intended application.
The Authorization Server (Google) requires all kinds of applications wanting to access its resources to register with them.(To know more about it, https://developers.google.com/identity/protocols/oauth2). Upon registration, each application will be given a client id and a client secret (equivalent of our email-id and password to access gmail). Authorization Server can verify the authenticity of the application using this client id and client secret. Like our gmail password, client secret is not meant to be shared. It is a confidential information that should only be stored in a secure system.
We will see how the access tokens are shared by the Authorization Server based on the type of application (or the kind of infrastructure it has).
Let us take a look at the infrastructure of the Web Application. It consists of the Server and the Browser. Server is a confidential system but browser is not.
The term “grant type” refers to the way an application gets an access token from the Authorization Server. Since the web application infrastructure has a secure channel, in this case the Server, OAuth recommends the grant type called
Authorization Code Grant.
Authorization Code Grant means, when you provide consent in the browser, the authorization server will not immediately provide the access token via the browser. Instead it will provide an authorization code. This code is then sent back to the Authorization Server again by the Backend Server along with the client id and client secret (Which we received while registering the application with the Authorization Server). The Authorization Server validates the veracity of the application requesting for access token (It does application authentication at this step) and only during this transaction, the application will get an access token.
The web application infrastructure can be compared with the railway station which had gantry. At the first step, the ticket is issued. Then at the next step, the ticket is scanned across the reader in the gantry for validity. Similarly there are two steps involved here. At the first step, the code is issued. In the second step, the validity of the code is verified by the Authorization Server and then the access token is provided.
This token is not available in the browser at all and hence less vulnerable to security threats.
Single Page Application
If you look at the infrastructure of the Single Page Application, there is no secure system. There is no server in the backend. Only browser is executing the code. Remember the suburban railway station with no gantry from our previous article . There is no infrastructure to securely store our client secret.
But OAuth still needed to support this kind of applications. So it recommended the
Implicit Flow. In this flow, when you provide consent in the browser, the
access token is readily made available in the browser itself. There is no additional step to verify the authenticity of the application requesting for the access token.
As we all know, browsers are more prone to security vulnerabilities. So OAuth recommended this
Implicit Flow and cautioned the application developers about taking precautions. Applications adapting to this grant have to make sure the token is not compromised.
In the suburban railway station with no gantry, the ticket is issued and we immediately accessed the train. Similarly, the access token is directly provided. No additional check is made.
PKCE for Single Page Application
Like how the suburban railway station is upgraded with the new infrastructure to provide additional security, there is a new recommendation by the OAuth specification to use the PKCE flow.
What has changed recently? Do Single Page Apps acquire a secure system to store the password?
Actually no. Single Page Apps are meant to execute inside the browser only. But the capabilities of the browser has changed. Like how, in
Authorization Code Grant, we sent a code via the secure channel, now from the browser we can securely post a request to the
Authorization Server. So this exchange is made possible by all the browsers recently. If you have noticed, there is still one thing missing. Yeah… that’s right.
When the Server requests for the access token via the secure channel, it sent a client secret along with it in
Authorization Code Grant flow. This client secret is stored inside the server. Remember, we mentioned that ‘client secret’ is the equivalent of the password. The server made it possible to store it securely. But the provision to store the password is still not available in the Single Page Apps.
So, OAuth recommends to generate a random secret for every request instead of using a single client secret. The flow to get access token would be,
- The browser will create a random secret and generate a hash of that secret.
- An API request is made with this hash value (known as Code Challenge) to the Authorization Server to request for code.
- This code received is then posted again to the Authorization Server securely (via HTTPS POST), along with the random secret (known as Code Verifier) created during the first step to exchange for access token.
- Now Authorization Server calculates the hash of the secret received and validates with the hash value received during the API request made in step 2.
Comparing with our analogy of upgraded security measures in our suburban railway station, in addition to tapping our ticket in the gantry we have to share the one-time password with security personnel. The security personnel has to manage a way of retrieving the One-Time Password for the specific passenger and compare it with the password shared by the passenger. Only if it checks out ok, the passenger is let inside to access the train.
In PKCE, the Authorization Server before delivering the access token, it compares the hash value of the random secret between two different transactions and provides the access token to ensure maximum security.
So what now? The
Implicit Flow was around for close to a decade now. There are plenty of applications available in production using implicit flow. Do they have to immediately move out of implicit flow since it is no longer recommended.
Actually no. There is no new vulnerability identified with the
Implicit Flow. If you have already taken the pro-active measures for any security compromises, you can continue with the implicit flow. It is still being supported. That being said, with all the improved and upgraded security measures, you are still letting the passenger through the small passage.
The best practices outlined by the OAuth specification, encourages to adapt to PKCE. Better to be safe than sorry. With the implicit flow being no longer recommended, it is advisable to add to the product life cycle if you are already been using the implicit flow.