Reputation: 16156
It looks like implementing basic HTTP authentication with Express v3 was trivial:
app.use(express.basicAuth('username', 'password'));
Version 4 (I'm using 4.2) removed the basicAuth
middleware, though, so I'm a little stuck. I have the following code, but it doesn't cause the browser to prompt the user for credentials, which is what I'd like (and what I imagine the old method did):
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();
}
});
Upvotes: 175
Views: 203259
Reputation: 6581
Yet another solution, i know, but i don't like any of these...and this is what i use. So i'm kind of putting it here so next time i'm looking for it i can find a solution i like.
This requires no modules and even works all the way back to node 9.
...
myRoute: function(req, res, next) {
// first and foremost...send the request to authenticate
const reject = () => {
res.setHeader("www-authenticate", "Basic");
res.sendStatus(401);
};
// next check and see if they have tried to authenticate
const authorization = req.headers.authorization;
if (!authorization) {
// okay, well send the request for authentication here
return reject();
}
// break open the authorization object sent by the users
const [username, password] = Buffer.from(
authorization.replace("Basic ", ""), "base64"
).toString().split(":");
// do NOT leave here!! pull them in from .env or secrets
if (!(username === "user" && password === "p@ssw0rb")) {
return reject();
}
// okay now put your regularly scheduled route result in
res.send('you\'re in myRoute!');
},
...
Upvotes: 0
Reputation: 909
install the express-basic-auth dependency:
npm i express-basic-auth
Require the auth package where you create your app
const app = require('express')();
const basicAuth = require('express-basic-auth');
and setup the middleware like this:
app.use(basicAuth({
users: { 'my-username': 'my-password' },
challenge: true,
}));
Upvotes: 10
Reputation: 81
function auth (req, res, next) {
console.log(req.headers);
var authHeader = req.headers.authorization;
if (!authHeader) {
var err = new Error('You are not authenticated!');
res.setHeader('WWW-Authenticate', 'Basic');
err.status = 401;
next(err);
return;
}
var auth = new Buffer.from(authHeader.split(' ')[1], 'base64').toString().split(':');
var user = auth[0];
var pass = auth[1];
if (user == 'admin' && pass == 'password') {
next(); // authorized
} else {
var err = new Error('You are not authenticated!');
res.setHeader('WWW-Authenticate', 'Basic');
err.status = 401;
next(err);
}
}
app.use(auth);
Upvotes: 8
Reputation: 31915
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.
req.headers.authorization
contains the value "Basic <base64 string>
", but it can also be empty and we don't want it to fail, hence the weird combo of || ''
atob()
and btoa()
, hence the Buffer
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)
:
. 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(/(.*?):(.*)/) || []
...on the other hand, if you only ever use one or very few logins, this is the bare minimum you need: (you don't 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
Upvotes: 203
Reputation: 111258
express.basicAuth
is gonebasic-auth-connect
is deprecatedbasic-auth
doesn't have any logichttp-auth
is an overkillexpress-basic-auth
is what you wantSince you're 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!
}));
Upvotes: 139
Reputation: 8430
We can implement the basic authorization without needing any 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
Upvotes: 8
Reputation: 5125
Express has removed this functionality and now recommends you use the basic-auth library.
Here's an example of how to use:
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 to this route you need to include an Authorization header formatted for basic auth.
Sending a curl request first you must take the base64 encoding of name:pass
or in this case aladdin:opensesame
which is equal to YWxhZGRpbjpvcGVuc2VzYW1l
Your curl request will then look like:
curl -H "Authorization: Basic YWxhZGRpbjpvcGVuc2VzYW1l" http://localhost:3000/
Upvotes: 2
Reputation: 22937
There seems to be multiple modules to do that, some are deprecated.
This one looks active:
https://github.com/jshttp/basic-auth
Here's a use example:
// auth.js
var auth = require('basic-auth');
var admins = {
'[email protected]': { 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 you put the auth
middleware in the correct place, any middleware before that will not be authenticated.
Upvotes: 22
Reputation: 451
I changed in express 4.0 the basic authentication with http-auth, the code is:
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);
Upvotes: 35
Reputation: 625
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'));
Upvotes: 60
Reputation: 16156
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();
}
});
Upvotes: 37