'Why do i get 502 Bad Gateway error in my async express.js middleware?
I have a node API which is deployed and run as a Lambda function inside AWS.
// mthd
export const validateHeaderBearerToken = (req, res) => {
if (!req.headers.authorization || req.headers.authorization.split(' ').length !== 2
|| req.headers.authorization.split(' ')[0].trim() !== authConstants.BEARER_HEADER) {
res.status(403)
.send({ message: 'Invalid token' });
throw new AuthenticationException(authConstants.NO_VALID_TOKEN_IN_HEADER_ERROR);
}
return req.headers.authorization.split(' ')[1].trim();
};
and the controller
// controller
searchApiV1Controller.use('/search/', checkAuthentication, searchRouter);
the main service
// mainService
export const checkAuthentication = async (req, res, next) => {
const bearerToken = req.headers.authorization;
logger.info(`[${getCorrelationId(req)}] Authenticating the request`);
const token = validateHeaderBearerToken(bearerToken, res);
let application='liberty';
await checkAuthorize(application);
...
}
When I pass the empty bearer token inside the header, it should respond "Invalid token" message with 403 statuscode. But Since the main service(middleware) is an async method, the call responds with 502 Bad Gateway error due to the AuthenticationException. If we remove this exception it will respond correctly with 403. But the main service method will asynchronously runs through the other sub util methods inside checkAuthentication method. So we can't remove it. What may be the solution for this?
FYI: I don't face any problems while running locally.
Solution 1:[1]
When using middleware chains in express, it's typically better form to use the next()
function than throwing exceptions/errors. It makes them more composable and also follows the principle of not using exceptions for control flow. Exceptions are for truely exceptional cirumstances, not your standard operations.
If you pass a value to next()
it will assume it's an error and skip straight to your error handling middleware. You can also add values onto the res.locals
to pass it through middleware chains.
For example:
export const validateHeaderBearerToken = (req, res, next) => {
if (/* checks */) {
return next(AuthenticationException(authConstants.NO_VALID_TOKEN_IN_HEADER_ERROR));
}
res.locals.token = req.headers.authorization.split(' ')[1].trim();
};
Now because you're setting res.locals you don't need to call your validate function a in checkAuthentication
, you can use it as middleware, turning that function into something like:
export const checkAuthentication = async (req, res, next) => {
// Assume res.locals.token exists, otherwise we'll have early-exited the entire request.
const bearerToken = res.locals.token
let application='liberty';
let result = await checkAuthorize(application);
// Example logic...
if (result.is_authorised == false) {
return next(/*error*/)
}
}
Now you will never call checkAuthentication if validateHeaderBearerToken
fails to find a token. Your router setup will look like:
searchApiV1Controller.use('/search/', validateHeaderBearerToken, checkAuthentication, searchRouter);
Further reading on error handling in express: http://expressjs.com/en/guide/error-handling.html
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Elliot Blackburn |