Skip to content

Instantly share code, notes, and snippets.

@psi-4ward
Created January 12, 2015 16:09
Show Gist options
  • Star 12 You must be signed in to star a gist
  • Fork 12 You must be signed in to fork a gist
  • Save psi-4ward/70856147e30106cc8166 to your computer and use it in GitHub Desktop.
Save psi-4ward/70856147e30106cc8166 to your computer and use it in GitHub Desktop.
Sails.JS JWT Auth
// policies/authenticated.js
module.exports = function(req, res, next) {
// adopt the User from the socket
if(req.isSocket && req.socket.User) {
req.User = req.socket.User;
return next();
}
// get token from header an validate it
var token = req.headers["x-token"];
function send401() {
res.send(401, {err: 'E_LOGIN_REQUIRED', message: 'Login required'});
}
// validate we have all params
if(!token) return send401();
// validate token and set req.User if we have a valid token
sails.services.tokenauth.verifyToken(token, function(err, data) {
if(err) return send401();
sails.models.user.findOne({id: data.userId}, function(err, User) {
if(err) send401();
req.User = User;
next();
});
});
};
// controllers/LoginController.js
module.exports = {
index: function(req, res) {
var email = req.param('email');
var password = req.param('password');
// delay everthing to prevent bruteforce, dos and timing attacks
setTimeout(function() {
if(!email || !password) {
return res.json(401, {err: 'email and password required'});
}
sails.models.user.findOne({email: email}, function(err, User) {
if(!User) {
return res.json(401, {err: 'invalid email or password'});
}
User.verifyPassword(password, function(err, valid) {
if(err) {
return res.json(403, {err: 'forbidden'});
}
if(!valid) {
return res.json(401, {err: 'invalid email or password'});
} else {
res.json({user: User, token: sails.services.tokenauth.generateToken({userId: User.id})});
// register in socket if this is a socket-request
if(req.isSocket) {
req.socket.User = User;
}
}
});
});
}, 200);
},
/**
* attach the User to the socket using a token
* (socket.io reconnect)
* @param req
* @param res
* @returns {*}
*/
authSocket: function(req, res) {
if(!req.isSocket) {
return res.json(400, 'This route is for socket connections only');
}
var token = req.param('token');
if(!token) return res.json(401, 'token missing');
sails.services.tokenauth.getUser(token, function(err, User) {
if(err || !User) {
return res.json(401, 'token invalid');
}
req.socket.User = User;
res.json(200, User.toJSON());
});
},
/**
* "logout" for sockets
* @param req
* @param res
* @returns {*}
*/
deauthSocket: function(req, res) {
if(!req.isSocket) {
return res.json(400, 'This route is for socket connections only');
}
delete req.socket.User;
res.json(200, 'ok');
}
};
// services/tokenauth.js
var jwt = require('jsonwebtoken');
var tokenauth = {
generateToken: function(payload) {
return jwt.sign(payload, sails.config.crypto.tokenSecret);
},
verifyToken: function(token, cb) {
return jwt.verify(token, sails.config.crypto.tokenSecret, {}, cb);
},
getUser: function(token, cb) {
tokenauth.verifyToken(token, function(err, data) {
if(err) return cb(err);
sails.models.user.findOne({id: data.userId}, function(err, User) {
if(err) return cb(err);
cb(null, User);
});
});
}
};
module.exports = tokenauth;
// models/user.js
/**
* user.js
* @docs :: http://sailsjs.org/#!documentation/models
*/
var bcrypt = require('bcrypt');
module.exports = {
schema: false,
labels: {
name: {
title: "Name"
},
email: {
title: "E-Mail"
},
password: {
title: "Passwort"
},
isAdmin: {
title: 'Administrator'
}
},
types: {
password: function(password) {
return password === this.passwordConfirm;
}
},
attributes: {
name: {
type: 'string'
},
email: {
type: 'string',
required: true,
unique: true,
email: true,
minLength: 3
},
password: {
type: 'string',
password: true,
minLength: 8,
required: true
},
isAdmin: {
type: 'boolean'
},
// Alter JSON response
toJSON: function() {
var obj = this.toObject();
delete obj.password;
return obj;
},
verifyPassword: function(password, cb) {
return bcrypt.compare(password, this.password, cb);
}
},
beforeCreate: function(data, cb) {
bcrypt.hash(data.password, sails.config.crypto.workFactor, function(err, hash) {
data.password = hash;
delete data.passwordConfirm;
cb();
});
},
beforeUpdate: function(data, cb) {
if(data.password) {
bcrypt.hash(data.password, sails.config.crypto.workFactor, function(err, hash) {
data.password = hash;
delete data.passwordConfirm;
cb();
});
} else {
return cb();
}
}
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment