Modern OAuth for Single Page Applications Using PKCE

Daniyal Khalid
The Startup
Published in
7 min readAug 30, 2020

The OAuth specification was first published in 2007. Today’s web development landscape, dominated by Single Page Applications (SPAs) built on frameworks such as React and Angular, would have been completely alien to the committee that created the first draft of OAuth. Recall that this was a time when MySpace was one of the largest websites around and mobile apps as we know them today did not exist.

It is no surprise then that OAuth has gone through several revisions. The first major revision was the launch of OAuth 2.0 in 2012, which catered for some of the glaring omissions previously mentioned. However, software development is a rapidly moving field and even the norms and technologies widely used in 2012 for development have largely been replaced today.

This story will focus on how OAuth has been updated to reflect the needs of today’s web applications powered by SPA frameworks and how we can use these new functionalities to write secure code that interacts with third party APIs.

OAuth Flows 101:

OAuth has several “flows” through which developers can allow users to let them access their data from another application. Almost every flow involves the user passing their credentials directly to the external API and an access token being received by your app which then represents the authenticated user. Let’s quickly study the four main OAuth flows before continuing our discussion.

  1. Implicit Flow: This is probably the most famous and widely used OAuth flow. In this flow, the user is presented a dialog box to enter their credentials for the external API (say Facebook or Google). After entering their credentials, they are redirected to a route with the access token conveniently placed in the URL as a query parameter. This method is commonly used with web apps without a backend server. No client secret is involved.
Typical Implicit Flow Process

2. Authorization Code: This is the alternative to implicit flow and is commonly used when there is a backend server connected to the web app. In this flow, the user enters their credentials as usual, but instead of directly returning the token as in implicit flow, the OAuth provider instead returns a code. This code, along with the client secret, is sent in another POST request to the auth provider to get the key. This method cannot be used with just a web front-end app because it requires a client secret which you should never expose to your web client.

Typical Authorization Code Flow

3. Client Credentials: This is a less commonly used flow. No user is involved in this flow. Instead, the your backend server directly authenticates with the OAuth server to get a token. The major limitation of this method is that you cannot get the access token of a specific user and are only limited to accessing publicly available information within the external API.

4. Authorization Code with Proof Key for Code Exchange PKCE: Authorization Code with PKCE (pronounced ‘pixy’) can be thought of as a combination of Implicit Flow and Authorization Code flow. It allows the authorization code flow to be used directly on the web client, as it eliminates the need for a client secret by using a hash challenge to verify the client as follows:

Here, the code verifier is a random string. It is different each time the front-end app gets loaded. The server verifies that the request in part 3 of the above diagram is coming from the same origin as the request in part 1 by calculating the hash of the code verifier itself in part 3 which should then be the same as the hash received in part 1.

Implicit Flow vs Authorization Code with PKCE

TLDR: Implicit Flow is an archaic standard with security vulnerabilities. Use Authorization Code with PKCE wherever possible instead of Implicit Flow.

Implicit flow and Authorization code flow with PKCE are both viable approaches for authenticating directly on an SPA client, as they both ultimately ensure that your client app ends up with the OAuth access token. However, Implicit Flow returns the access token as part of the URL, which is a major security vulnerability as anyone who can see the URL of the redirect can impersonate the user. Authorization code flow solves this problem by returning the token securely in the response body of a POST request. Therefore you should always aim to use the Authorization Code flow with PKCE instead of the Implicit Flow.

Authorization Code vs Authorization Code with PKCE

This is a common dilemma that people face when they have an SPA client such as React connected to their own back-end. In this case you can either use the Authorization Code flow to retrieve the token on your backend server or use the Authorization Code with PKCE flow to retrieve your token at the front-end. Which one should you use? Unless you have a good reason to absolutely require the token to be retrieved on the server side, I would recommend you still go with the Authorization Code with PKCE.

This is because using the Authorization Code flow leaves the user hanging on the front-end, as the redirect is to the server. Suppose we have a client-side rendered React app with a Node/Express backend and we are implementing a login with a third party provider. Refer to the authorization code flow (without PKCE) diagram above. When the OAuth provider returns the access code in step 4 to the back-end, at that point your user on the web app will still be on the login screen and the server will have no way to communicate to the server that the authentication was successful. The web app will have to be refreshed at this point to be updated.

In contrast, the PKCE flow resolves on the web app, which allows us to send the token to the backend server and immediately update the display on the web app once we get the response. This results in a much smoother user experience.

Example: Implementing OAuth with PKCE using Spotify’s API

Let’s do a quick example to see the Auth Code with PKCE flow in action. We’ll use a barebones React app. We will implement a single functionality in our app that allows the user to login to Spotify to get an access token. We’ll pretend to send this access token to our backend and which will use it to register the user in our database by extracting the email from the token.

Spotify’s API implements the PKCE authorization flow and has easy to follow documentation which you can follow.

First, here is our main App.jsx file. Our app only has two components: one to initiate the login flow and the other to handle the redirect from step 2 in the PKCE flow diagram above.

Next up is the Login component. Upon clicking the login button, a random string of random length is generated. The base-64 encoded hash of this is calculated and included in the URL redirect where the user enters their details to be sent to the Spotify server. Another random string, called the state, is generated and sent in the request. This can be checked later to verify that the response from Spotify is legitimate. The code verifier and state are stored in local storage, since we will need them in the next step when we handle the redirect from the Spotify API.

Finally, we have a component to handle the redirect from the Spotify API. The redirect includes a code which we can use to generate an access token through a POST request. However, we cannot just use the code to exchange for the token. We will also need to include the unhashed code verifier we generated and stored in the last step. Here, we also verify the state we sent in the previous part.

Once we have the token, we can send it to our backend server which can use the token to extract the user’s email and other details and store them in the database.

Wrapping up

OAuth has evolved significantly over the years. The Authorization Code with PKCE flow is one of the latest additions that is designed to be used with Single Page Applications built on frameworks such React, Angular or Vue. The PKCE flow overcomes the issues and vulnerabilities of the old Implicit Flow and is the recommended method to receive OAuth tokens in modern web apps. Spotify provides a well-documented authorization API which you can use to learn how to implement the PKCE flow.

--

--

Daniyal Khalid
The Startup

Software Engineer with interests in web development, AI and learning new stuff.