I recently picked up a Yubico U2F hardware key and thought I’d try to create a web application that was protected with two-factor hardware-based authentication. Things were going smooth until I realized that it is mandatory to be using HTTPS within your application, even when testing locally. HTTPS is common, but I’d never actually set it up with Node.js because I had always been using services like Cloudflare that configure it for you. The problem is that these services are for live domain names, not necessarily localhost.
While we’re not going to explore U2F hardware keys in this tutorial, we’re going to take a look at creating and installing a self-signed certificate for use in Node.js within macOS.
Before we tell Node.js that we want to use a self-signed certificate for testing on localhost, we need to actually generate that certificate. If you’re on a Mac and you’ve already got your development tools installed like Xcode, you should already have the necessary command line tools to be successful.
From the command line, execute the following:
openssl genrsa -out server.key 2048
openssl req -new -x509 -key server.key -out server.cert -days 365
The above commands will do two different things. The first command will generate a private key to be used when creating your certificate in the second command. In the second command, we generate a certificate that expires after a a year. The above commands are not specific towards generating a localhost certificate, but they are for a self-signed certificate. To make the certificate localhost compatible, it is important that you use localhost as the common name when prompted by the second command.
Don’t lose the .key file and the .cert file as both will be necessary when configuring the Node.js application.
With the .cert file in hand, the next step is to install it as a trusted authority on macOS. To do this, you’ll need to open your Keychain application.
In the certificates tab, drag your .cert file into the window. You may be prompted to enter your computer password and if not, you will be prompted later.
With the certificate added, we need to change the trust so that way it is actually used by our web browsers. Double click on the certificate entry to be brought to a new window with the certificate information.
Because this certificate is self-signed for localhost testing, it is easiest to choose the dropdown and select to always trust what the certificate has to offer. If you are more comfortable choosing only what you need, go for it. When you close the window after making the change, you may be prompted to enter your password.
With the certificate generated and in place on macOS, we can work towards using it in Node.js.
We’re going to build an incredibly simple RESTful API with Express Framework that uses our self-signed certificate. If you’d like more information on creating APIs, you might check out my previous tutorial titled, Create a Simple RESTful API with Node.js, or even my in-depth eBook and video course, Web Services for the JavaScript Developer.
On your computer, create a new project directory and execute the following commands:
npm init -y
npm install express --save
The above commands will create a new Node.js project and install the Express Framework package. What you’ll also need to do is create an app.js file or some other JavaScript file to hold our application logic. Within the app.js file, include the following:
const Express = require("express");
const HTTPS = require("https");
const FS = require("fs");
var app = Express();
app.get("/", (request, response, next) => {
response.send({ "message": "Hello World" });
});
HTTPS.createServer({
key: FS.readFileSync("server.key"),
cert: FS.readFileSync("server.cert")
}, app).listen(443, () => {
console.log("Listening at :443...");
});
If you’ve ever worked with an Express Framework API before, the above code should look very familiar. At the top you’ll notice that we’ve imported the https
and fs
dependencies, both of which are readily available out of the box in Node.js. We have a single endpoint, which will be served over HTTPS.
To make our application HTTPS, we need to use the https
package and read the .key and .cert files from the disk. You’ll want to provide the path to your files because the above code assumes that both files exist in the same directory as the app.js file. Finally it might be a good idea to use the typical HTTPS port which is 443.
When you run this application and navigate to https://localhost/ in your web browser, Chrome or similar might throw an alert about the destination being unsafe. This is because we’re using a self-signed certificate and Chrome or similar might not recognize it as a safe authority. Go ahead and choose to proceed anyways because we know what we’re trying to accomplish.
You just saw how to generate, install, and use a self-signed certificate in your Node.js application running on localhost on a macOS computer. The process of installing a self-signed certificate may vary between Mac, Linux, and Windows, but the generation and usage in Node.js should be more or less the same.
If you want to expand what this tutorial has to offer when it comes to building web services, check out my eBook and video course titled, Web Services for the JavaScript Developer.
A video version of this tutorial can be found below.