Build Your Own Invoicing Service with Node, Coinbase, Bitcoin, and Okta

I got into Bitcoin back in 2011. Since then, I've been a fan of cryptocurrencies and have always had an interest in them. I've also built several Bitcoin projects over the years (an information website, an ecommerce site, and several others) to help promote the usage of the cryptocurrency (while having some fun).

The idea of being able to send and receive money almost instantly from anywhere in the world with no middleman is really appealing to a lot of people.

Today, I thought it'd be fun to build a small web invoicing portal (something similar to FreshBooks, but much less sophisticated) that allows you to easily invoice your clients over email and collect payment in Bitcoin.

Table of Contents

The client can then pay their invoices using their local currency or Bitcoin (if they have it). In the end: you'll be able to manage and bill your clients and receive payment in Bitcoin.

I do a bit of consulting work myself and will be using this in the future =)

PS: If you want to skip the article and go straight to the code, go for it! I'm using Node.js, Express.js, and Coinbase to power the application.

Get Started with Coinbase, Okta, and Node

Before I walk you through building the application, there are a few things you'll need to do.

You'll need to go create an account with Coinbase. Coinbase is the largest and most popular Bitcoin exchange in the US. It allows you to easily get started using Bitcoin without needing to install software, learn a lot, etc.

You'll also need to create an Okta developer account. Okta is an API service that allows you to create user accounts, and perform simple authentication and authorization for your web apps, mobile apps, and API services.

Once you've finished creating the key, you'll be able to see an API key and API secret value. Copy these down, you'll need them later.

Set Up Okta

Now that your Coinbase account is ready for usage, you need to set up your Okta account. This is what you'll be using to protect your portal so only you can access it.

Log into your Okta dashboard and copy down the Org URL value you see at the top right of the page. You will need this value later. It looks something like this:

You next need to create a new Okta Application. Using Okta, you can manage users for many applications you might have.

To do this, click the large Applications menu item and click Add Application. Then when you are prompted, select the "Web" application option. This tells Okta that you are building a web application (not an API service, for instance). Behind the scenes, Okta uses this information to set your app up with the proper types of OAuth 2.0 and OpenID Connect.

Now you'll see a page asking you to define your Application settings. Use the values below:

These settings basically tell Okta where your web app will be running (locally in this example) and what sort of security rules to apply.

Once you've finished creating the Application, you'll then be taken to your settings page for this newly created Application. You'll want to copy down two values, your Client ID and Client Secret. These will be needed later.

These credentials will be used to communicate securely with Okta in order to authenticate yourself into the web portal later.

Clone the Project

Now that we've done the boring stuff, let's take a look at some code.

You can either clone the project locally from my Github repository:

$ git clone https://github.com/rdegges/crypto-invoicer

Or you can fork the project to your own Github account and then clone that locally. This might make it easier to make changes and play around with the code as you follow along below.

Through the rest of this article, I'll assume that you're working inside of the cloned/forked project directory.

Set Up Your Credentials

Now let's take the credentials you gathered earlier and define them as environment variables that you'll use to store these sensitive values.

To do this, you'll want to create a file named .env which looks like the following:

OKTA_ISSUER_URI should be set to the value of the Org URL value you copied down earlier, and placed into the URL. The final URL should look something like https://dev-111464.oktapreview.com/oauth2/default.

OKTA_CLIENT_ID and OKTA_CLIENT_SECRET are the Application credentials you generated when you created your Okta Application previously

REDIRECT_URI is a hard-coded URL that will be used as part of the authentication flow. More on this later.

SECRET should be a long, random string you define. This is used to secure your HTTP sessions and keep your authentication data safe. I like to generate these by bashing my hands on the keyboard for a second or two.

This is a pretty standard HTML page that uses the Bootstrap CSS library with the Sketchy Bootswatch theme. This theme makes the entire site look like a mockup. Since this is an example application, I thought the theme was fitting.

The index.pug view is also quite simple:

