How to HTTPS All Things in Node

This post by Geoff Gauchet originally appeared on the LookFar blog.

Since the mid-90s, HTTPS (secure HTTP connections) has safeguarded your bank account, your credit card number, tax information, and more. These applications of security are no-brainers, but today you’ll find that your favorite social media platform and even the news site you check every morning also throw up that little padlock icon. There are plenty of reasons to do this for any website or app you run, so buckle up because I’m about to tell you what they are.

First, the major reason to use HTTPS is protecting your users’ privacy. Aside from making their passwords safer when they login, any data that they post or read is encrypted, which keeps prying eyes from snooping. No one wants that friends-only rant about Game of Thrones or the government to be accessible by the weird guy in the corner of the coffee shop digging through the free WiFi.

Secondly, major browser and mobile device companies are pushing HTTPS hard. So hard, in fact, that many browsers will mark any non-HTTPS site as “not safe” which can make visitors to your site pause and go “Oh hellllll no!” and then Google an alternative to your site. iOS and Android’s documentation requires that you use HTTPS for your app’s API connections. Additionally, non-HTTPS websites get penalized in Google’s page ranking, which is the SEO version of inviting all of your friends to a party except for Jim, the guy who always smells like soup despite never having any soup near him.

So, now that I’ve skillfully convinced you that your site and app need to be locked down and you’ve bought an SSL certificate and you’re successfully serving up https://my-super-cool-app.internet, people typing in your domain name without the https:// are still getting the lame, insecure, soup-smelling version of your site. “How do I fix this?! How do I make my users feel safe and comfortable automatically?!” Ok, first, stop typing in my blog post. There’s a bunch of different ways depending on your server, your application, or your hosting provider. Today, I’ll show you a simple way to do this in node.js.

The simple plan is to tell your Node server to redirect any http:// URLs to https:// URLs, so we’ll accomplish this by writing some super simple middleware (basically a function that runs after your server is configured, but before it starts serving things up).

app.use(function(req, res, next) {
if (req.secure){
return next();
}
res.redirect(“https://” + req.headers.host + req.url);
});
view rawnode-https-redirect hosted with ❤ by GitHub

Node very handily gives us a secure flag on each incoming request that simply gives us a true or false whether the URL is over HTTPS or HTTP, respectively. If it’s true, we just tell Node “Oh rad, yeah, just do whatever it is you were gonna do” with the next() function. If it’s false, we tell it to redirect to the secure version. Super simple.

I did, however, run into a little gotcha with this. This has to be the first app.use() call in your server.js. Otherwise, some requests to your server (namely, the initial page load) will still come over insecure.

If you’re behind a load balancer, you’ll want to also place app.enable('trust proxy'); above your middleware so that all the proper headers come through and are readable by your code.

Putting it all together in this very simple server, we get:

// set up ======================================================================
var express = require(‘express’);
var app = express(); // create our app w/ express
var bodyParser = require(‘body-parser’);
var port = process.env.PORT || 8080; // set the port
// configuration ===============================================================
app.enable(‘trust proxy’); //needed if you’re behind a load balancer
app.use(function(req, res, next) {
if (req.secure){
return next();
}
res.redirect(“https://” + req.headers.host + req.url);
});
app.use(bodyParser.json()); // parse application/json
app.use(bodyParser.json({ type: ‘application/vnd.api+json’ })); app.use(bodyParser.urlencoded({ extended: true })); app.use(express.static(__dirname + ‘/dist’));
// routes ======================================================================
require(‘./routes.js’)(app);
// listen (start app with node server.js) ======================================
app.listen(port);
console.log(“App listening on port ” + port);
exports = module.exports = app; // expose app
view rawnode-https-solution hosted with ❤ by GitHub

And that’s that! “What if I’m running my app on Heroku?? I tried this and it didn’t work! What do I do????” Again, stop typing in my blog post, but hang on — I’ll cover that too.

Heroku essentially proxies your requests before they reach your app, so you need to do a couple extra steps to make it redirect properly, but they’re painless. First, make sure you have app.enable('trust proxy'); in your server. We need this because Heroku sets a “x-forwarded-proto” header on the requests to tell you which protocol (http or https) was used. Which is good and cool and definitely wasn’t a source of frustration for me for several hours!

We modify our code to this for Heroku:

app.use(function(req, res, next){
if(req.header(‘x-forwarded-proto’) !== ‘https’){
res.redirect(‘https://’ + req.header(‘host’) + req.url);
}else{
next();
}
})

Same principle as before, but instead of checking the secure flag, we check the header. Nothing too crazy!

You may also want this to only happen on your production server and not your local or development server. You can set an environment variable on production that says “Hey I’m the Production Server” and check that and if it’s true, run your middleware. Or, just shell out the cash for an SSL cert on your development server. Your call.

One Comment For "How to HTTPS All Things in Node"