req.isAuthenticated returns true only on '/login'

req.isAuthenticated returns true only on '/login'
0

Hello all!

I’m messing around with the authentication/passport projects and noticed that req.isAuthenticated only ever returns true when used in the ‘/login’ endpoints. This makes the ‘/profile’ redirect challenge 100% useless. Right now it’s always redirecting, regardless of if a user has been logged in or not.

My Project URL

https://krisb-fcc-information-advanced.glitch.me/

** NOTE: ** If you’d like to run some independent tests, you can use the following user information:

user: test-user
password: password

My Project Code URL

My Code

Summary

"use strict";

const express = require("express");
const fccTesting = require("./freeCodeCamp/fcctesting.js");
const pug = require("pug");
const session = require("express-session");
const passport = require('passport');
const app = express();
const bcrypt = require('bcrypt');
const mongoose = require("mongoose");
const mongodb = require("mongodb");
const ObjectID = mongodb.ObjectID;
// const MongoClient = mongodb.MongoClient;
// const Client = new MongoClient(process.env.DATABASE,{useUnifiedTopology: true, useNewUrlParser:true});
const LocalStrategy = require("passport-local");
let API = require("./api/api");
let makeNewUser = API.makeNewUser;
let fs = require("fs")
let dir = process.cwd();


app.set('view engine', 'pug');

app.use(session({
  secret: process.env.SESSION_SECRET,
  resave: true,
  saveUninitialized: true,
}));

app.use(passport.initialize());

app.use(passport.session());

fccTesting(app); //For FCC testing purposes
app.use("/public", express.static(process.cwd() + "/public"));
app.use(express.json());
app.use(express.urlencoded({ extended: true }));



function ensureAuthenticated(req, res, next) {
  console.log(req.isAuthenticated())
  if (req.isAuthenticated()) {
    return next();
  } else {
  res.redirect('/');
  }
};

// app.use((req, res)=>{
//   req.session.save()
// })

mongoose.connect(process.env.DATABASE, {useNewUrlParser:true, useUnifiedTopology:true}, async (err, db)=>{
  
  if(err) console.error(err);
  
  else {
      console.log("Connected to database")
//     let db = Client.db('Advanced-Node-And-Express');
//     /* START SERVER */
    
    
    /* SERIALIZATION */
    passport.serializeUser((user, done) => {
      done(null, user._id);
    });

    /* DESERIALIZATION */
    passport.deserializeUser((id, done) => {
      db.collection('users').findOne(
        {_id: new ObjectID(id)},
          (err, doc) => {
            done(null, null);
          }
      );
    });
    
    /*STRATEGY*/
    passport.use(new LocalStrategy(
      function(username,password,done){
        db.collection('users').findOne({username:username}, function(err, user){
          console.log(`User has attempted to login`);
          
          if(err) {
            console.log("Error");
            return done(err)
          }
          
          if(!user) {
            console.log("No username")
            return done(null, false);
          }
          
           if(!password) {
            console.log("password")
            return done(null, false);
          }
          
          else bcrypt.compare(password, user.password, (err, res)=>{
            if(res) {
              console.log("User authenticated")
              return done(null, user);
            }
            else  { 
              console.log("Incorrect password");
              return done(null, false)
            };
          }) ;
        });
      }));
    
    
    app
      .route("/")
      .get((req, res) => {
      res.render(dir + "/views/pug/index", {title: 'Hello', message: 'Please login', showRegistration:true, showLogin:true});
    });
    
    
    app
      .route('/login')
      .post(passport.authenticate('local', { failureRedirect: '/', successRedirect: "/profile" }));
    
    
    app
    .get('/profile', ensureAuthenticated, (req,res) => {
        
        console.log(req.isAuthenticated());
      
        if (req.isAuthenticated()) {
          res.render(process.cwd() + "/views/pug/profile")
        } else {
          res.redirect('/');
        }
      
   });
    
    app
    .route("/logout")
    .get((req, res)=>{
      req.logout();
      res.redirect('/')
    });
    
    
    app
    .route("/register")
    .get((req, res)=>{
        res.send("This endpoint is POST only");
      })
    .post(async (req, res)=>{
        res.json(await makeNewUser(req.body.username, req.body.password));
    });

    
    /*ALL ROUTES AND LOGIC BEFORE THIS LINE*/
    
    app.use((req, res, next) => {
      res.status(404)
        .render(`${dir}/views/pug/404`);
    }); 
    
    app.listen(process.env.PORT || 3000, ()=>console.log("Listening on port " + process.env.PORT));
    
    /*END ELSE*/
    
  }
})

app.route("/render").get((req, res) => {
  res.render(`${dir}/views/pug/${req.query.temp}`, req.query.options != undefined ? require(`${dir}/views/pug/options/${req.query.options}`).options : {});
});


Browser Info: “Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36”

Hello there,

I am going to move this into the #contributors sub-forum, as this is a useful place to discuss issues like this.

Are you saying that this allows req.Authenticated to return true:

app.route('/login')
   .post((req,res) => {
      if (req.isAuthenticated()) {
        res.render(process.cwd() + "/views/pug/profile")
      } else {
        res.redirect('/');
      }
    });

Great, thanks!

Also, yes, in that scenario it would return true. If it’s used in that specific endpoint, it works fine. On any other endpoint it returns false.

Weird!

Thanks in advance :smiley:

I found a workaround using cookies, but obviously this isn’t an optimal solution. Any suggestions?

Workaround Code

//Login workaround

    app
      .route('/login')
      .post(passport.authenticate('local'), (req, res, next)=>{
          res.cookie("isAuthenticated", req.isAuthenticated());
          res.redirect("/profile")
    });

//Logout workaround
    app
    .route("/logout")
    .get((req, res)=>{
      res.cookie("isAuthenticated", false)
      req.logout();
      res.redirect('/')
    });

//Ensure Auth Middleware

function ensureAuthenticated(req, res, next) {
  if (req.cookies.isAuthenticated == "true") {
    return next();
  } else {
  res.redirect('/');
  }
};
    

Hi all

The problem was that my deserialization function was not configured correctly. I never passed the doc variable to the done function.

My code with error:

        passport.serializeUser((user, done) => {
          done(null, user._id);
        });

        passport.deserializeUser( (id, done) => {
            db.collection('users').findOne(
                {_id: new ObjectID(id)},
                (err, doc) => {
                    done(null, null); // this is the error...doc should be passed as the second arg
                }
            );
        });

Fixed code:



        passport.serializeUser((user, done) => {
          done(null, user._id);
        });

        passport.deserializeUser( (id, done) => {
            db.collection('users').findOne(
                {_id: new ObjectID(id)},
                (err, doc) => {
                    done(null, doc); // this is the fix
                }
            );
        });