node.js – Basic HTTP authentication with Node and Express 4

node.js – Basic HTTP authentication with Node and Express 4

Simple Basic Auth with vanilla JavaScript (ES6)

app.use((req, res, next) => {

  // -----------------------------------------------------------------------
  // authentication middleware

  const auth = {login: yourlogin, password: yourpassword} // change this

  // parse login and password from headers
  const b64auth = (req.headers.authorization || ).split( )[1] || 
  const [login, password] = Buffer.from(b64auth, base64).toString().split(:)

  // Verify login and password are set and correct
  if (login && password && login === auth.login && password === auth.password) {
    // Access granted...
    return next()
  }

  // Access denied...
  res.set(WWW-Authenticate, Basic realm=401) // change this
  res.status(401).send(Authentication required.) // custom message

  // -----------------------------------------------------------------------

})

note: This middleware can be used in any handler. Just remove next() and reverse the logic. See the 1-statement example below, or the edit history of this answer.

Why?

  • req.headers.authorization contains the value Basic <base64 string>, but it can also be empty and we dont want it to fail, hence the weird combo of ||
  • Node doesnt know atob() and btoa(), hence the Buffer

ES6 -> ES5

const is just var .. sort of
(x, y) => {...} is just function(x, y) {...}
const [login, password] = ...split() is just two var assignments in one

source of inspiration (uses packages)


The above is a super simple example that was intended to be super short and quickly deployable to your playground server. But as was pointed out in the comments, passwords can also contain colon characters :. To correctly extract it from the b64auth, you can use this.

  // parse login and password from headers
  const b64auth = (req.headers.authorization || ).split( )[1] || 
  const strauth = Buffer.from(b64auth, base64).toString()
  const splitIndex = strauth.indexOf(:)
  const login = strauth.substring(0, splitIndex)
  const password = strauth.substring(splitIndex + 1)

  // using shorter regex by @adabru
  // const [_, login, password] = strauth.match(/(.*?):(.*)/) || []

Basic auth in one statement

…on the other hand, if you only ever use one or very few logins, this is the bare minimum you need: (you dont even need to parse the credentials at all)

function (req, res) {
//btoa(yourlogin:yourpassword) -> eW91cmxvZ2luOnlvdXJwYXNzd29yZA==
//btoa(otherlogin:otherpassword) -> b3RoZXJsb2dpbjpvdGhlcnBhc3N3b3Jk

  // Verify credentials
  if (  req.headers.authorization !== Basic eW91cmxvZ2luOnlvdXJwYXNzd29yZA==
     && req.headers.authorization !== Basic b3RoZXJsb2dpbjpvdGhlcnBhc3N3b3Jk)        
    return res.status(401).send(Authentication required.) // Access denied.   

  // Access granted...
  res.send(hello world)
  // or call next() if you use it as middleware (as snippet #1)
}

PS: do you need to have both secure and public paths? Consider using express.router instead.

var securedRoutes = require(express).Router()

securedRoutes.use(/* auth-middleware from above */)
securedRoutes.get(path1, /* ... */) 

app.use(/secure, securedRoutes)
app.get(public, /* ... */)

// example.com/public       // no-auth
// example.com/secure/path1 // requires auth

TL;DR:

express.basicAuth is gone
basic-auth-connect is deprecated
basic-auth doesnt have any logic
http-auth is an overkill
express-basic-auth is what you want

More info:

Since youre using Express then you can use the express-basic-auth middleware.

See the docs:

Example:

const app = require(express)();
const basicAuth = require(express-basic-auth);
 
app.use(basicAuth({
    users: { admin: supersecret123 },
    challenge: true // <--- needed to actually show the login dialog!
}));

node.js – Basic HTTP authentication with Node and Express 4

A lot of the middleware was pulled out of the Express core in v4, and put into separate modules. The basic auth module is here: https://github.com/expressjs/basic-auth-connect

Your example would just need to change to this:

var basicAuth = require(basic-auth-connect);
app.use(basicAuth(username, password));

Leave a Reply

Your email address will not be published.