I am new to this part of backend development using JS and the truth being a new programming language (for me) it is worrying that it suddenly does not meet the structuring and / or security standards.
CLEAN ARCHITECTURE
API / CONTROLLERS / SERVICES / LIBS
ROUTE
//Required application
const express = require('express');
//Required services
const LoginServive = require('../../services/auth/login');
// Schemas
const {
authenticationIdSchema,
authenticationSchema
} = require('../../utils/schemas/auth/login');
// Middleware
const verifyToken = require('../../utils/middleware/verifyTokenHandler.js');
const validationHandler = require('../../utils/middleware/validationHandler')
function loginApi(app)
{
const router = express.Router();
app.use("/api/v1/login", router);
//Class call
const loginService = new LoginServive();
/*
******************************************************************************
******************************************************************************
****************************** POST METHOD ******************************
******************************************************************************
******************************************************************************
*/
router.post('/',
validationHandler(authenticationSchema),
async function(req, res, next) {
const { body:login } = req;
try
{
const response = await loginService.login({ login });
const data = response[0];
req.session.user = {
_id:response[1].id,
_username: response[1].username,
_name: response[1].name,
_role: response[1].role
};
console.log("Session: ", req.session.user);
res.status(201).json(data);
} catch (err) {
next(err);
}
});
}
module.exports = loginApi;
SERVICE
const pool = require('../../lib/db');
const bcrypt = require('bcrypt');
const jwt = require('jsonwebtoken');
const { config } = require('../../config');
class LoginService
{
async login({ login })
{
//Parameters
const { username, password } = login;
//Api Info
const SECRET_API = config.secretApi;
if (username && password)
{
const user_query = `SELECT usr.id,
usr.username,
usr.email,
usr.hash,
CONCAT(pple.name, ' ', pple.lastname) AS full_username,
usr.user_status_id,
usr.user_type_id
FROM users usr
INNER JOIN people pple
ON pple.id = usr.people_id
INNER JOIN user_states usts
ON usts.id = usr.user_status_id
INNER JOIN user_types utps
ON utps.id = usr.user_type_id
WHERE usr.data_status_id = '1'
AND usr.email = ?`;
const rows = await pool.query(user_query, [username]);
if (rows.length > 0) {
const { id, username, email, hash, full_username, user_status_id, user_type_id } = rows[0];
// Compare hash with the plain text password
const match = await bcrypt.compare(password, hash);
if (match) {
//Get the access token
const token = jwt.sign({ _id: id }, SECRET_API, {
expiresIn: 60 * 60 * 8
});
const response = [
{
status: 201,
message:'You are welcome.',
role: user_type_id,
token:token
},
{
id:id,
username: username,
name: full_username,
role: user_type_id
}
];
const authenticationId = await Promise.resolve(response);
return authenticationId || [];
} else {
const authenticationId = {
status: 401,
message:'Wrong password.'
};
return authenticationId || [];
}
} else {
const authenticationId = {
status: 401,
message:'The user does not exist.'
};
return authenticationId || [];
}
}
};
};
module.exports = LoginService;
MySQL SESSION STORE
For the session data store I am implementing express-mysql-session this as reflected in the direct documentation of express-session
.
Warning The default server-side session storage, MemoryStore, is purposely not designed for a production environment. It will leak memory under most conditions, does not scale past a single process, and is meant for debugging and developing.
QUESTIONS
I am trying to implement the Clean Architecture development model and set aside the MVC model, looking for maximum performance in this development part.
- Is my code exposed to some kind of SQL injection or other type of security flaw?
- The user session is an important issue (due to security and performance issues). It is a good practice for what I am doing, since I expected to do it directly from the service but I had problems accessing the request
req
. - Is any part of the code improvable?
- Should I have the session data assigned in the token
{ _id: id }
or implement express-session?