114

I've been reading passport.js info and samples for two days, but I'm not sure after that I did all the process of authenticating.

How do I know if I'm logged in, for example, I'll have a navigation bar with a login or logout button, is there some variable like code below?

if (login)
   <button>logout</button>
else 
   <button>login</button>
Fabian Fagerholm
  • 4,099
  • 1
  • 35
  • 45
RMontes13
  • 2,138
  • 3
  • 16
  • 23

6 Answers6

232

If user is logged in, passport.js will create user object in req for every request in express.js, which you can check for existence in any middleware:

if (req.user) {
    // logged in
} else {
    // not logged in
}

You can create simple express.js middleware for that, that will check if user is logged in, and if not - will redirect to /login page:

function loggedIn(req, res, next) {
    if (req.user) {
        next();
    } else {
        res.redirect('/login');
    }
}

And use it:

app.get('/orders', loggedIn, function(req, res, next) {
    // req.user - will exist
    // load user orders and render them
});
moka
  • 22,846
  • 4
  • 51
  • 67
  • It is global? Can I access it in all project after login? – RMontes13 Sep 11 '13 at 11:33
  • If you include passport.js middleware in the configure of express.js, then it will affect every request (in all routes). – moka Sep 11 '13 at 12:40
  • 3
    its not global its just on the request object. – supernova Sep 11 '13 at 12:56
  • 1
    In 98.8% of web development with express.js and passport.js you will deal with requests (app.get, app.post, etc), so talking about using passport.js outside of it is little bit pointless. Yes it is only within express route middleware handlers like `app.get`, `app.post` etc. If you need different functionality, then you should explain it in details in your question as well as what you are trying to achieve. – moka Sep 11 '13 at 13:03
  • No, I only needed to know if it is global or not, perfect thank you very much to both. – RMontes13 Sep 11 '13 at 14:40
  • This would only work for a traditional app, not a javascript one - you would need an endpoint to validate the users session cookie – Dominic May 10 '14 at 15:36
  • @DominicTobias 3rd code example shows how this code is used as middleware for endpoint in express.js, could you please clarify what did you meant? – moka May 12 '14 at 12:00
  • 3
    I found that if I don't provide router.get() with any middleware to check for authentication, as in "router.get('/', my_controller.index)", then passport is never consulted and req.user will always be undefined. This is frustrating because I want to allow any visitor to call an API, but tailor the content of the response depending on who is requesting. – Lawrence I. Siden Nov 25 '14 at 23:11
  • Have one middleware that will decide what behaviour you want and will call another middleware based on your dynamic content routing. Although it is not good to change url semantics. – moka Nov 26 '14 at 10:09
  • This isn't working for me, it req is not accessible in the routes for me. – DatBassie Nov 30 '14 at 15:57
  • Then your definition of arguments in middleware for routes is different. – moka Dec 01 '14 at 00:07
  • What do you mean by that? It should all be correct, I've checked multiple times. I've asked a question about it on SO, if that's more convenient to discuss the issue. – DatBassie Dec 03 '14 at 15:46
  • Without code, there is not much can be done, please share simple example to replicate the issue. – moka Dec 03 '14 at 18:37
  • I have more info here: http://stackoverflow.com/questions/27216731/unable-to-access-req-user-with-passport-js-and-express-4. I can give you the info to a test account if needed. – DatBassie Dec 03 '14 at 19:17
  • 4
    Can someone explain how this is not exploitable? That check simply looks to see if their is a user object in the request. Where is the session validation? – Michael Ramos Jun 07 '16 at 11:29
  • @Michael-R I put the user in req.session so I can control the lifetime by expiration and the secret key for security. I also check the user.id in session against my user database if the page is sensitive and not just rely on user object existence. – Maziyar Aug 04 '16 at 10:22
  • Even after successful authentication `req.user` is undefined on the next request. Could you help answer this question http://stackoverflow.com/questions/42842171/detect-if-the-user-was-authenticated-before – Suhail Gupta Mar 17 '17 at 02:43
  • 1
    @rambossa The user can't directly set `req.user` in any way. All of the request data is in things like `req.body`, `req.query`, and `req.params` -- i.e. in subobjects. There's no way, barring compromised middleware, for a request to directly set the user, and at that point you've already lost. – Nic Aug 08 '18 at 17:59
52

If you would like to use it in your templates as your code sample seems to indicate you can create some middleware such as this:

