From 69b111d99572b263e78f65e3fb22921f01a16566 Mon Sep 17 00:00:00 2001 From: Pau Date: Wed, 14 May 2025 19:21:04 +0200 Subject: [PATCH] small fix to not allow refresh and access to be treated as the same for auth validation --- src/middlewares/auth.js | 26 +++++++++++++------------- src/routes/index.js | 2 +- src/services/authService.js | 24 ++++++++++-------------- 3 files changed, 24 insertions(+), 28 deletions(-) diff --git a/src/middlewares/auth.js b/src/middlewares/auth.js index fb2485e..761dfd0 100644 --- a/src/middlewares/auth.js +++ b/src/middlewares/auth.js @@ -5,6 +5,7 @@ import { error404, errorHandler } from '../utils/errors.js'; import { noResults } from '../validators/result-validators.js'; import mysql from '../adapters/mysql.js'; + const obtainToken = (req, res) => { return new Promise((resolve, reject) => { const token = req.header('Authorization')?.replace('Bearer ', ''); @@ -23,7 +24,7 @@ const setToken = (result, req, res, next, config) => { next({ user: { ...result, accessToken, refreshToken} }) } -const authenticateToken = (req, res, next) => { +const authenticateToken = (req, res, next, config) => { obtainToken(req, res) .then((token) => getDataFromToken(token)) .then((decoded) => { @@ -31,21 +32,25 @@ const authenticateToken = (req, res, next) => { next(); }) .catch((error) => { - return sendResponseUnauthorized(res, error); + const err = errorHandler(error, config.environment) + res.status(err.code).json(err) }); }; const refreshAuthenticate = (req, res, next) => { const token = req.body.refreshToken - getDataFromToken(token) + getDataFromToken(token, 'refresh') .then((decoded) => { req.auth = decoded; next(); }) .catch((error) => { + if (error.code === 'TOKEN_TYPE_MISMATCH') { + return sendResponseForbidden(res, error); // 403 Forbidden + } return sendResponseUnauthorized(res, error); }); - } +} const authorizePermission = (endpoint) => { return (req, res, next, config) => { @@ -53,7 +58,7 @@ const authorizePermission = (endpoint) => { .then((token) => getDataFromToken(token)) //extract user data from the token .then((decoded) => { const roleName = decoded.role - _getRolePermissionsByName(roleName, config) + _getRolePermissionsByName(res, roleName, config) .then((rolePermissions) => { const action = req.method //check if the user has the necessary permissions @@ -77,22 +82,17 @@ const authorizePermission = (endpoint) => { }; }; -const _getRolePermissionsByName = (roleName, config) => { +const _getRolePermissionsByName = (res, roleName, config) => { const conn = mysql.start(config) return getRolesHasPermissionsModel({ roleName, conn }) .then((response) => { - if (noResults(response)) { - const err = error404() - const error = errorHandler(err, config.environment) - return sendResponseNotFound(response, error) - } return response.map(({ permission_action, permission_endpoint }) => ({ permission_action, permission_endpoint })) }) - .catch((err) => { - errorHandler(err, config.environment) + .catch((err) =>{ + throw err }) .finally(() => { mysql.end(conn) diff --git a/src/routes/index.js b/src/routes/index.js index 3647689..5d1514d 100644 --- a/src/routes/index.js +++ b/src/routes/index.js @@ -1723,7 +1723,7 @@ export default(config) => { varChar('username'), varChar('password'), varChar('email').optional({ nullable: true, values: 'falsy' }), - varChar('fk_role') + varChar('fk_role').optional({nullable: false, values: 'falsy'}) ], (req, res, next) => payloadExpressValidator(req, res, next, config), (req, res, next) => postRegisterController(req, res, next, config), diff --git a/src/services/authService.js b/src/services/authService.js index 45b6dcb..2f98007 100644 --- a/src/services/authService.js +++ b/src/services/authService.js @@ -13,11 +13,19 @@ dotenv.config(); * @param {string} token - The JWT token to verify. * @returns {Promise} - Resolves with the decoded token payload. */ -const getDataFromToken = (token) => { +const getDataFromToken = (token, expectedType = 'access') => { return new Promise((resolve, reject) => { const JWT_SECRET = process.env.JWT_SECRET; jwt.verify(token, JWT_SECRET, (err, decoded) => { - err ? reject(err) : resolve(decoded); + if (err) { + reject(err); + } else if (decoded.type !== expectedType) { + const err = error403() + const error = errorHandler(err) + reject(error); + } else { + resolve(decoded); + } }); }); }; @@ -70,26 +78,14 @@ const checkPermission = (action, endpoint, userPermissions, config) => { } return { hasPermission: false }; }) - .catch((error) => { - const err = error403() - return errorHandler(err, config.environment,`Authorization failed: ${error.message}`); - }); }; const _getEndpointByRoute = (route, config) => { const conn = mysql.start(config) return getEndpointsModel({ route, conn }) .then((endpointInformation) => { - if (noResults(endpointInformation)) { - const err = error404() - errorHandler(err, config.environment) - } - return endpointInformation[0] }) - .catch((err) => { - errorHandler(err, config.environment) - }) .finally(() => { mysql.end(conn) })