From 0b001533498aae2dcb76a8e04183dab86b11a3f0 Mon Sep 17 00:00:00 2001 From: juancarmore Date: Sat, 10 May 2025 18:18:08 +0200 Subject: [PATCH] backend: Enhance error handling in authentication middleware to control validator flow --- backend/src/middlewares/auth.middleware.ts | 44 ++++++++++++++++------ 1 file changed, 33 insertions(+), 11 deletions(-) diff --git a/backend/src/middlewares/auth.middleware.ts b/backend/src/middlewares/auth.middleware.ts index e22162a..b20b2df 100644 --- a/backend/src/middlewares/auth.middleware.ts +++ b/backend/src/middlewares/auth.middleware.ts @@ -36,9 +36,13 @@ export const withAuth = (...validators: ((req: Request) => Promise)[]): Re // If any middleware granted access, it is not necessary to continue checking the rest return next(); } catch (error) { - // If no middleware granted access, return unauthorized - if (error instanceof OpenViduMeetError) { - lastError = error; + if (isErrorWithControl(error)) { + lastError = error.error; + + if (error.stopValidation) { + // Stop checking other validators + break; + } } } } @@ -58,7 +62,7 @@ export const tokenAndRoleValidator = (role: UserRole) => { const token = req.cookies[INTERNAL_CONFIG.ACCESS_TOKEN_COOKIE_NAME]; if (!token) { - throw errorUnauthorized(); + throw errorWithControl(errorUnauthorized(), false); } const tokenService = container.get(TokenService); @@ -67,7 +71,7 @@ export const tokenAndRoleValidator = (role: UserRole) => { try { payload = await tokenService.verifyToken(token); } catch (error) { - throw errorInvalidToken(); + throw errorWithControl(errorInvalidToken(), true); } const username = payload.sub; @@ -75,11 +79,11 @@ export const tokenAndRoleValidator = (role: UserRole) => { const user = username ? await userService.getUser(username) : null; if (!user) { - throw errorInvalidTokenSubject(); + throw errorWithControl(errorInvalidTokenSubject(), true); } if (user.role !== role) { - throw errorInsufficientPermissions(); + throw errorWithControl(errorInsufficientPermissions(), false); } req.session = req.session || {}; @@ -101,7 +105,7 @@ const validateTokenAndSetSession = async (req: Request, cookieName: string) => { const token = req.cookies[cookieName]; if (!token) { - throw errorUnauthorized(); + throw errorWithControl(errorUnauthorized(), false); } const tokenService = container.get(TokenService); @@ -114,7 +118,7 @@ const validateTokenAndSetSession = async (req: Request, cookieName: string) => { req.session.tokenClaims = payload; req.session.user = user; } catch (error) { - throw errorInvalidToken(); + throw errorWithControl(errorInvalidToken(), true); } }; @@ -123,11 +127,11 @@ export const apiKeyValidator = async (req: Request) => { const apiKey = req.headers[INTERNAL_CONFIG.API_KEY_HEADER]; if (!apiKey) { - throw errorUnauthorized(); + throw errorWithControl(errorUnauthorized(), false); } if (apiKey !== MEET_API_KEY) { - throw errorInvalidApiKey(); + throw errorWithControl(errorInvalidApiKey(), true); } const apiUser = { @@ -192,3 +196,21 @@ export const withLoginLimiter = (req: Request, res: Response, next: NextFunction return loginLimiter(req, res, next); }; + +// OpenViduMeetError with control to stop checking other validators +interface ErrorWithControl { + error: OpenViduMeetError; + stopValidation: boolean; +} + +const errorWithControl = (error: OpenViduMeetError, stopValidation: boolean): ErrorWithControl => { + const errorWithControl: ErrorWithControl = { + error, + stopValidation + }; + return errorWithControl; +}; + +const isErrorWithControl = (error: unknown): error is ErrorWithControl => { + return typeof error === 'object' && error !== null && 'error' in error && 'stopValidation' in error; +};