app.use(function (req, res, next) {
  res.locals.login = req.isAuthenticated();
  next();
});

Place that code somewhere after you have setup passport.

And then use it in your template (swig example)

{% if login %}
<button>logout</button>
{% else %} 
<button>login</button>
{% endif %}
cyberwombat
  • 38,105
  • 35
  • 175
  • 251
  • For some reason the above middleware was giving me an issue with user being undefined in my template. I had to re-supply the user object to the view to fix it like so: `app.use(function(req,res,next){` `res.locals.login = req.isAuthenticated();` `res.locals.user = req.user;` `next();` `});` – Tebbers Mar 26 '16 at 18:50
  • 1
    Even after successful authentication, `isAuthenticated` gives false in the next request. Could you help answer this question http://stackoverflow.com/questions/42842171/detect-if-the-user-was-authenticated-before – Suhail Gupta Mar 17 '17 at 02:42
5

It is not explicitly documented but there is a isAuthenticated() method which is inserted into req by passport.
Can be used as follows,

req.isAuthenticated() // returns true if auth, false if not

// auth.js
module.exports = {
  ensureAuthenticated: (req, res, next) => {
    if (req.isAuthenticated()) {
      return next()
    }
    res.redirect('/login') // if not auth
  },

  forwardAuthenticated: (req, res, next) => {
    if (!req.isAuthenticated()) {
      return next()
    }
    res.redirect('/dashboard');  // if auth    
  }
}

// app.js
app.get('/dashboard', ensureAuthenticated, (req, res) => res.render('dashboard'))
app.get('/login', forwardAuthenticated, (req, res) => res.render('login'))
app.get('/register', forwardAuthenticated, (req, res) => res.render('register'))
Hasan Sefa Ozalp
  • 6,353
  • 5
  • 34
  • 45
2

I was searching such solution and came across this page. Question is how to check login status on client side.

After logging I hide the Login button and show the logout button. On page refresh I again see the login button instead of logout button. The only solution is to save an item in sessionStorage if you are using session (and localStorage if you are using JWT). Delete this item when you logout. Then in every page load check this sessionStorage item and do accordingly.

if (sessionStorage.getItem('status')) {
    $("#btnlogout").show();
    $("#btnlogin").hide();
// or what ever you want to do
} else {
    $("#btnlogout").hide();
    $("#btnlogin").show();
}



function Login() {
            var data = {
                username: $("#myModal #usr").val(),
                password: $("#myModal #pw").val()

            };
            $.ajax({
                type: 'POST',
                url: '/login',
                contentType: 'application/JSON; charset=utf-8',
                data: JSON.stringify(data),
                success: funcSuccess,
                error: funcFail
            });
            function funcSuccess(res) {
                sessionStorage.setItem('status', 'loggedIn');

                $("#btnlogout").show();
                $("#btnlogin").hide();
            }
            function funcFail() { $("#pp").text('Login Failed'); };
        };

function Logout() {
    $.ajax({
        type: 'GET',
        url: '/logout',
        contentType: 'application/JSON; charset=utf-8',
        success: funcSuccess,
        error: funcFail,
    });
    function funcSuccess(res) {
        $("#btnlogout").hide();
        $("#btnlogin").show();
        sessionStorage.removeItem("status");
    };
    function funcFail() { alert('Login method Failed'); };
}; 
Zeni
  • 947
  • 1
  • 12
  • 24
2

use below code inside app.get() or router.get()

router.get('/edit/:id', (req, res)=>{
  if(req.isAuthenticated()){
     if(req.isAuthenticated()){
      //

      }
  else{
   res.redirect('/users/login');//your particular login routes
     }
});
Pankaj
  • 169
  • 2
  • 11
1

Good question, I had some issues while trying to implement something like this, when there is a un-authenticated request the handlebars skips the if block if the res.locals variable returns a falsy value. To solve this issue you need to setup a middleware in your app.js file to make the req.user available globally in your app Like so..

app.use(function (req, res, next) {
res.locals.login = req.user;
next();

});

In your header file you can do this check for authenticated user and display according content like so..

                {{#if login }}
                    <li><a href="#">User Account</a></li>
                    <li role="separator" class="divider"></li>
                    <li><a href="#">Logout</a></li>
                {{/if}}
                {{#unless login}}
                    <li><a href="#">Sign up</a></li>
                    <li><a href="#">Sign in</a></li>
                {{/unless}}