Node js passport's req.isAuthenticated returns always false

B.G.

I know there are lots of questions similar to this, I checked the questions asked before and none of the answers did solve my problem. I m developing a simple authentication node.js app for now (the front end is react-native, the database is MongoDB). I m using following packages for this:

  • passport-local-mongoose
  • express-session
  • passport-local
  • passport

So here is the app.js

var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
var cors = require('cors');
var passport = require('passport');
var user = require('./models/user');
var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
var cookieParser = require('cookie-parser')
var app = express();
app.use(cookieParser('keyboard cat'));


var corsOptions = {
  origin: '*',
  credentials: true };
app.use(cors(corsOptions))



app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(express.static(path.join(__dirname, 'public')));


app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');

//auth settings
app.use(require("express-session")({
  secret: 'keyboard cat',
  resave: false,
  saveUninitialized: false,
}));

app.use(passport.initialize());
app.use(passport.session());

passport.use(user.createStrategy());
passport.serializeUser(user.serializeUser());
passport.deserializeUser(user.deserializeUser());



app.use('/', indexRouter);
app.use('/users', usersRouter);

// catch 404 and forward to error handler
app.use(function(req, res, next) {
  next(createError(404));
});

// error handler
app.use(function(err, req, res, next) {
  // set locals, only providing error in development
  res.locals.message = err.message;
  res.locals.error = req.app.get('env') === 'development' ? err : {};

  // render the error page
  res.status(err.status || 500);
  res.render('error');
});

module.exports = app;

Here is the user model:

var mongoose=require('mongoose');
var passportLocalMongoose = require('passport-local-mongoose');

var userShema = new mongoose.Schema({
    username : String,
    password : String
})

userShema.plugin(passportLocalMongoose);


var user= mongoose.model("User",userShema);

module.exports = user;    
     

Here is my route file

var express = require('express');
var router = express.Router();
var user= require("../models/user");
const passport = require('passport');
var isLoggedIn =require('../session');
/* GET home page. */
router.get('/', function(req, res, next) {
 
  res.render('index', { title: 'Express' });
});

router.post('/login', function(req, res, next) {
  passport.authenticate('local' ,function(err, user, info) {
    if (err) { return next(err); }
    if (!user) { return res.send("-1"); }
    
    req.logIn(user, function(err) {

      if (err) { return next(err); }
      req.session.save(() => res.send("Başarılı"));
    });
  })(req, res, next);
});


router.post('/signUp', async function(req, res, next) {
  try{

    console.log('registering user');
    user.register(new user({username: req.body.username}), req.body.password, function(err) {
      if (err) {
        console.log('error while user register!', err);
        return next(err);
      }
      console.log('user registered!');
      res.redirect('/');
    });
 
  }
  catch(e){
    console.log(e);
    res.status(503).send("-1")
  }
 
 
  
});

router.get('/logOut', function(req,res,next){
  req.logOut();
  res.send("1");
})

router.get('/home',isLoggedIn,function(req,res,next){
  res.send("Success");
})

module.exports = router;

And finally here is the session.js

const passport = require('passport');
var isLoggedIn =(req,res,next) =>{
    if(req.isAuthenticated()){
        return next();
    }
    res.status(403).send("Something went wrong")
}


module.exports = isLoggedIn;

The problem is here, after authentication (which works fine), React native goes to the home page and I wanna take some information as the user logged in.For this i m using isLoggedIn function which uses req.isAuthenticated() and returns always false.