extends base.pug
block body
h1.text-center.head Crypto Invoicer
.row.intro
.col
.col-8
.jumbotron
h2.text-center A Personal Invoicing Portal
p.
This is a personal invoicing portal. Use this portal to bill your clients
for work done using #[a(href="https://www.coinbase.com/") Coinbase]:
accept money in USD or Bitcoin.
p.
If you're performing work for clients and need a simple way to bill
them, give Crypto Invoicer a try!
p.
Please #[a.btn.btn-primary(href="/login") login] to continue.
.col

This template simply displays a basic home page that prompts the user to log into their account to continue:

The last view you need to inspect is the dashboard.pug view. This view renders the dashboard page that allows a user to create and view their invoices.

It creates a form that allows the user to send a client an invoice. This form takes a few input parameters: the client's email address, a description of what is being billed, and finally an amount (in USD) to bill the client.

It lists all past invoices in an HTML table that can be sorted with JavaScript. To do this, you'll use pug to loop through all past transaction objects, and display their data as appropriate.

When you render this page, you'll see the invoice creation form:

And… If you've generated any past invoices, you'll see them listed below:

You'll also notice that if you click one of the table headers, you're able to sort all of the invoices by any column you want.

If you take a look at the dashboard.pug template code above, you can see how this works:

The sorttable JavaScript library is used to provide automatic table sorting in the browser

Pug is being used to display transaction details

Other than these two things, the rest of the page is plain old HTML. Nothing fancy!

Build the Server

Now that you've seen how the frontend code works, let's take a look at the server-side codebase.

Open up the server.js file found in the root of the project folder and follow along below.

Import Dependencies

The first thing I do in the server.js is import all the Node.js dependencies needed to run the app:

All the const definitions are fairly straightforward: they pull in the environment variable values that were set previously, and store them as JavaScript variables so they can be easily referenced.

The client variable defines a new Coinbase API client (which is later used to talk to the Coinbase API).

The account variable represents a Coinbase Account object. In Coinbase you can have any number of "Accounts": Bitcoin wallets, USD wallets, etc. You can move money between these much like checking accounts at a normal bank. When implementing the invoicing later, you'll need to know which Coinbase Account you want to issue the request for, this determines how you receive the money.

The transactions variable will be our own in-memory cache of all recent invoice transactions available to us via the Coinbase API. This is what we'll use when rendering our dashboard page later on: we'll store a cache of the transactions to avoid making API calls to Coinbase on each page load.

Finally, you'll notice the app variable. This is a standard Express.js convention: create an app object and use that to start up the web server later on.

Configure App Settings and Middleware

Once the globals have been defined, the next thing you need to do is define the app settings and middleware.

There's a section of code commented that contains these two blocks of functionality:

There's only one actual app setting here: app.set("view engine", "pug");, and all it does is tell Express to use the pug templating engine when rendering views.

Below that are the middleware definitions.

The first middleware defined is express.static. This middleware is configured to serve static assets (css, images, javascript) from the static directory in the root of the project folder. This definition tells Express that any requests that start with /static should be routed to that folder, and automatically return whatever files exist there.

This might be a good time to inspect the static folder and see what's in it. There are only two files:

A style.css file which holds some custom styling, and

A sorttable.js script which is used in our frontend to make our HTML table sortable

Next you'll see the express-session middleware defined. What this middleware does is configure Express to store sensitive user information in cookies (which are the safest way to store authentication data). When you are logged into the website via Okta later on, your authentication information will be stored in these cookies that are managed by this library.

NOTE: The SECRET variable that's used when initializing the session library is incredibly important. This long, random string that you previously defined is what keeps your cookies safe from tampering. If this value is ever leaked publicly (on Github, etc.) it would be a security catastrophe. All cookie-based systems require a secret key to be used to cryptographically validate the cookie.

The last middleware you'll see is the oidc-middleware. This is a little more complex, as it handles a lot of magic behind the scenes, and makes all the authentication logic in the application work.

The way this middleware works is by fully enabling your app to use OpenID Connect (OIDC) for authentication. When you define the new ExpressOIDC and give it your Okta configuration information, it builds an OIDC object that remembers all your application rules: what URL your application runs one, where to redirect the user after they've logged in, what your secret application keys are, etc.

