Reputation: 20545
I am creating an production angularJs
application.
Now ive created parts of my RESTFul
API
this API
generates a user
object on login however i am not keen on sending the password
unhashed / un incrypted over the HTTP header.
To give you some insight of my API
:
on login:
var jwt = require('jwt-simple');
// Route: /login
module.exports = function (express, sequelize, router) {
var DataTypes = require("sequelize");
var crypto = require('crypto');
var User = sequelize.define('user', {
id: DataTypes.INTEGER,
username: DataTypes.STRING,
name: DataTypes.STRING,
organization_id: DataTypes.INTEGER,
type_id: DataTypes.INTEGER,
division_id: DataTypes.INTEGER
}, {
freezeTableName: true,
instanceMethods: {
retrieveByNamePassword: function (username, onSuccess, onError) {
User.find({where: {username: username}}, {raw: true})
.then(onSuccess).catch(onError);
}
}
}
);
router.route('/login')
.post(function (req, res) {
var user = User.build();
var username = req.body.username || '';
var password = req.body.password || '';
if (username == '' || password == '') {
res.status(401);
res.json({
"status": 401,
"message": "Invalid credentials"
});
return;
}
user.retrieveByNamePassword(username, function (users) {
if (users) {
// If authentication is success, we will generate a token
// and dispatch it to the client
res.json(genToken(users));
return;
} else {
// If authentication fails, we send a 401 back
res.status(401);
res.json({
"status": 401,
"message": "Invalid credentials"
});
return;
}
}, function (error) {
res.status(401);
res.json({
"status": 401,
"message": "Invalid credentials"
});
return;
});
});
var genToken = function(user) {
var expires = expiresIn(7); // 7 days
var token = jwt.encode({
exp: expires,
user_id: user.id,
organization_id: user.organization_id,
type_id: user.type_id,
division_id: user.division_id
}, require('./config/secret')());
return {
token: token,
expires: expires,
user: user
};
};
var expiresIn = function(numDays) {
var dateObj = new Date();
return dateObj.setDate(dateObj.getDate() + numDays);
};
As you can see right now (Because i am not sure yet how to handle it) am only looking for the username and then checks that the username exists.
My question is fairly simple how do you go around encrypting the password and then validate it once it reaches the API?
Upvotes: 3
Views: 2769
Reputation: 496
This is super late, but could you not add a hook after the user model that uses crypt? (Like this: https://www.youtube.com/watch?v=pquxHIBx8ks)
// User model...
}, {
hooks: {
beforeValidate: function() {
},
afterValidate: function(User) {
User.hashword = bcrypt.hashSync(User.hashword, 10);
},
beforeCreate: function() {
},
afterCreate: function() {
}
}
});
Upvotes: 1
Reputation: 3469
JWT can be used with both encrypted and non-encrypted data. However regardless of whether or not you're encrypting the information you're transferring, there is always a signing process involved which allows you to verify that the information you're receiving hasn't been tampered with before you read it.
For the use case of transferring login state via the URL between domains, I would say not including the password at all in your JWT would be the best option.
Take the following process for example:
Authenticate the user. If successful, create a JWT containing at least:
2.1. exp: expiry time (let's say current time + 10 to 15 seconds at most)
2.2. iat: token creation time
2.3. email: user's email address
2.4. do not include the users password (or any other sensative data).
Redirect your user to your domain2 with your JWT token in the URL
This works because as long as the JWT data validates, the second domain doesn't actually need to know your users password, because domain1 server has already validated the login and is simply telling domain2 to accept it. So long as your JWT secret key is kept completely secret, this should be fairly secure. I would also encourage having an automated method of randomly changing your secret key on both servers periodically if possible as well.
Note: with this method, anyone that gets hold of the JWT can view the data contained in it - so do not transfer any confidential or sensative information there.
Note 2: This method would be vulnerable to a replay attack for whatever time period you set in your expiry field of the JWT. If a third party can get hold of the token during that timeframe, they would be able to also use the token to log themselves in as that user. For this reason, you must keep the expiry field as low as possible to reduce the risk of this.
Upvotes: 2