Yesterday I learned… HTTPS in development

While working on a project I wanted to copy a generated link programmatically to the clipboard.
I figured I have 2 ways to do that either with the wildly supported document.execCommand("copy")
:
const input = document.getElementById("myInput");
input.select();
input.setSelectionRange(0, 99999);
document.execCommand("copy");
or using the async navigator api:
navigator.clipboard.writeText(text)
Since I didn’t have an input field, just a piece of data in a react component, I went with the second option.
Little I know about the fact that the navigator object only has the clipboard accessible in a trusted environment. That means HTTPS.
HTTPS in localhost? #
To test the piece of code I looked for ways to use a secured connection in a dev environment.
With React and create react app, one can start the development server with https like this, but this is not quite enough.
"scripts": {
"start": "HTTPS=true react-scripts start",
...
},
This is half the story as I needed to start the backend service with https too. And somehow I had to convince Chrome that the self signed cert comes from a trusted CA.
The plan #
- Create a locally trusted Certificate Authority (CA) that can
- Create and sign a certificate for localhost, 127.0.0.1, ::1 domains
- So I can use this cert in my app to achieve the S in HTTPS.
MKCERT #
Found this as an alternative to OpenSSL, and I choose to install it as a global package with yarn, on macOS. There are other options with homebrew, and for Windows.
yarn global add mkcert
Create the CA and keep the generated key safe:
mkcert create-ca
And then generate a certificate for your localhost domains:
mkcert create-cert --ca-key <pathtocakey>/ca.key --ca-cert <pathtocacert>/ca.crt --domains localhost,127.0.0.1,::1
React + Https #
To use this with React (and CRA), create a .env file with the following:
HTTPS=true
SSL_CRT_FILE=<pathToCert>/cert.crt
SSL_KEY_FILE=<pathToKey>/cert.key
Node + Https #
const https = require('https');
const fs = require('fs');
const options = {
key: fs.readFileSync('<pathToKey>/cert.key'),
cert: fs.readFileSync('<pathToCert>/cert.crt')
};
const server = https.createServer(options, app);
Chrome #
At the time of writing: version 89.0.xx.
After setting up and starting your app in HTTPS mode, you might come across this:

Chrome doesn’t appear to accept our new shiny certificate and says it’s invalid. Click on the Certificate (invalid) to find out more:

Ahha, so it says the Test CA certificate authority is not trusted. To solve this we need to add the CA to our trusted entities. On a mac open Keychain Access find the CA and mark it as trusted:

If all went well now you should see the green lock in the browser:

Conclusion #
I’ve learned how to use https in local development with React and Node, and since we aim to make our dev environment closer to production, this is a good way to tighten the gap and reveal issues related to https earlier.