Before we can secure the users
module by implementing the permission and validation
middleware, we’ll need to be able to generate a valid token for the current
user. We will generate a JWT in response to the user providing a valid email
and password. JWT is a remarkable JSON web token that you can use to have the
user securely make several requests without validating repeatedly. It usually
has an expiration time, and a new token is recreated every few minutes to keep
the communication secure. For this tutorial, though, we will forgo refreshing
the token and keep it simple with a single token per login.
First, we will create an endpoint for POST
requests to /auth
resource. The request body will contain the user email and
password:
{
"email" :
"marcos.henrique2@toptal.com",
"password" :
"s3cr3tp4sswo4rd2"
}
Before we engage the controller we should validate the user
in /authorization/middlewares/verify.user.middleware.js
:
exports.isPasswordAndUserMatch =
(req, res, next) => {
UserModel.findByEmail(req.body.email)
.then(
(user)=>{
if(!user[
0]){
res.status(
404).send({});
}
else{
let passwordFields = user[
0].password.split(
'$');
let salt = passwordFields[
0];
let hash = crypto.createHmac(
'sha512', salt).update(req.body.password).digest(
"base64");
if (hash === passwordFields[
1]) {
req.body = {
userId: user[
0]._id,
email: user[
0].email,
permissionLevel: user[
0].permissionLevel,
provider:
'email',
name: user[
0].firstName +
' ' + user[
0].lastName,
};
return next();
}
else {
return res.status(
400).send({
errors: [
'Invalid email or password']});
}
}
});
};
Having done that we can move on to the controller and generate the JWT:
exports.login =
(req, res) => {
try {
let refreshId = req.body.userId + jwtSecret;
let salt = crypto.randomBytes(
16).toString(
'base64');
let hash = crypto.createHmac(
'sha512', salt).update(refreshId).digest(
"base64");
req.body.refreshKey = salt;
let token = jwt.sign(req.body, jwtSecret);
let b =
new Buffer(hash);
let refresh_token = b.toString(
'base64');
res.status(
201).send({
accessToken: token,
refreshToken: refresh_token});
}
catch (err) {
res.status(
500).send({
errors: err});
}
};
Even though we won’t be refreshing the token in this tutorial, the controller has been set up to enable such generation to make it easier to implement it in subsequent development.
All we need now is to create the route and invoke the appropriate
middleware in /authorization/routes.config.js
:
app.post(
'/auth', [
VerifyUserMiddleware.hasAuthValidFields,
VerifyUserMiddleware.isPasswordAndUserMatch,
AuthorizationController.login
]);
The response will contain the generated JWT in the accessToken field:
{
"accessToken":
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiI1YjAyYzVjODQ4MTdiZjI4MDQ5ZTU4YTMiLCJlbWFpbCI6Im1hcmNvcy5oZW5yaXF1ZUB0b3B0YWwuY29tIiwicGVybWlzc2lvbkxldmVsIjoxLCJwcm92aWRlciI6ImVtYWlsIiwibmFtZSI6Ik1hcmNvIFNpbHZhIiwicmVmcmVzaF9rZXkiOiJiclhZUHFsbUlBcE1PakZIRG1FeENRPT0iLCJpYXQiOjE1MjY5MjMzMDl9.mmNg-i44VQlUEWP3YIAYXVO-74803v1mu-y9QPUQ5VY",
"refreshToken":
"U3BDQXBWS3kyaHNDaGJNanlJTlFkSXhLMmFHMzA2NzRsUy9Sd2J0YVNDTmUva0pIQ0NwbTJqOU5YZHgxeE12NXVlOUhnMzBWMGNyWmdOTUhSaTdyOGc9PQ=="
}
Having created the token, we can use it inside the Authorization
header using the form Bearer ACCESS_TOKEN
.