Fabio Berger

Building a coinbase app in Go

Coinbase is a terrific Bitcoin hosted Wallet that continues to simplify the purchase and safe storage of Bitcoin. They have an extensive API that allows 3rd party developers to build apps on top of their platform. I noticed they didn't have an API wrapper written in Go, so I decided to write one. In this post, I will show you how to write a simple app using both their API Key and OAuth methods of authentication.

The library is hosted on Github here together with a comprehensive list of examples, detailing the many API calls it supports.

API Key Application

Every Coinbase user can request an API key and secret associated with their account. With it, they can programmatically interact with their account (i.e automate purchases & sales of Bitcoin, retrieve previous transactions, orders and recepients, etc...). This first part of the tutorial will show you how to use the Coinbase-go library to print out your current Coinbase balance.

Adding Your Key Pair to Environment Variables

First, we need to create a key pair on Coinbase's API Settings page. Make sure to enable the key pair by copying over the verification code sent via email from Coinbase.

Once this is done, let's set the key and secret as environment variables in our shell's config file by running the following in terminal:

echo "export COINBASE_KEY='YOUR_KEY' " >> ~/.bash_profile
echo "export COINBASE_SECRET='YOUR_SECRET' " >> ~/.bash_profile

Note that we might need to replace .bash_profile with .bashrc or whatever shell config file is in use (more on this here).

Once this is done, we need to reload our shell configs:

source ~/.bash_profile #  or .bashrc, etc.

In order to check that this worked properly, try running the following:

echo $COINBASE_KEY

If this printed out your coinbase key we are good to go! The reason we set the key and secret as environment variables is because it is considered good security practice not to include API keys in our project source code. If someone got access to your API key and secret, they could gain control over your Coinbase account.

Downloading the Library

We assume here that you have already installed Golang on your machine. Make sure you also have your $GOPATH set. If not, run the following after editing the path to your actual Go workspace path:

echo "export GOPATH='path/to/your/go/folder'" >> ~/.bash_profile

We are now ready to download the Coinbase-go library with the following command:

go get github.com/fabioberger/coinbase-go

Writing the App

For this demo, we are going to write a simple command line application which will output our current Coinbase balance. Lets create a new project within our Go workspace called coinbase-app and create our main.go file:

mkdir $GOPATH/src/coinbase-app
cd $GOPATH/src/coinbase-app
touch main.go

Opening up main.go, we can write the following:

package main

import (
	"fmt"
	"log"
	"os"
	"github.com/fabioberger/coinbase-go"
)

func main() {

	c := coinbase.ApiKeyClient(os.Getenv("COINBASE_KEY"), os.Getenv("COINBASE_SECRET"))

	balance, err := c.GetBalance()
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("Balance is %f BTC", balance)

}

This simple program imports the Coinbase-go library, along with the 'fmt', 'log' and 'os' Go standard library packages. Within main, we instantiate an APIKeyClient using the API key pair we set as environment variables. Once we have done this, we can use this client 'c' to call convenience methods for sending requests to most of Coinbases API endpoints. For this example, we call the 'GetBalance()' method in order to request our current balance from Coinbase.

To test out this example, run the following:

go run main.go

For a full list of available methods, visit the Coinbase-go GoDoc Page and for examples on how to call them, look at the README examples section.

OAuth Authentication

It's great to be able to interact with our own Coinbase account via the API, especially for automating trades and keeping an eye on our account. What is even more powerful however is being able to build apps that any Coinbase account holder can use. To do this, we need to build an OAuth enabled application.

Setup

First we need to create an OAuth application at https://coinbase.com/oauth/applications. We will need to specify a redirect URI ('https://localhost:8443/tokens' during development). Coinbase will give us a Client Id and Secret for your OAuth App, let's add these to our shell configs as environment variables and reload them:

echo "export COINBASE_CLIENT_ID='YOUR_CLIENT_ID' " >> ~/.bash_profile
echo "export COINBASE_CLIENT_SECRET='YOUR_CLIENT_SECRET' " >> ~/.bash_profile
source ~/.bash_profile # .bashrc, etc.

Remember that we might need to replace .bash_profile with our shell config file name.

We will assume we have also downloaded the Coinbase-go library but if not, refer to the 'Downloading the Library' section under the 'API Key Application' instructions. In order to build this example web app using the Martini Framework, we will need to download it as well:

go get github.com/go-martini/martini

Martini is a powerful package for quickly writing modular web applications/services in Golang. We will use it to build a simple OAuth application that returns the balance of any Coinbase user who authenticates through our app.

Writing the App

Lets create a new project within our Go workspace called coinbase-oauth and create our main.go file:

mkdir $GOPATH/src/coinbase-oauth
cd $GOPATH/src/coinbase-oauth
touch main.go

Opening up main.go, we will write the following:

package main