The most common answers that I've tried and didn't work are

  1. Make sure session-passport.init-passport.session lines in the correct order (which already is in my app)
  2. Issue related clients get-post call (in my react-native app -> axios.post(BaseURL+url,data,{ withCredentials: true }) , also in server app -> var corsOptions = { origin: '*', credentials: true }; app.use(cors(corsOptions)))
  3. Some say if you are working with https you have to set {secure:true} ( which I m not)
  4. One said "After authenticating, passport.js requires you to reroute/redirect"otherwise the session is not created, but lots of people also having problems with redirect. I did try it didn't solve the issue.
  5. One said don't use express-session, use client-sessions (i did try that, didn't work)
  6. Some people suggest to change serialize and deserialize functions ( i tried other codes that I found on the internet, none of them worked) but the problem is my deserialize function never runs(i think this function works after isAuthenticated() and checks the user info on the req but my req does not have that info. Basically, I can log in to the app but it doesn't save my session in request.)
  7. A person suggests that " express-session tries to delay the redirect, but some browsers don't wait for the whole response before directing. So you need to manually save before redirecting." and it solved almost everyone's problem but me. (In my code as you can see req.session.save(() => res.send("Başarılı")); )
  8. Also, another person said putting delay also works the issue ( i tried, it didn't)

So if anybody has another solution besides these, please share. I am open to all suggestions.

B.G.

I kinda solved the problem by changing the server code a bit. I had to take a break since last time I was working related to this project so there are some parts I don't exactly remember why I had to change but, at the end of the day, code works.

I think something was wrong between express-session and passport so that session created but no passport object in req.session.

In App.js, i have to add some new libraries:

const { v4: uuidv4 } = require('uuid');
const FileStore = require('session-file-store')(session);
const LocalStrategy = require('passport-local').Strategy;
const bodyParser = require("body-parser");

I used some default code provided by express-session and passport before and they didn't work. So I started to change the session first a bit. To do that I need to import a library to create random session-id (uuid), also I started to save sessions in a file from the server-side. I guess I didn't have to import any library to save data, I could hold all info in the database but I prefer to move along with using session-file-store library. I also added the passport-local library to this file (it was used on the user model only before). Lastly, I had to add body-parser library to parse the response. I have to indicate that I was using express.urlencoded() function before and it was working fine for my routing. I didn't have to use another library to parse the request body. As far as I remember when I add some middleware for the session, this express.urlencoded didn't work, and I was like let's try other one and put body-parser library in my code and it just work fine.

app.use(bodyParser.urlencoded({ extended: false })); 
app.use(express.urlencoded({ extended: false }))

I don't know the exact difference between these 2 lines. But I know that they work differently and it seems body-parser library works better than express parser.

I changed the settings of my session

app.use(session({
  genid: (req) => {
    console.log('Inside the session middleware')
    console.log(req.sessionID)
    return uuidv4(); // use UUIDs for session IDs
  },
  store: new FileStore(),
  secret: 'keyboard cat',
  resave: false,
  saveUninitialized: true
}))

So basically I create id with session object and I saved it to request. This code works before my router so every request has a sessionId. I think express-session checks if a request has sessionId and is it saved to the server-side before calling genId function which means that this function is called only if the request has no session-id or the session id is not stored in the server. Browsers save your session Id and use the same id for each request. The sessions saved in the server as objects hold the cookie info for the session. Passport.js puts your userId or username into the cookie (if you are logged in of course) so we can separate if that cookie is related to an account or not.

I was using the default strategy method coming from passport-local, but I re-write it. LocalStrategy function is the place that performs authentication when a request sent to '..../login'.In login (post) function, you use passport.authenticate('local' ,function(err, user, info) {} -> Here local indicates that use the local strategy that u decided in app.js

passport.use(new LocalStrategy(
  function(username, password, done) {
    console.log("passport localStrategy",username,password)
    user.findOne({ username: username }, function (err, user) {
       user.authenticate(password).then(res => {
        if (err) { return done(err); }
        if (!user) { return done(null, false); }
        if (!res.user) { return done(null, false); }
        console.log('Local strategy works fine')
        return done(null, user);
       })
    
    });
  }
));

//takes user and save it to  session file store
//saves the user id in the request object as request.session.passport
//and adds request object as request.user.
passport.serializeUser(function(user, done) {
  console.log('Inside serializeUser callback. User id is save to the session file store here')
  done(null, user); 
});

passport.deserializeUser(function(user, done) {
  console.log('Inside De-serializeUser callback.')   
    done(null,user)
});

I don't recommend you to serialize the only user.id if you re using MongoDB (at least don't do this until you re sure that other parts of your program work without error). I had some problems with deserializeUser with findById (my problems were related to using default objectIds that MongoDB created automatically) function. It wasn't giving any error but returned to 500 as a response. SerializeUser is called after login and put your info into the cookie. DeserializeUser is called if your request has the cookie that is saved on your server-side.

In Index.js (my router file)

 router.post('/login', function(req, res, next) {
  console.log("inside of the login",req.sessionID)

  //passport.authenticate with local parameter will call function that configured in passport.use(new strategyCalss)
  passport.authenticate('local' ,function(err, user, info) {
    console.log('Inside passport.authenticate() callback');
    console.log(`req.session.passport: ${JSON.stringify(req.session.passport)}`)
    console.log(`req.user: ${JSON.stringify(req.user)}`)
    if (err) { return next(err); }
    if (!user) { return res.send("-1"); }
    //req.login calls passport.serialize user
    req.login(user, function(err) {
      console.log('Inside req.login() callback')
      console.log(`req.session.passport: ${JSON.stringify(req.session.passport)}`)
      console.log(`req.user: ${JSON.stringify(req.user)}`)
      if (err) { return next(err); }
      return res.send('You were authenticated & logged in!\n');
    });
  })(req, res, next);
});

I changed my login function like this. So it actually worked fine when you changed session settings a bit. I even deleted the session.save() part because the session was even created before.My problem was that session data didn't save as object in the session so I tried to force to save it.

After all these changes, server-side works fine. I tested this code with the postman and it worked perfectly. However even though I send a cookie to the browser, the browser didn't save my cookie. There is something wrong related to the front-end or browser. However, this issue at the server side is resolved.

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

Passport isAuthenticated() always returns false?

Node.js, Vue.js and Passport.js. .isAuthenticated() always returns false? Axios headers possibly?

passport req.isAuthenticated() always returns fasle

req.isAuthenticated always returns false

passport's req.isAuthenticated always returning false, even when I hardcode done(null, true)

Passport isAuthenticated() always returns TRUE

Ionic + Passport isAuthenticated() returns false

Express-session + Passport + MongoDB - req.isAuthenticated() always return false after login

Passportjs req.isAuthenticated always shows false

How is req.isAuthenticated() in Passport JS implemented?

isAuthenticated always false using Javascript express and passport

req.session.passport and req.user blank , and req.isAuthenticated returns false after initial successful login using passport-facebook

Setting up passport for the first time. isAuthenticated() always returning false

Passport.js `isAuthenticated()` inconsistent behavior; false when it should be true

koa-passport w/ passport-steam: ctx.isAuthenticated() always false

isAuthenticated() always returns true

JS / JSX function always returns true even if it's false

Azure AD API returns System.Security.Principal.GenericIdentity.IsAuthenticated as false always

passport: req.isAuthenticated() is not a function and req.user is not being set by passport

Moment.js comparison always returns false

JS Checking return function with if, always returns false

Request.IsAuthenticated always returning false on Login

Passport.js error debug('dispatching %s %s', req.method, req.url);

Passport JWT : req.user is always Unauthorized

passport.js req.user is returning: 'Promise { false }' - How do I get the current sessions' username?

Passport.js & Express Session - req.user undefined causing .isAuthenticted() to return false

node js multer file upload not working. req.file and req.files always undefined

isAssignableFrom always returns false

Contains always returns false