HTTP Authentication in Node.js

Last week, in Creating a HTTP Server in Node.js, I covered the basics of HTTP in Node.js. Today’s article will show you how to password protect your Node.js site using HTTP authentication. We’ll start by looking at basic access authentication, and then move on to the more secure digest access authentication.

Basic Access Authentication

When a user visits a site that implements authentication, he/she is prompted for a username and password. If the user provides valid credentials they are taken to the page’s content, otherwise they are rejected with a “401 Unauthorized” response. The simplest type of HTTP authentication is basic access authentication.

The Password File

On the server side, all of the usernames and encrypted passwords are stored in a password file. The Node.js utility, htpasswd can be used to manage the password file. To install htpasswd, use the command shown below. npm stands for Node.js Package Manager, and it is installed by default with Node.js. npm is used to install Node.js modules. The -g flag installs the package globally, meaning that it is included in the system’s PATH variable.

npm install -g htpasswd

Once htpasswd is installed, you can create new users using the command shown below. This example creates a new password file named “htpasswd” using the -c flag. In the new file, a user named “foo” is added. The -b flag allows the password, “bar”, to be specified as part of the command line.

htpasswd -bc htpasswd foo bar

After running the command, open your “htpasswd” file. The password file entry for the user “foo” is shown below. This line contains the username and encrypted password. Since this is the first and only user in the file, this should be the only line in the file.

foo:{SHA}Ys23Ag/5IOWqZCw9QGaVDdHwH00=

Node.js Incorporation

The next step is to add authentication support to our HTTP server. First, you will need to install the http-auth module using the following npm command.

npm install http-auth

Next, create a new file named “basic_auth_server.js”, and add the code shown below. Notice that the http-auth module is referenced on line 2. On lines 3 through 7, a configuration object is passed to the authentication module. The authRealm field defines an authentication realm. The authFile field points to the password file we created earlier. __dirname refers to the directory that the currently executing script resides in. This example assumes that the “htpasswd” file is in the same directory as “basic_auth_server.js”. The authType configuration field indicates the type of authentication to use. On line 9, the basic authentication scheme is applied to the HTTP connection. The authentication callback function provides the authenticated username for further processing.

var http = require("http");
var auth = require("http-auth");
var basic = auth({
  authRealm: "Private area",
  authFile: __dirname + "/htpasswd",
  authType: "basic"
});
var server = http.createServer(function(request, response) {
  basic.apply(request, response, function(username) {
    response.writeHead(200, {"Content-Type": "text/plain"});
    response.write("Hello " + username);
    response.end();
  });
});

server.listen(80);
console.log("Server is listening");

Finally, start the server. You can connect to the server by navigating to http://localhost. You will be prompted for a username and password. Provide the credentials you created earlier, and the browser will respond by greeting you by name.

Limitations

The biggest shortcoming of basic access authentication is the fact that credentials are sent over the network as plaintext. This type of authentication should only be used with secure (i.e. HTTPS) connections in order to prevent eavesdropping. If a secure connection is not available, a more secure form of authentication should be used instead.

Digest Access Authentication

Digest access authentication is a more secure alternative to basic authentication. With digest authentication, passwords are encrypted prior to network transmission.

The Password File

Digest authentication also uses a password file. However, the format of the file is slightly different from the one used for basic authentication. In order to work with the digest password file format, we will use a different utility named htdigest. Install htdigest using the following npm command.

npm install -g htdigest

Next, create a new password file using the command shown below. Again, the -c flag is used to create a new password file named “htpasswd”. This time we must also specify an authentication realm. In this case, the authentication realm is “Private area”. In this example, the username is “foo” again. Notice that the password is not provided in the command. Once you enter the command, you will be prompted to provide the password.

htdigest -c htpasswd "Private area" foo

After running htdigest, look inside the new “htpasswd” file. The entry for “foo” is shown below. The digest authentication file contains the username and encrypted password, as well as the authentication realm, which was not included in the basic authentication file.

foo:Private area:b8e1b1c08abcd38173a7dba3ad93a0c3

Node.js Incorporation

To incorporate digest authentication into our server, we will use the http-auth module again. If you’ve been following along with this tutorial, the module should already be installed on your machine. Next, create a new file named “digest_auth_server.js” to implement your server. The server code is shown below. Notice that the server code is nearly identical to the basic authentication server code. The difference lies in the authType field of the configuration object. In this case, authType has been set to "digest". This server can be accessed in the same fashion as the basic authentication server.

var http = require("http");
var auth = require("http-auth");
var digest = auth({
  authRealm: "Private area",
  authFile: __dirname + "/htpasswd",
  authType: "digest"
});
var server = http.createServer(function(request, response) {
  digest.apply(request, response, function(username) {
    response.writeHead(200, {"Content-Type": "text/plain"});
    response.write("Hello " + username);
    response.end();
  });
});

server.listen(80);
console.log("Server is listening");

Conclusion

This article has covered the basics of HTTP authentication. By following the examples provided here, your Node.js applications can be a little more secure. However, you should be aware that authentication alone is not enough. If security is a primary concern, your site should be served over HTTPS. In future articles, I’ll explore HTTPS and many other awesome Node.js features.

If you’ve enjoyed this post, you’re going to want to learn all about SitePoint’s newest series of print and ebooks, Jump Start. The first title is Node.js by Don Nguyen — find out more at SitePoint!

Win an Annual Membership to Learnable,

SitePoint's Learning Platform

  • Rahmat Awaludin

    Thanks for the tutorial Colin!
    Anyway, i’m trying your first code snippet in ubuntu (just copy n paste it). But, when I run it, terminal show this message:
    Server is listening

    events.js:48
    throw arguments[1]; // Unhandled ‘error’ event
    ^
    Error: listen EACCES
    at errnoException (net.js:670:11)
    at Array.0 (net.js:756:28)
    at EventEmitter._tickCallback (node.js:190:39)

    Any idea?

    • http://www.cjihrig.com Colin Ihrig

      Thanks for reading! I don’t think you have permissions to bind port 80. Try listening on port 8080 (assuming nothing is already running on 8080).

    • cGuille

      You need root permissions to bind port 80, so you’ll have to use another one as Colin Ihrig said, or run node with root permissions (`sudo node your-script.js`).

  • Avinash

    Colin I must say nice article series..

    • http://www.cjihrig.com Colin Ihrig

      Thanks Avinash!

  • Varun Tak

    great stuff Colin.. keep it up.

    • http://www.cjihrig.com Colin Ihrig

      Thank you, Varun!

  • Bryan Kimani

    This is a nice tutorial.Easy to follow along. I am teaching my self node.js and your article has been helpful to me. Is good to always use another port instead of port 80 which may be being used by other services in your localhost.

    • http://www.cjihrig.com Colin Ihrig

      Yes, Bryan, it is not uncommon for port 80 to be in use. Some machines may even require admin/root privileges to use it. The upside is that browsers automatically connect to port 80, so it makes your URLs simpler.

  • viyancs

    it’s what i’m looking for…great article Colin…thanks for share

    • http://www.cjihrig.com Colin Ihrig

      Thanks for reading, viyancs!

  • Prabu

    thank you very much sir for sharing your knowledge about this stuff. i’m very appreciate it. and this tutorial is a must-read by everyone who wants to know the basics about node.js, once again thanks in advance.

    • http://www.cjihrig.com Colin Ihrig

      You’re very welcome!