import (
	"log"
	"net/http"
	"os"
	"strconv"
	"github.com/fabioberger/coinbase-go"
	"github.com/go-martini/martini"
)

var o *coinbase.OAuth

func main() {
	// Martini Setup
	m := martini.New()
	m.Use(martini.Logger())
	m.Use(martini.Recovery())
	m.Use(martini.Static("public"))
	r := martini.NewRouter()
	m.MapTo(r, (*martini.Routes)(nil))
	m.Action(r.Handle)

	// Instantiate OAuthService with the OAuth App Client Id & Secret from the Environment Variables
	o, err := coinbase.OAuthService(os.Getenv("COINBASE_CLIENT_ID"), os.Getenv("COINBASE_CLIENT_SECRET"), "https://localhost:8443/tokens")
	if err != nil {
		panic(err)
		return
	}

	// At http://localhosts:8443/ we will display an "authorize" link
	r.Get("/", func() string {
		authorizeUrl := o.CreateAuthorizeUrl([]string{
			"all",
		})
		link := "<a href='" + authorizeUrl + "'>authorize</a>"
		return link
	})

	// After authentication, AuthorizeUrl redirects to https://localhost:8443/tokens with
	// query parameter 'code'. If successful, the user's balance will show
	r.Get("/tokens", func(res http.ResponseWriter, req *http.Request) string {

		// Get the tokens given the 'code' query param
		tokens, err := o.NewTokensFromRequest(req) // Will use 'code' query param from req
		if err != nil {
			return err.Error()
		}

		// Instantiate the OAuthClient with tokens
		c := coinbase.OAuthClient(tokens)

		// Request the user's balance
		amount, err := c.GetBalance()
		if err != nil {
			return err.Error()
		}
		return strconv.FormatFloat(amount, 'f', 6, 64)
	})

	// HTTP
	go func() {
		if err := http.ListenAndServe(":8080", m); err != nil {
			log.Fatal(err)
		}
	}()

	// HTTPS
	// To generate a development cert and key, run the following from your *nix terminal:
	// go run $(go env GOROOT)/src/pkg/crypto/tls/generate_cert.go --host="localhost"
	if err := http.ListenAndServeTLS(":8443", "cert.pem", "key.pem", m); err != nil {
		log.Fatal(err)
	}
}

Before we can run the above code, Coinbase requires our redirect URI to communicate over SSL in order to protect their user's data. In order to run our server through HTTPS, we need to generate a development cert and key pair. Luckily, we can do this easily:

go run $(go env GOROOT)/src/pkg/crypto/tls/generate_cert.go --host="localhost"

This command will create a cert.pem and key.pem file in our directory. Since this is a self-signed certificate, our browser might complain that the certificate isn't trusted by a Certificate Authority. Since we are running this server however, we can safely ask our browser to ignore this warning and continue rendering the page. When deploying our app for the world to use, we will need to purchase an SSL certificate from a trusted Certificate Authority. We can now run this example with the following command:

go run main.go

To see the example, visit https://localhost:8443/ in your browser.

Ok, lets walk step by step through the code we just wrote. We start by importing Martini, Coinbase-go and a couple other Go standard library packages. Go then runs the main function which begins by instantiating OAuthService with the OAuth app client Id and Secret we defined as environment variables as well as a redirect URI back to our app. We can then use this OAuthService 'o' in the rest of our app.

Next, we define a Handle Function for requests sent to http://localhost:8443/. When someone requests this url, the app calls 'o.CreateAuthorizeUrl()' to generate the authentication URL we would like to redirect users to in order for them to authorize our app's access to their Coinbase account. We pass into this method the desired permissions to request from the user (full permissions list). This method then displays a link to the authorization page at Coinbase.

Once the user has clicked on this link, authorized our application on Coinbase, they will be sent back to the redirect URI we defined in OAuthService, in this case https://localhost:8443/tokens. This endpoint is the next Handle Function defined in the code. It calls the 'o.NewTokensFromRequest()' convenience method which will extract the 'code' query parameter returned by Coinbase and request the tokens associated with it.

Once we have these tokens, we can instantiate an OAuthClient with them. This client is similar to the ApiKeyClient above and has access to all the same convenience methods for sending requests to the Coinbase API. The only difference is that this time, each of those requests will be on behalf of the authenticated user. The next step in the code is for us to call 'GetBalance()' and return its response to the user.

The tokens we received from Coinbase have an expiry time we can access through 'tokens.ExpireTime'. When we are getting close to this time, we will need to call 'o.RefreshTokens(tokens)' in order to renew their validity.

Conclusion

I hope that this walk through on how to create a Coinbase app using the Golang API wrapper was helpful. Please be sure to take a look at the README examples section on the Github project for more examples on the kinds of requests that are available through the wrapper. If you have any questions or comments, don't hesitate to reach out!