Shakespeare’s plays are wonderful expressions of beauty and romance. His plays are also complicated, tragic, and hard to understand. Working with OAuth can feel a lot like Shakespeare. It sounds overly complicated, but the more time you spend with it, the more you see the underlying beauty and begin to truly understand it.

Let’s demystify some aspects of OAuth so you, too, can see the beauty and benefits to using it. If you’re already familiar with OAuth, skip ahead to take a look at the basic OAuth setup with Square.

Before we go into explaining OAuth , it’s worth talking about when you should be implementing it. A lot of API’s require utilizing OAuth, but sometimes you might not really need to use it. If you’re building an integration solely for your own use or your own application, you’re probably fine using your personal access token. If you’re wanting to build an application that needs access to multiple accounts or needs granular access, you’ll want to build out an OAuth integration. Even for your own infrastructure, if you have an ETL service, you might want to create an access token specifically for just that service that has read-only access.

Behind the Scenes of OAuth

To explain OAuth, we’ll walk through it like acts in a play. The first act is the authorization, the second act is the redirect, and the third act is acquisition. There’s also a prologue — getting things set up with your authorizer (in this case, Square) to register your application and get all your special credentials to use in the process.

In the first act, we’re sending the user off to the authorization server to ask for some permissions — like a kid who wants to go on a field trip. In order to attend, they’re sent to their parent with a list of what the field trip entails, and the parent has to sign off on it. For OAuth, you’re sending a user to the authorizer with your scope (permissions) that you would like to have. Then the user can see everything being requested and confirm that they would like to grant your application access for those permissions.

The second act is the redirect, which is where Square sends back a code to your application that can be used to acquire an access token. This should seem familiar if you’ve ever used SMS to log in to something. You need to provide both your password and the code that was sent via SMS in order to log in. The code sent back to your application from Square is your authorization code and is used by your application in the final act of getting the access token.

The third act is where we finally receive our access token from Square so we can process API requests for our user. Here, we need to provide the authorization code we received in the redirect to our callback url and our own application secret (which is acquired when registering with Square) in order to get our user’s access token. The access token can then be used to make API calls on behalf of our user.

The Benefits

We’ve gone through a few analogies and it’s clear that this process is a lot more complicated than simply asking a user for their password or making your user go get a special access token for you. The complexity ensures the process is secure — but it also gifts us more flexibility.

If we simply ask a user for their password, and they forget their Square password, then we’ll have to update our system with this new password and our integration would likely break in the interim (also, don’t ever ask for someone’s password). We also give the end users the ability to gracefully revoke access without having to change their password.

In addition, since we specified the scope up front, we only have to give access to whatever was specified. This means the end user can make an informed decision on what’s being granted. When providing a password, you can’t really control what’s being accessed. It’s all or nothing.

The Implementation

In order to solidify our understanding of OAuth, we’ll actually walk through an implementation of Square’s OAuth. There is a fully functional example over at https://glitch.com/~square-oauth-example. You can take a look at the source code and even remix it to have it work with your own account; just be sure to add in your own variables in the .env file. We’ll cover the core parts of the process, but we won’t be going into detail on things like storing user credentials or how best to handle session persistence.

The example is built using Express and SQLite. Express allows us to direct our users to the correct authorization URL and handle callbacks while SQLite allows us to store the token, and eventually renew or revoke the token. The last step there is important for a full implementation, since we don’t really want our users having to re-authorize our application every 30 days (the length an access token is valid for).

Before getting into writing code for our implementation we need to sign up for a Square Developer Account. We need to create an application and acquire our Application Secret and set our redirect URL. The redirect URL is where the user will be sent after they have signed-in and granted our application permission to access their account.

We’ll start off creating our route for handling sending the user to the authorization URL where we as for our permissions. Here’s what our route will look like:

Our authorize route start on line 14.

For those unfamiliar with Express, the req parameter is just our request object and the res parameter is our response object. We are also using Mozilla’s client-sessions middleware for creating encrypted cookies, which are accessible via req.auth. We start our method with checking if the user has already been authenticated, so we could skip needing to run through our whole authorization process. If the user hasn’t previously authorized with us, we initialize their state and store it in their cookie using req.auth so that we could later verify it to mitigate CSRF. After that, we’re simply constructing our authorization URL for redirecting the user. The CLIENT_ID is our application ID found at https://connect.squareup.com/apps for our specific application. Take a note of the scope and how we’re limiting this application to only read the MERCHANT_PROFILE to limit our access to read-only access on our user’s profile. If we needed more access, we could request more by adding additional values to the scope URL parameter.

Next, we want to show how to construct our redirect URL for handling the callback. Here is our example (I’ll forewarn, this part looks a little bit dense):

Our callback route starts on line 33.

We immediately start off by checking that the state in the query string matches what was stored in the user’s encrypted cookie, since we don’t want to process unauthorized requests. Then we’re simply POSTing our payload to https://connect.squareup.com/oauth2/token in order to get our access token for our user. Everything after that is simply querying Square’s API for some user information and creating our user in the database (we’re using Sequelize as an ORM to simplify things). I would like to point out as well that we’re only storing the user’s id in the cookie and no other personal information, because even though the cookie is encrypted, we don’t want to store sensitive information there. You need to treat access tokens like passwords, and you wouldn’t store passwords in unsafe places, so do the same for access tokens. In this example application, we’re going the extra step to encrypt the tokens before storing them and decrypting them when we need to use them.

Finally, we’ll cover renewal and revocation. Although these steps are optional, they’re extremely useful to implement to create a better user experience. Square allows access tokens to remain valid for 30 days, after which, you would need to renew them. You have a 15-day window to renew an access token.

We’ve covered each step in the process of creating an OAuth integration with Square to show how each method works, but there are a lot of libraries out there that simplify this process for you (PassportJS, Grant, and many others). If you’ve never implemented OAuth before, it’s useful to see a full integration like this in order to understand each step of the process better (which always helps with debugging down the road).