How to use OAuth Refresh Tokens with Coinbase

Recently I launched StopCoin, a platform to automatically buy and sell bitcoins on Coinbase. We monitor the price every few seconds and execute buy and sell orders on your behalf.

The hardest part of building StopCoin was getting OAuth working correctly and managing the user’s tokens properly. I struggled for weeks due to both my own inexperience with OAuth, and a lack of good documentation from Coinbase (which has since gotten much better, thanks guys!).

OAuth, if you’re not familiar, is a mechanism by which users can log in with a service like Facebook, Twitter, Google, or in this case, Coinbase.

For this article, I’m not going to go into the particulars of setting your app, I mainly want to talk about tokens and persisting them throughout your user’s experience in your app.

Coinbase has some good documentation on API Authentication, Getting Started with an OAuth 2 App, Tutorials and Use Cases, and API client libraries.

Once a user has authorized your application with Coinbase, you will access their account via an access token and a refresh token.

If you’re unfamiliar with OAuth2 and take three things away from this article, I hope it’s:

  • The access token can only be used once. It expires in two hours for security measures specific to Coinbase. Other API’s refresh times will be different. Some access tokens don’t require refreshing at all.
  • Coinbase uses an optional security feature of OAuth2 called refresh tokens.
  • Coinbase’s refresh tokens never expire but are critical to getting a new pair of tokens when you need them. They can only be used once and then are invalid. Again, this is Coinbase-specific.
  • When you give the OAuth system a valid refresh token and a valid or expired access token, in return you’ll get a new access token and a new refresh token.
  • A user with an old or used access token and a valid refresh token can have those tokens sitting in your database indefinitely, until you need them again to create a client, refresh it, get new tokens, and do something on behalf of that user

It looks like this:

  1. User signs in
  2. You get tokens for them and save them to the User model in your app, ideally encrypted for further security
  3. They use your app for a few minutes and go on with their day
  4. Their access token expires a few hours later. Regardless, you have a perfectly good refresh token to use with their old access token to create a Coinbase client, refresh the client, get a new access token and a new refresh token and store those (again, encrypted) on the User
  5. There is no need to constantly be refreshing the user’s tokens. You can refresh the tokens when the user comes back and needs to do something with a fresh client
https://gist.github.com/zackshapiro/206826141d4d11b4c5af

What’s a client?

A client is an instance of a user’s account that Coinbase returns when you send it the correct information above. It needs an access token, a refresh token, and an expiration date along with your unique app ID and app secret. Clients allow you to access a user’s Coinbase information like their account balance and the ability to buy or sell bitcoins.

It’s not necessary to create a client for things like fetching the buy or sell price because that information is public and the endpoint is unauthenticated. A simple GET request to the buy_price API endpoint will give you the information you need.

(Aside: one of the main struggles I had was creating a client without an expiration date. Coinbase says you can do it but I had bad results. I encourage you to use an expiry date both for your users’ security and because it seems necessary to work properly.)

I have a client, now what?

Now that you have a client, you can do things for your user that would otherwise require them to be logged in on Coinbase’s website. Let’s get their balance:

https://gist.github.com/zackshapiro/e2deedf79269d2c8a0ab

Now the tricky part, keeping credentials current

I prefer to update the user’s credentials at the end of a large task like a buy or sell on StopCoin. That way, access token and refresh token are new and unused, ready to create a new client without the need to be refreshed

https://gist.github.com/zackshapiro/ddead39f839b73a08a29
https://gist.github.com/zackshapiro/09bff2e2903e4a09bc64

Sell_users_coins is a big piece of code in StopCoin. It’s very complex and handles a variety of cases. By introducing the ensure block at the end, we can tell our app that regardless of the outcome of sell_users_coins, always run the code to update the user’s credentials (tokens).

In the second gist above, `update_credentials`, we’re passing in the old client with the previous tokens and calling `.refresh!` on it, which will give us a brand new client with a new access token and a new refresh token.

Careful here, the access token is called token, not access_token. It’s the same thing.

Next, I updated my user with those new tokens so that next time, the system can create a fresh client without any problems or additional work.

You don’t need to run ensure in every method you write because your client should last for two hours by default. In StopCoin, buys and sells are big operations that run frequently and I want to make sure that the system can quickly create clients, do the work it needs to do, update credentials and sign off.

I hope this article helps clear up some sticking points related to OAuth and Coinbase for you so you can develop apps faster and get them out into the world!


Zack Shapiro is the creator of Built in Public, a project studio and year-long experiment in creativity and transparency. StopCoin is the first project to come out of Built in Public. Zack also founded Luna, a nighttime delivery company based in San Francisco, which was acquired in early 2014.