Value set on the request object in one handler function is missing(undefined) on the next route call

Viewed 189

I have a login route that if a user signs in successfully, it attaches the id of the user from the database to the req.session.user property of the request object:

router.route('/za/login')
.get(onlyGuest, (req, res) => {
  res.render('login', { layout: false });
})
.post(onlyGuest, async(req, res) => {
 try {
       const user = await User.findByCredentials(req.body.email, req.body.password);
       req.user = user;
       req.session.user = req.user._id;

       res.redirect('/');
   } catch (err) {
       console.log(err);
       res.status(400).render('login', {
           layout: false,
           message: {
           error: 'login failed!',
           email: req.body.email
           } 
       });
   }
});

After this property(req.session.user) has been set, a user is directed to the home route. But there is a middleware that allows access to a certain route upon authenticated, otherwise it redirects to another page. Here is the code for the middleware:

let regex = /^\/za(\/.*)?$/; /*a route prefixed with '/za', followed by zero or /anything_else*/
app.use(async (req, res, next) => {
    let url = req.originalUrl;

    if(!req.session.user && !regex.test(url)) {
        console.log('You are trying to access an authenticated route. Login first!');
        console.log(req.session.user);
        if(url === '/') {
            res.redirect('/za');
            return;
        }
        res.redirect('/za/login?forbidden');
        return;
    }

/*req.session.user property is true or has a value set*/
if (req.session.user) {
        try {
            const user = await User.findById(req.session.user);
            if(!user) {
                return res.redirect('/za/login?forbidden');
            }
            req.user = user;
            return next();

        } catch (err) {
            console.log(err);
            return res.render('errors/500');
        }
    }
});

After successfully logging in via the login route(providing the correct credentials), i wonder why the request.session.user is still undefined and therefore redirecting me to a page accessible by unauthenticated users. I have a feeling that i am missing the timing of order of execution. But this is just a feeling.Actually i don't know where i may have errored.

1 Answers

Short answer: You have to set the session or token or whatever you use for authentication on the client side.

Long answer: You have the req object and the res object available in your handlers. The req object is the request and data sent by the client (web browser). The res object is what is sent back to the client as a response. As soon, as you call any terminating method on the res object like res.render or res.send, the handling of the specific client request is done and the linked objects are "thrown away". Therefore, setting any value on the req object does never affect the client, as the req object never gets sent back to the client. Modifying the req object would only be of use if you want to access some values on the req object in another middleware dealing with the same request.

So, you have to send the user id in the response object back to the client upon successful authentication and on the client side, take this id and set it e.g. as permanent header to be sent along with every request sent from the client from now on.

Hint: This way of authentication is not very secure. Usually, you would generate a token - e.g. a JSON Web Token (JWT-token) on the server-side upon successful authentication, send this token to the client and verify this token on each subsequent request.

Hint 2: Search (on Stackoverflow) for e.g. "node.js authentication" to get more input.

Related