Trying to implement Digest auth in nodejs. Below is the code
var http = require('http');
var auth = require('http-auth');
var express = require('express');
var app = express();
var user;
var basic = auth.basic({
realm: 'Sample',
file: __dirname + "/users.htpasswd",
algorithm:'md5'
});
basic.on('success', (result, req) => {
console.log(`User authenticated: ${result.user}`);
user = result.user;
});
basic.on('fail', (result, req) => {
console.log(`User authentication failed: ${result.user}`);
console.log(req.headers.authorization);
});
basic.on('error', (error, req) => {
console.log(`Authentication error: ${error.code + " - " + error.message}`);
});
http.createServer(app).listen(8000);
app.use(auth.connect(basic));
app.get('/', function(req, res) {
console.log(req.headers);
console.log(basic);
res.json('Hello from '+ user);
res.end();
});
app.post('/', function(req, res) {
console.log(req.headers);
console.log(basic);
res.json('Hello from '+ user);
res.end();
});
This is the content of users.htpasswd file:-
ankit:Sample:e4b2d19b03346a1c45ce86ad41b85c5e
Using postman to call the end point with username ankit, pwd ankit & realm Sample, everytime I am getting 401.
Please let me know where I am doing wrong.
Thanks
You're mixing basic auth and digest auth. Replace auth.basic with auth.digest and your code should work as-is.
Related
I need a little help figuring out how to get this working -- I've tested and have working JWT authentication and SSL on my '/user' routes. I'm trying to safely allow the user to upload an audio file, also using the JWT and SSL route.
The authentication middleware works, and multer works to let me upload files when I comment out the authentication middleware. However, when I leave the middleware in, the uploaded file is created on my system, but the file fails to upload properly and I get a 404 error.
Thanks for any help!
server.js (main file)
var express = require('express')
, app = express()
, passport = require('passport')
, uploads = require('./config/uploads').uploads
, user_routes = require('./routes/user')
, basic_routes = require('./routes/basic')
, jwt = require('jwt-simple');
// get our request parameters
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
// Use the passport package in our application
app.use(passport.initialize());
require('./config/passport')(passport);
//double check we have an ssl connection
function ensureSec(req, res, next) {
if (req.headers['x-forwarded-proto'] == 'https') {
return next();
} else {
console.log('NOT SSL PROTECTED! rejected connection.');
res.redirect('https://' + req.headers.host + req.path);
}
}
app.use(ensureSec);
//authenticate all user routes with passport middleware, decode JWT to see
//which user it is and pass it to following routes as req.user
app.use('/user', passport.authenticate('jwt', {session:false}), user_routes.middleware);
//store info on site usage- log with ID if userRoute
app.use('/', basic_routes.engagementMiddleware);
// bundle our user routes
var userRoutes = express.Router();
app.use('/user', userRoutes);
userRoutes.post('/upload', uploads:q, function(req,res){
res.status(204).end("File uploaded.");
});
// Start the server
app.listen(port);
routes/basic_routes.js (tracks engagement middleware)
var db = require('../config/database')
, jwt = require('jwt-simple')
, getIP = require('ipware')().get_ip
, secret = require('../config/secret').secret;
exports.engagementMiddleware = function(req, res, next){
if (typeof(req.user) == 'undefined') req.user = {};
var postData = {};
var ip = getIP(req).clientIp;
var fullUrl = req.protocol + '://' + req.get('host') + req.originalUrl;
if (req.method=="POST") postData = req.body;
var newEngagement = new db.engagementModel({
user_id: req.user._id,
ipAddress: ip,
url: fullUrl,
action: req.method,
postData: postData
});
//log the engagement
newEngagement.save(function(err) {
if (err) {
console.log('ERROR: engagement middleware db write failed');
next();
}
console.log('LOG: user ' + req.user._id +' from ipAddress: ' + ip + ': ' + req.method + ' ' + fullUrl);
next();
});
next();
}
config/passport.js (passport authentication middleware)
var JwtStrategy = require('passport-jwt').Strategy;
// load up the user model
var db = require('../config/database'); // get db config file
var secret = require('../config/secret').secret;
module.exports = function(passport) {
var opts = {};
opts.secretOrKey = secret;
passport.use(new JwtStrategy(opts, function(jwt_payload, done) {
db.userModel.findOne({id: jwt_payload.id}, function(err, user) {
if (err) {
return done(err, false);
}
if (user) {
done(null, user);
} else {
done(null, false);
}
});
}));
};
routes/user_routes.js (user route middleware, user add to header)
var jwt = require('jwt-simple');
var db = require('../config/database');
var secret = require('../config/secret').secret;
//expose decoded userModel entry to further routes at req.user
exports.middleware = function(req, res, next){
var token = getToken(req.headers);
if (token) req.user = jwt.decode(token, secret);
else res.json({success: false, msg: 'unable to decode token'});
//should be unnecessary, double checking- after token verification against db
db.userModel.findOne({email: req.user.email}, function (err, user) {
if( err || !user ) {
console.log('something has gone horribly wrong. Token good, no user in db or access to db.');
return res.status(403).send({success: false, msg: 'unable to find user in db'});
}
});
//end unnecessary bit
next();
}
//helper function
getToken = function (headers) {
if (headers && headers.authorization) {
var parted = headers.authorization.split(' ');
if (parted.length === 2) return parted[1];
else return null;
} else { return null; }
};
config/uploads.js (finally where we try to upload)
var moment = require('moment');
var multer = require('multer');
var jwt = require('jwt-simple');
var uploadFile = multer({dest: "audioUploads/"}).any();
var storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, 'audioUploads/')
},
filename: function (req, file, cb) {
cb(null, req.user._id + '_' + moment().format('MMDDYY[_]HHmm') + '.wav')
}
});
exports.uploads = multer({storage:storage}).any();
in your server.js do this:
const authWare = passport.authenticate('jwt', {session:false});
userRoutes.post('/upload', authWare, uploads:q, function(req,res){
res.status(204).end("File uploaded.");
});
works for me!
I'd try to get Extended User Access Token from OAuth2 with Nodejs
Actually, the program send out a message (on Browser) with:
XMLHttpRequest cannot load https://www.facebook.com/dialog/oauth?redirect_uri=http%3A%2F%2Flocalhost%3…2Fcallback&scope=user_about_me%2Cpublish_actions&client_id=487932668044758. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3000' is therefore not allowed access.
Using standard express generator, I modified a code in a index.js as below:
var express = require('express');
var request = require('request');
var OAuth2 = require('oauth').OAuth2;
var router = express.Router();
var oauth2 = new OAuth2("487932668044758",
"0793918b3ab637b2096787e10643980a",
"", "https://www.facebook.com/dialog/oauth",
"https://graph.facebook.com/oauth/access_token",
null);
/* GET home page. */
router.get('/', function(req, res, next) {
res.render('index', {
// title: 'Express'
});
});
router.post('/userToken', function(req, res) {
if (!req.body) {
return
res.sendStatus(400)
}
var uid = req.body.uid;
var token = req.body.token;
validate_uid_token(uid, token, res);
console.log('req:', req.body);
console.log("uid: ", uid);
console.log('token: ', token);
// res.send("okie");
});
router.get("/callback", function(req, res) {
console.log('here..form callback');
res.header('Access-Control-Allow-Origin', 'http://localhost3000');
res.header('Access-Control-Allow-Origin', 'https://www.facebook.com/dialog/oauth');
res.header('Access-Control-Allow-Origin', 'https://graph.facebook.com/oauth/access_token');
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
res.header('Access-Control-Allow-Headers', 'Content-Type');
if (req.error_reason) {
res.send(req.error_reason);
}
if (req.query.code) {
var loginCode = req.query.code;
var redirect_uri = "/"; // Path_To_Be_Redirected_to_After_Verification
// For eg. "/facebook/callback"
oauth2.getOAuthAccessToken(loginCode, {
grant_type: 'authorization_code',
redirect_uri: redirect_uri
},
function(err, accessToken, refreshToken, params) {
if (err) {
console.error(err);
res.send(err);
return;
}
var access_token = accessToken;
console.log('access_token : ', access_token);
// var expires = params.expires;
// console.log('expires : ', expires);
req.session.access_token = access_token;
// req.session.expires = expires;
}
);
}
// res.send('okie');
});
function validate_uid_token(uid, token, res) {
var redirect_uri = "http://localhost:3000" + "/callback";
// For eg. "http://localhost:3000/facebook/callback"
var params = {
'redirect_uri': redirect_uri,
'scope': 'user_about_me,publish_actions'
};
res.redirect(oauth2.getAuthorizeUrl(params));
}
module.exports = router;
Click on a url in error message. Browser throws out ma JSON message as
{"statusCode":400,"data":"{\"error\":{\"message\":\"redirect_uri isn't an absolute URI. Check RFC 3986.\",\"type\":\"OAuthException\",\"code\":191}}"}
Could someone help me please...Thank to much..
I'd recommend to use Passport.js together with the passport-facebook strategy. This hides away most of the complexity involved.
See
http://passportjs.org/
https://github.com/jaredhanson/passport-facebook
Information on the express-jwt module can be found here:
https://github.com/auth0/express-jwt
https://www.npmjs.com/package/express-jwt
In my main.js server file, I have the following:
import ExpressJwt from 'express-jwt';
// import other crap...
let token = ExpressJwt({
secret: 'whatever',
audience: 'whatever',
issuer: 'whatever'
});
app.all('/apiv1', token.unless({ path: ['apiv1/user/create', '/apiv1/auth/login']}));
app.use('/apiv1/user', user);
app.use('/apiv1/auth', auth);
Where user and auth are the middlewares that handle my routes. What I want to do is obvious; deny API access to all unauthenticated users, except when they attempt to create a new user via apiv1/user/create and/or login via apiv1/auth/login.
Any time I try to make a request to the aforementioned unprotected paths however, I get the error:
UnauthorizedError: No authorization token was found
It's still protecting the routes I specified to be unprotected! I also tried:
app.use('/apiv1/user', token.unless({ path: ['/apiv1/user/create'] }), user);
app.use('/apiv1/auth', token.unless({ path: ['/apiv1/auth/login'] }), auth);
But that didn't work. I also tried using regex for the unless paths, but that didn't work either.
I arrived at app.all('/apiv1', token...) via this answer, but that solution does not yield me the desired functionality.
Instead of using all:
app.all('/apiv1', token.unless({ path: ['apiv1/user/create', '/apiv1/auth/login']}));
Try using use and adding in the path route a slash / at the beginning:
app.use('/apiv1', token.unless({ path: ['/apiv1/user/create', '/apiv1/auth/login']}));
Here it is an example that is working:
app.js:
var express = require('express');
var app = express();
var expressJwt = require('express-jwt');
var jwt = require('jsonwebtoken');
var secret = 'secret';
app.use('/api', expressJwt({secret: secret}).unless({path: ['/api/token']}));
app.get('/api/token', function(req, res) {
var token = jwt.sign({foo: 'bar'}, secret);
res.send({token: token});
});
app.get('/api/protected', function(req, res) {
res.send('hello from /api/protected route.');
});
app.use(function(err, req, res, next) {
res.status(err.status || 500).send(err);
});
app.listen(4040, function() {
console.log('server up and running at 4040 port');
});
module.exports = app;
test.js:
var request = require('supertest');
var app = require('./app.js');
describe('Test API', function() {
var token = '';
before(function(done) {
request(app)
.get('/api/token')
.end(function(err, response) {
if (err) { return done(err); }
var result = JSON.parse(response.text);
token = result.token;
done();
});
});
it('should not be able to consume /api/protected since no token was sent', function(done) {
request(app)
.get('/api/protected')
.expect(401, done);
});
it('should be able to consume /api/protected since token was sent', function(done) {
request(app)
.get('/api/protected')
.set('Authorization', 'Bearer ' + token)
.expect(200, done);
});
});
I have to test my rest api. Some routes require a value in the http requests headers for the user authentication token.
I have separated my interesting bussiness logic in pure javascript code but I can't find a way to test the routes that require a token in the headers of the http request.
Any other alternatives to mocha and/or supertest are welcome.
With supertest, you can set a header parameter with the set keyword :
api.get('/aroute/')
...
.set('headerParameterName', value)
...
Here is an example of testing a express server API with token authorization using supertest :
app.js:
var express = require('express');
var app = express();
var jwt = require('jsonwebtoken');
var expressJwt = require('express-jwt');
var secret = 'my-secret';
app.get('/get-token', function(req, res) {
var token = jwt.sign({foo: 'bar'}, secret);
res.send({token: token});
});
app.post(
'/test',
expressJwt({
secret: secret
}),
function(req, res) {
res.send({message: 'You could use the route!'});
}
);
app.use(function(err, req, res, next) {
res.status(err.status || 500).send({error: err.message});
});
app.listen(4040, function() {
console.log('server up and running at 4040 port');
});
module.exports = app;
test.js:
var request = require('supertest');
var app = require('./app.js');
describe('Test Route with Token', function() {
var token = '';
before(function(done) {
request(app)
.get('/get-token')
.end(function(err, res) {
var result = JSON.parse(res.text);
token = result.token;
done();
});
});
it('should not be able to consume the route /test since no token was sent', function(done) {
request(app)
.post('/test')
.expect(401, done);
});
it('should be able to consume the route /test since token valid was sent', function(done) {
request(app)
.post('/test')
.set('Authorization', 'Bearer ' + token)
.expect(200, done);
});
});
This is a resume about an authentication method.
I tried to use express.basicAuth, but it forces the browser to ask for user and pass, and I need to use my own login page, like google, facebook yahoo...
Is this right? Is there any better way to do this?
I want to avoid modules, like passport, if I can.
I want to use a function like this, using auth middleware (app.get('/loggedin', auth, function(req, res)...)
var express = require('express');
var app = express();
app.use(express.cookieParser());
var RedisStore = require('connect-redis')(express);
app.use(express.session({
store: new RedisStore({
host: 'localhost',
port: 6379,
db: 2,
pass: 'RedisPASS'
}), secret: '1234567890QWERTY'
}));
var auth = function(req, res, next) {
if (req.session.authStatus === 'loggedIn')
next();
else
res.redirect('/login');
};
app.get('/', function(req, res) {
console.log("/");
res.send('not authenticate');
});
app.get('/signin', function(req, res) {
console.log("/signin");
if (req.body.user && req.body.pass)
{
req.user = req.body.user;
req.remoteUser = req.body.user;
req.session.authStatus = 'loggedIn';
req.session.lastPage = '/signin';
res.redirect('/loggedin');
}
else
res.redirect('/login');
});
app.get('/loggedin', auth, function(req, res) {
if(req.session.lastPage) {
res.write('Last page was: ' + req.session.lastPage + '. ');
}
req.session.lastPage = '/loggedin';
res.write('Yeeeeeeeeeee');
res.end();
});
app.get('/loggedin2', auth, function(req, res) {
console.log("/loggedin2");
if(req.session.lastPage) {
res.write('Last page was: ' + req.session.lastPage + '. ');
}
req.session.lastPage = '/loggedin2';
res.write('WoWWWWW!!!!!!');
res.end();
});
app.get('/logout', auth, function(req, res) {
console.log("/logout");
req.session.destroy();
});
app.get('/login', function(req, res) {
console.log("/notlogged");
res.send('enter user and pass...');
});
app.listen(process.env.PORT || 8080);
You could use the passport middleware module in npm — the passport-local module provides authentication against a local resource such as a database.