Basic HTTP authentication with Node and Express 4

It seems that implementing basic HTTP authentication using Express v3 was trivial:

app.use(express.basicAuth('username', 'password')); 

Version 4 (I'm using 4.2) basicAuth , so I'm a bit stuck. I have the following code, but it does not force the browser to ask the user for credentials, which I would like (and, it seems to me, the old method):

 app.use(function(req, res, next) { var user = auth(req); if (user === undefined || user['name'] !== 'username' || user['pass'] !== 'password') { res.writeHead(401, 'Access invalid for user', {'Content-Type' : 'text/plain'}); res.end('Invalid credentials'); } else { next(); } }); 
+86
May 12 '14 at 18:37
source share
8 answers

I used the code for the original basicAuth to find the answer:

 app.use(function(req, res, next) { var user = auth(req); if (user === undefined || user['name'] !== 'username' || user['pass'] !== 'password') { res.statusCode = 401; res.setHeader('WWW-Authenticate', 'Basic realm="MyRealmName"'); res.end('Unauthorized'); } else { next(); } }); 
+33
May 12 '14 at 18:37
source
β€” -

Simple Basic Authentication 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] = new Buffer(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 change the logic. See Example 1 statement below or edit history for this answer.

What for?

  • req.headers.authorization contains the value " Basic <base64 string> ", but it can also be empty, and we do not want it to fail, so the strange combination || '' || '' || '' || ''
  • The node does not know atob() and btoa() , therefore, Buffer

ES6 β†’ ES5

const just var .. view
(x, y) => {...} it's just function(x, y) {...}
const [login, password] =...split() are just two var assignments in one

source of inspiration (uses packages)




The above is a very simple example, which was supposed to be very short and quickly deployable on a playground server. But, as noted in the comments, passwords can also contain colon characters : To correctly extract it from b64auth, you can use this.
  // parse login and password from headers const b64auth = (req.headers.authorization || '').split(' ')[1] || '' const strauth = new Buffer(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 authentication in one statement

... on the other hand, if you use only one or very few login names, this is a necessary minimum: (you don’t even need to analyze 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 a "safe" and a "public" path? Try using express.router .

 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 
+72
Nov 24 '15 at 23:15
source

A lot of middleware was taken out of the Express kernel in version 4 and put into separate modules. The main auth module is here: https://github.com/expressjs/basic-auth-connect

In your example, you just need to change this:

 var basicAuth = require('basic-auth-connect'); app.use(basicAuth('username', 'password')); 
+57
Jun 25 '14 at 20:20
source

TL; DR:

β˜’ express.basicAuth is no more
β˜’ basic-auth-connect deprecated
β˜’ basic-auth has no logic
β˜’ http-auth is overkill
β˜‘ express-basic-auth is what you want

More information:

Since you use Express, you can use express-basic-auth middleware.

See documents:

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! })); 
+37
Mar 01 '18 at 5:53
source

I changed the basic authentication in express 4.0 with http-auth , code:

 var auth = require('http-auth'); var basic = auth.basic({ realm: "Web." }, function (username, password, callback) { // Custom authentication method. callback(username === "userName" && password === "password"); } ); app.get('/the_url', auth.connect(basic), routes.theRoute); 
+32
Jul 08 '14 at 10:04 on
source

It seems that there are several modules, some of them are outdated.

This one looks active:
https://github.com/jshttp/basic-auth

Here is a usage example:

 // auth.js var auth = require('basic-auth'); var admins = { 'art@vandelay-ind.org': { password: 'pa$$w0rd!' }, }; module.exports = function(req, res, next) { var user = auth(req); if (!user || !admins[user.name] || admins[user.name].password !== user.pass) { res.set('WWW-Authenticate', 'Basic realm="example"'); return res.status(401).send(); } return next(); }; // app.js var auth = require('./auth'); var express = require('express'); var app = express(); // ... some not authenticated middlewares app.use(auth); // ... some authenticated middlewares 

Make sure the auth middleware is installed in the right place, any middleware will not be completed before that.

+19
Jan 01 '15 at 9:23
source

We can implement basic authorization without the need for a module

 //1. var http = require('http'); //2. var credentials = { userName: "vikas kohli", password: "vikas123" }; var realm = 'Basic Authentication'; //3. function authenticationStatus(resp) { resp.writeHead(401, { 'WWW-Authenticate': 'Basic realm="' + realm + '"' }); resp.end('Authorization is needed'); }; //4. var server = http.createServer(function (request, response) { var authentication, loginInfo; //5. if (!request.headers.authorization) { authenticationStatus (response); return; } //6. authentication = request.headers.authorization.replace(/^Basic/, ''); //7. authentication = (new Buffer(authentication, 'base64')).toString('utf8'); //8. loginInfo = authentication.split(':'); //9. if (loginInfo[0] === credentials.userName && loginInfo[1] === credentials.password) { response.end('Great You are Authenticated...'); // now you call url by commenting the above line and pass the next() function }else{ authenticationStatus (response); } }); server.listen(5050); 

Source: - http://www.dotnetcurry.com/nodejs/1231/basic-authentication-using-nodejs

+4
Dec 18 '17 at 11:35
source

Express has removed this feature and now recommends using the basic-auth library.

Here is a usage example:

 var http = require('http') var auth = require('basic-auth') // Create server var server = http.createServer(function (req, res) { var credentials = auth(req) if (!credentials || credentials.name !== 'aladdin' || credentials.pass !== 'opensesame') { res.statusCode = 401 res.setHeader('WWW-Authenticate', 'Basic realm="example"') res.end('Access denied') } else { res.end('Access granted') } }) // Listen server.listen(3000) 

To send a request for this route, you need to include the authorization header formatted for basic auth.

First, sending a curl request, you must take base64 encoding name:pass or in this case aladdin:opensesame , which is equal to YWxhZGRpbjpvcGVuc2VzYW1l

After that, your request will look like this:

  curl -H "Authorization: Basic YWxhZGRpbjpvcGVuc2VzYW1l" http://localhost:3000/ 
+1
Oct 27 '17 at 19:08
source



All Articles