In this post we will be discussing about implementing digest authentication in Node.js and how to process a Digest Authentication request over plain HTTP. Digest Authentication combines Basic Authentication with MD5 encryption thus helps in avoiding the transmission of plain text passwords.
According to Wiki, Digest access authentication is one of the agreed-upon methods a web server can use to negotiate credentials, such as username or password, with a user's web browser.
Also Read : Implement Basic Authentication in NodeJS
Example of Digest Authentication
var http = require('http');
var crypto = require('crypto');
var username = 'codingdefined',
password = 'coding',
realm = 'Digest Authentication - Coding Defined',
hasedMsg;
function hashFunction(message) {
return crypto.createHash('md5').update(message).digest('hex');
}
hasedMsg = hashFunction(realm);
http.createServer(function (req, res) {
var auth, login, digestAuth = {};
if(!req.headers.authorization) {
authenticateResponse(res);
return;
}
auth = req.headers.authorization.replace(/^Digest /, '');
auth = getAuth(auth);
digestAuth.hashValue1 = hashFunction(auth.username + ':' + realm + ':' + password);
digestAuth.hashValue2 = hashFunction(req.method + ':' + auth.uri);
digestAuth.response = hashFunction([digestAuth.hashValue1, auth.nonce, auth.nc, auth.cnonce, auth.qop, digestAuth.hashValue2].join(':'));
if(auth.response !== digestAuth.response) {
authenticateResponse(res);
return;
}
res.end('Login Successful');
}).listen(8052);
function authenticateResponse(res) {
res.writeHead(401, {'WWW-Authenticate' : 'Digest realm="' + realm + '"' + ', qop="auth",nonce="' + Math.random() + '"' + ',opaque="' + hasedMsg + '"'});
res.end('Authorization required');
}
function getAuth (auth) {
var authObj = {};
auth.split(', ').forEach(function (value) {
value = value.split('=');
authObj[value[0]] = value[1].replace(/"/g, '');
});
return authObj;
}
We have included crypto module for creating a md5 hashing. In Digest Authentication several attributes are included like realm, qop, nonce and opaque in WWW-Authenticate header where realm is same as Basic Authentication, opaque is an MD5 hash of the realm, qop (Quality of Protection) attribute set to auth and nounce attribute is just a random integer.
The getAuth function converts all the attributes to an object (authObj). The first hash digestAuth.hashValue1 contains username and password, the second hash digestAuth.hashValue2 contains request method (i.e. GET) and uri attribute. The digest response digestAuth.response contains digestAuth.hashValue1, nonce, nc, cnounce, qop and digestAuth.hashValue2 each separated by colon(:). Then we check the digest.response with the original response. If both are not same (login failed) user will be presented with another authentication dialog. If both are same then the Login is Successful.
Please Like and Share the CodingDefined Blog, if you find it interesting and helpful.
According to Wiki, Digest access authentication is one of the agreed-upon methods a web server can use to negotiate credentials, such as username or password, with a user's web browser.
Also Read : Implement Basic Authentication in NodeJS
Example of Digest Authentication
var http = require('http');
var crypto = require('crypto');
var username = 'codingdefined',
password = 'coding',
realm = 'Digest Authentication - Coding Defined',
hasedMsg;
function hashFunction(message) {
return crypto.createHash('md5').update(message).digest('hex');
}
hasedMsg = hashFunction(realm);
http.createServer(function (req, res) {
var auth, login, digestAuth = {};
if(!req.headers.authorization) {
authenticateResponse(res);
return;
}
auth = req.headers.authorization.replace(/^Digest /, '');
auth = getAuth(auth);
digestAuth.hashValue1 = hashFunction(auth.username + ':' + realm + ':' + password);
digestAuth.hashValue2 = hashFunction(req.method + ':' + auth.uri);
digestAuth.response = hashFunction([digestAuth.hashValue1, auth.nonce, auth.nc, auth.cnonce, auth.qop, digestAuth.hashValue2].join(':'));
if(auth.response !== digestAuth.response) {
authenticateResponse(res);
return;
}
res.end('Login Successful');
}).listen(8052);
function authenticateResponse(res) {
res.writeHead(401, {'WWW-Authenticate' : 'Digest realm="' + realm + '"' + ', qop="auth",nonce="' + Math.random() + '"' + ',opaque="' + hasedMsg + '"'});
res.end('Authorization required');
}
function getAuth (auth) {
var authObj = {};
auth.split(', ').forEach(function (value) {
value = value.split('=');
authObj[value[0]] = value[1].replace(/"/g, '');
});
return authObj;
}
We have included crypto module for creating a md5 hashing. In Digest Authentication several attributes are included like realm, qop, nonce and opaque in WWW-Authenticate header where realm is same as Basic Authentication, opaque is an MD5 hash of the realm, qop (Quality of Protection) attribute set to auth and nounce attribute is just a random integer.
The getAuth function converts all the attributes to an object (authObj). The first hash digestAuth.hashValue1 contains username and password, the second hash digestAuth.hashValue2 contains request method (i.e. GET) and uri attribute. The digest response digestAuth.response contains digestAuth.hashValue1, nonce, nc, cnounce, qop and digestAuth.hashValue2 each separated by colon(:). Then we check the digest.response with the original response. If both are not same (login failed) user will be presented with another authentication dialog. If both are same then the Login is Successful.
Nice code.
ReplyDeleteIs there a client implementation which makes use of it?