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,
: 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 =
newBuffer(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
.