Reputation: 675
When I add the err at the beginning of the function signature like so: function middleware(err, req, res, next)
is causing Express to skip the function entirely:
Route:
const express = require('express')
const router = express.Router()
const { requireSignin, authMiddleware, randomMiddleware } = require('../controllers/auth')
const { read, publicProfile, update, photo } = require('../controllers/user');
router.get('/user/profile', requireSignin, randomMiddleware, authMiddleware, read);
requireSignin:
exports.requireSignin = expressJwt({
secret: process.env.JWT_SECRET
});
randomMiddleware (used to test if middleware is ran):
exports.randomMiddleware = (req, res, next) => {
console.log('coming from ranomd middleware')
console.log('');
console.log(req.user);
console.log('');
next();
}
authMiddleware (where the problem is occuring):
exports.authMiddleware = (err, req, res, next) => {
console.log(err);
console.log('made it to authMiddleware')
if(err.name === 'UnauthorizedError' || !req.user) {
return res.status(401).json({ error: 'Session has expired. Please sign in again' });
}
const authUserId = req.user._id;
User.findById(authUserId).exec((err, user) => {
if (err || !user) {
return res.status(400).json({
error: 'User not fond'
})
}
req.profile = user;
next();
});
}
read:
exports.read = (req, res) => {
req.profile.hashed_password = undefined;
return res.json(req.profile);
};
Callstack console error:
coming from ranomd middleware
{ _id: '5ef8c16036951836582ed80d', iat: 1596064684, exp: 1596151084 }
GET /api/user/profile 500 17.619 ms - 1872
TypeError: Cannot set property 'hashed_password' of undefined
at exports.read (C:\Users\ncg user\Desktop\mern-course-ryan_dhungel\seoblog\backend\controllers\user.js:11:33)
at Layer.handle [as handle_request] (C:\Users\ncg user\Desktop\mern-course-ryan_dhungel\seoblog\backend\node_modules\express\lib\router\layer.js:95:5)
at next (C:\Users\ncg user\Desktop\mern-course-ryan_dhungel\seoblog\backend\node_modules\express\lib\router\route.js:137:13)
at Layer.handle [as handle_request] (C:\Users\ncg user\Desktop\mern-course-ryan_dhungel\seoblog\backend\node_modules\express\lib\router\layer.js:91:12)
at next (C:\Users\ncg user\Desktop\mern-course-ryan_dhungel\seoblog\backend\node_modules\express\lib\router\route.js:137:13)
at exports.randomMiddleware (C:\Users\ncg user\Desktop\mern-course-ryan_dhungel\seoblog\backend\controllers\auth.js:88:9)
at Layer.handle [as handle_request] (C:\Users\ncg user\Desktop\mern-course-ryan_dhungel\seoblog\backend\node_modules\express\lib\router\layer.js:95:5)
at next (C:\Users\ncg user\Desktop\mern-course-ryan_dhungel\seoblog\backend\node_modules\express\lib\router\route.js:137:13)
at C:\Users\ncg user\Desktop\mern-course-ryan_dhungel\seoblog\backend\node_modules\express-jwt\lib\index.js:128:7
at C:\Users\ncg user\Desktop\mern-course-ryan_dhungel\seoblog\backend\node_modules\async\lib\async.js:52:16
at Immediate.<anonymous> (C:\Users\ncg user\Desktop\mern-course-ryan_dhungel\seoblog\backend\node_modules\async\lib\async.js:1206:34)
at processImmediate (internal/timers.js:439:21)
As you can see, the "coming from random middleware" and the req.user are console logged, confirming that randomMiddleware ran, but there is not even a console.log of "made it to authMiddleware".
Even more confusing to me is that the route doesn't stop getting processed. The route is just simply skipping the authMiddleware function then getting to the read function. That is the reason why the TypeError
occurs. In the authMiddleware function, I am setting req.profile = user
which would contain the hashed_password
property.
I've already tested removing the err from the authMiddleware as so: exports.authMiddleware = (req, res, next)
and when I do that it runs.
Why is adding the err
at the beginning of the middleware function causing Express to skip it entirely?
Also to add, if there actually is an err
, the middleware will run! I tested my jwt session by setting it to one milliesecond. When the jwt token expires, the authMiddleware
runs, there is an UnauthorizedError and the response is processed. When I set the token back to expiring in a day, the middleware stopped running. Does this have something to do with the fact that if there is no err
, a middleware that includes err
won't even run?
Upvotes: 0
Views: 108
Reputation: 675
Well, I answered my own question almost immediately after typing up the question, so I figured I would post it anyways. I was right
Does this have something to do with the fact that if there is no err, a middleware that includes err won't even run?
That is exactly what is happening. I don't know why, so you'll have to look elsewhere for a why, but if there is no express handled error and you include the first argument (typically called err
, but you can call it whatever) like so: function middleware(err, req, res, next)
, express will skip the function entirely.
What this means is I had to separate out my error handler into it's own middleware entirely. Retrieving data and handling an Express genereated error should not be combined. This is the key takeaway. This is all stems from an earlier issue I had with handling a jwt expired token. I could only retrieve the expired jwt token error from the backend by using the err
object at the beginning of the middleware.
Here is my solution:
authMiddleware:
exports.authMiddleware = (err, req, res, next) => {
console.log(err);
console.log('made it to authMiddleware')
if(err.name === 'UnauthorizedError' || !req.user) {
return res.status(401).json({ error: 'Session has expired. Please sign in again' });
}
}
getUserAfterAuth (new function):
exports.getUserAfterAuth = (req, res, next) => {
const authUserId = req.user._id;
User.findById(authUserId).exec((err, user) => {
if (err || !user) {
return res.status(400).json({
error: 'User not fond'
})
}
req.profile = user;
next();
});
}
and finally, the route:
router.get('/user/profile', requireSignin, authMiddleware, getUserAfterAuth, read);
Error handling middleware gets skipped if there is no error object
Upvotes: 1