Once this new object is created, it contains an Express router object that is then enabled below with the app.use(oidc.router); call. This line registers some magical routes behind the scenes: the main one of which is /login.

When this line of code is executed any requests to /login will redirect you to your dedicated login page (hosted by Okta), and prompt you to log into the application. Once the user has been logged in, they will then be redirected BACK to your Node application, where they will be logged in and able to access the dashboard page.

Define Helpers

Let's skip towards the bottom of the server.js file now and take a look at the updateTransactions function:

The purpose of this helper function is to build an in-memory cache of Coinbase transactions.

Each time you request money from a client and send them an invoice, Coinbase creates a transactional record. There are many different types of transactions that Coinbase logs, so what this function does is iterate through all available transactions, pruning out just the ones relevant to invoicing, then stores them in the global transactions array variable for later usage.

The idea here is that each time the dashboard is displayed, instead of talking to the Coinbase API and performing this logic in real-time, the app will simply pull the latest list of transactions out of the cache instead.

In this function I'm using the async library to perform a do-while loop that:

Talks to the Coinbase API and requests a list of transactions

Tries to determine whether there are any more "pages" of transactions left to iterate through (because there may be many transactions, it might require many requests to the Coinbase API to retrieve them all)

Filters out only the transactions that are of the type "request", as these are the "request" money transactions that this app generates

Stores them in the global transactions array for later usage

Define Startup Jobs

The next thing you'll do is define the jobs that need to run each time this Node server starts up.

If you take a look at the startup jobs code block, you'll see what I mean:

The setInterval() call essentially tells this Node process to update the cache of transaction data once per hour (in milliseconds). This way, all transaction information will be at most one hour old.

Finally, the Express app itself will be launched once the authentication library has finished preparing itself.

NOTE: It's important not to run the web server (app.listen(PORT);) until the OIDC library emits the "ready" event. This could result in odd security edge cases where a user making requests to protected pages on your website runs into errors if they make a request before the OIDC library has finished configuring itself.

Create Routes

Now that we've gone through the rest of the server.js code, let's look at the final section we skipped from earlier (the routes):

The first route just displays the home page of the site. Since all we need here is to show a simple template, there's nothing special we need to do other than render the page.

The app.get("/dashboard") route is what displays the dashboard page when requested. What's important to note here is the additional middleware it uses: oidc.ensureAuthenticated(). This middleware forces the user to log in before being able to access this page.

If you try to visit the /dashboard page before logging in, for instance, you'll be redirected to the login page and forced to authenticate.

Once the user has authenticated, however, they'll be allowed into the dashboard page, which simply renders itself using the in-memory cache of transaction data.

The app.post("/dashboard") route is what handles the invoicing.

When a user fills out the invoice form and clicks "submit", this route is processed and receives the invoicing data. It then talks to Coinbase using the Coinbase API and generates a proper money request (and email). Finally, before refreshing the page and showing the new list of transactions, this code will force a refresh of the transaction data cache.

By forcing the cache refresh after each new invoice is created, this prevents an issue where after creating an invoice you would not see it appear in the list below.

When invoices are generated and Coinbase sends out an email, the client receives an email that looks something like this:

This is quite nice, because then a click can simply click the "Complete this payment." button, and be redirected to Coinbase where they can complete the transaction using either Bitcoin or their local currency (USD) to pay.

Piece It Together

As I've hopefully shown you, building Bitcoin invoicing software using Node.js can be fairly straightforward.

The Coinbase API provides a lot of rich functionality. Paired with Okta for authentication and several open source Node.js libraries, you can quickly throw together complicated applications in a small amount of time.

If you're interested in building cryptocurrency apps of your own, I highly recommend you create a Coinbase account and check out their fantastic API documentation. They have a good number of libraries and tools available to help you build your applications in a fun and fast way.

I'd also recommend creating an Okta developer account which you can use to store users for your web apps, mobile apps, and API services, as well as handle authentication, authorization, OAuth2, OpenID Connect, Single Sign-On, etc.

Finally, if you'd like to see more articles like this, tweet @oktadev and let me know! We've also got a ton of other interesting developer articles you can find on the Okta developer blog.