0

I am using express, node and handlebars to create a web app with passport being the authentication library. I am trying to set a variable in res.locals to render a navigation bar based on user state. The issue I am having is that when setting res.locals.isUser or res.locals.isAdmin using middleware, the variable does not seem to be passed around or at least it does not appear to be. Code is below (watered down for simplicity).

app.js

var app = require('express)();

app.use(function(req, res, next){
   res.locals.isUser = false;
   if(req.user && req.user.role === 'user'){
      res.locals.isUser = true;
   }

   next();
});

// Admin logic same as above but isAdmin instead of isUser

var passport =  require('./lib/auth/passport.js')(app);

require('./routes.js');

layout.handlebars

 {{#if isUser}}
     {{> userNav}}
 {{else if isAdmin}}
     {{> adminNav}}
 {{else}}
     <nav>
         // Render normal nav
     </nav>
 {{/if}}

 {{{body}}}

What is happening is when the user logs in the nav bar changes, but when the user logs out, sometimes, the nav bar stays as {{> userNav}}. Refreshing the page seems to fix the issue. Furthermore, once the user is logged out, and the nav bar stays as {{> userNav}}, clicking on a link in the nav bar sends me to a 404. This assured me that the passport logout mechanism is working fine. I placed a console.log('...') in the middleware just to see if it is being called on every request, and sure enough it is. I moved the middleware into the routes.js file, issue still persists. I have racked my brain and have no idea why this is the case. It seemed to work fine a few days ago, or at least I never noticed this issue before. Am I doing something wrong? Any help would be greatly appreciated. Thanks all!

Using...

  • Express
  • Express-Handlebars
  • Passport
  • MongoDB

Some related posts...

Why is PassportJS in Node not removing session on logout

Express+jade: local variable not available in view

Community
  • 1
  • 1
cyclops
  • 1
  • 3
  • 1
    Can you show the route you're using to log out a user? – robertklep Sep 08 '16 at 06:20
  • @robertklep - `app.get('/logout', function(req, res) {req.logout(); res.redirect(303, '/'); });` – cyclops Sep 08 '16 at 06:45
  • Can you check if redirecting to `/?_=SOME_RANDOM_VALUE` fixes the issue? Perhaps your browser is caching `/`? – robertklep Sep 08 '16 at 07:31
  • @robertklep No that did not solve it. But 303 should tell the browser not to cache, no? – cyclops Sep 08 '16 at 08:02
  • I think the 303 response itself shouldn't be cached, but I don't think that it means that the page that gets redirected _to_ can't be cached. Have you tried destroying the session before the redirect? `req.session.destroy(function() { res.redirect(...) })` – robertklep Sep 08 '16 at 08:04
  • Yes I did. That was one of the first things I tried with no ava. I also tried the logOut() from some other SO answer, natha. Hmmmm... weird. I just started noticing this so I have no idea if this is something due to code I have recently added or just something that I have missed this whole time. – cyclops Sep 08 '16 at 08:07
  • What do you think of the solution abdulbarik is suggesting? Also I just re-read you suggestion about destroy, not in that manner. I did `req.session.destroy(); req.logout();` – cyclops Sep 08 '16 at 08:08
  • I second your comments to it: it shouldn't be necessary. To be clear, when you hit `/` after logging out, inside the `/` handler, what are the values of `res.locals.isUser` and `res.locals.isAdmin`? Depending on the session store you use, `destroy` may be async, hence the callback. – robertklep Sep 08 '16 at 08:11
  • `undefined` - I am using MongoDB as my session store – cyclops Sep 08 '16 at 08:29
  • `undefined` is unexpected, as you're explicitly initializing it to `false` in your middleware. Not that I would expect it to matter, but still. – robertklep Sep 08 '16 at 08:31
  • Ya sorry about that. I just rechecked. It is `false` for both. My eyes are going bonkers. Been on this for better part of the night. And then I hit `res.render('home', mainVM.home());` – cyclops Sep 08 '16 at 08:35
  • @robertklep I inserted a bunch of `console.log`'s, one in the middleware, one in route after logout, one in the viewModel, and I also made a `{{showMe}}` helper ie. `{{showMe isUser}}` which I placed in the layout prior to nav bar. It would seem 9/10 times it behaves as expected. Any other thoughts on what can be going on here? – cyclops Sep 08 '16 at 13:13
  • Does the issue occur with all routes, or just specific ones? Also, you're not caching anything, I assume? – robertklep Sep 08 '16 at 13:15
  • As for as I can tell, just login and logout, for both, user and admin. If I click a link to another page, then it loads the next page and fixes the issue. Not using AJAX. I am in development mode so express by default does not cache views. My concern then becomes, when it does cache views in production mode, what other issues are going to crop up that never occurred while in development. – cyclops Sep 08 '16 at 13:19
  • View cache should only cache the compiled template, not the rendered template, but it's worthwhile to check at some point :) – robertklep Sep 08 '16 at 13:21
  • Well I just ran into another issue. When I use the admin login mechanism, the `{{showMe isAdmin}}` logged `false` and took me to a `404` page. Typically the admin dashboard needs authentication, while the user landing is the same landing as an unauthenticated session would use. Refreshing the page while on the `404` took me to the dashboard. Figured this might help with your assessment. How do I check? `app.get('view chache');`? – cyclops Sep 08 '16 at 13:25
  • `app.get('view cache')` – robertklep Sep 08 '16 at 13:34
  • I did `console.log(app.get('view cache'));` within the middleware and it logged `undefined`. – cyclops Sep 08 '16 at 13:35

1 Answers1

0

As I seeing when you are logged out, you are not sending any value for isUser That's why your View is not updated while your session is closed by passport but when you refresh the page then you get the false value of isUser.

You need to pass isUser value while redirecting after logout.

You need to do something like this

res.redirect(303, '/?isuser='+false)

And after getting response from logout update the isuser value in view

Hope this will solve your problem

abdulbarik
  • 6,101
  • 5
  • 38
  • 59
  • If the the middleware is getting called on every request, shouldn't setting `res.locals.isUser = false;` take care of that? And why does it work sometimes and not all the time? – cyclops Sep 08 '16 at 07:18
  • what you want the value of `isuser` after logout route called?And this value will be change when you logout the user in logout block so your `middleware` will work as it is – abdulbarik Sep 08 '16 at 07:27
  • Even setting it to 'false' in logout block prior to 'req.logout()' does not seem to work. Furthermore, this also happens when logging in. After logging in, it keeps the state to the ``. The middleware gets executed on the `res.redirect`. Logging to console shows that it is in fact being called. Using your solution would work but feels like it is circumventing the whole middleware idea. I would also have to append `isAdmin=false` and do something with that. What happens if I have 5 user roles? Then I would keep appending query parameters? – cyclops Sep 08 '16 at 07:42
  • In my view you should use a single variable to identify the user is logout since doesn't matter you have 10 user roles but if user loging out then it must be logged out from app. no matter he is admin or user – abdulbarik Sep 08 '16 at 07:45
  • Based on different user roles, different navigation bars are made available. How do you propose that should be handled given what you are saying with regards to using one variable? – cyclops Sep 08 '16 at 07:53
  • Also doing what you are suggesting, exposes implementation details IMHO. – cyclops Sep 08 '16 at 07:57
  • I suggest that you can use single variable in back-end side to send respose after getting logout and and update this value in `isUser`,`isAdmin` etc on view side – abdulbarik Sep 08 '16 at 08:49
  • Ok sure that solves the logout issue, there is still the issue when you try to log in that it keeps the normal nav which is not related to any role, although you are logged in as a role. How would I fix that? Refreshing then does the same thing, whereby it gets the value which at that point it is `true`. – cyclops Sep 08 '16 at 09:00
  • After successfully logged in I think you send `true` value, you can updated that value in view avoids frozen view. – abdulbarik Sep 08 '16 at 09:04
  • You can accept answer if your log out issue is resolved :) – abdulbarik Sep 08 '16 at 09:23
  • I want to wait a little bit longer to see if there are other solutions. The middleware should be working as expected and it is not. If this turns out to be the only solution, I will gladly accept it in due course. – cyclops Sep 08 '16 at 13:16