1

Partially this error seem to be common in terms that req.Authenticated() is false but from what I have read it seems to affect all browsers according to the past post since they don't mention anything about being browser specific problem. So I have a heroku hosted web app, front end and back end are separate from each other.

Locally the problem does not exist regardless of browser but when moving to production then affects Chrome any chromium based browser but the ones that seem to not be affected are FireFox, PostMan (although nor a browser but is not affected),Electron APP (although I believe is chromium based but i don't know) ,when I go to the login route the back end simply skips over passport.deserializeUser() for affected browsers and thus req.isAuthenticated() returns false.

I have attempted all common solutions but none seem to fix the problem

Versions of dependancies

"axios": "^0.21.4",
"bcrypt": "^5.0.1",
"compression": "^1.7.4",
"connect-redis": "^5.2.0",
"cookie-parser": "^1.4.5",
"cors": "^2.8.5",
"express": "^4.17.1",
"express-session": "^1.17.2",
"knex": "^0.21.21",
"passport": "^0.5.0",
"passport-local": "^1.0.0",
"pg": "^8.7.1",
"redis": "^3.1.2",

Here is the code

server.js:

const passport = require("passport");
const LocalStrategy = require("passport-local");
const session = require("express-session");
require("dotenv").config();
const express = require("express");
const cors = require("cors");
const compression = require("compression");
const isAuth =require("./location/login_Verification").isAuth;




const whitelist =
  process.env.NODE_ENV === "development"
    ? ["http://localhost:3001"]
    : [
        "https://www.frontend.com",
        "https://www.backend.com/",
      ];
const corsOption = {
  origin: function (origin, callback) {
    if (whitelist.indexOf(origin) !== -1) {
      callback(null, true);
    } else {
      callback(new Error("Not allowed by CORS"));
    }
  },
  credentials: true,
};

const app = express();
app.use(compression());
app.use(cookieParser());
app.use(express.json());
app.use(
  express.urlencoded({
    extended: true,
  })
);

app.use(
  cors(corsOption)
);

app.use(
  session({
    secret: process.env.SESSION_SECRET,
    resave: false,
    saveUninitialized: true,
    store: new RedisStore({ client: redisClient }),
    cookie: {
      maxAge: 1000 * 60 * 60 * 24,
      secure: false,//tried to add true does not work
    },
  })
);

require("./location/config/passport");

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


app.post(
    "/login",
    passport.authenticate("local", {
      //session: true, tried this as well but nothing
      successRedirect: "/login-success",
      failureRedirect: "/login-fail",
    })
  );

/*It was suggested to use req.logIn to be more implicit but does not work
app.post("/login", function (req, res, next) {
    passport.authenticate("local", function (err, user, info) {
      if (info) {
        console.log(info);
        res.json({ success: "fail info" });
      }
      if (err) {
        console.log(err);
        return err;
      }
      if (!user) {
        console.log(user);
        res.json({ success: "fail user" });
      }
      req.logIn(user, function (err) {
        if (err) {
          return next(err);
        }
        req.session.save(function () {
          console.log(req.session.passport); 
          res.redirect("/login-success");
        });
      });
    })(req, res, next);
  });*/

app.get("/login-success",/*delayhere*/ isAuth, (req, res) => {
  const { hassignedup, reviewing_info } = req.user;
  res.json({
    success: true,
    hassignedup: hassignedup,
    reviewing_info: reviewing_info,
  })
  });

  app.get("/login-fail", (req, res) => {
    res.json({ success: false });
  });

app.listen(process.env.PORT, () => {
});

passport.js:

const ValidPassword =
  require("../location/passwordUtils").ValidPassword;
const passport = require("passport");
const LocalStrategy = require("passport-local").Strategy;
var knex= require("knex")(
  process.env.NODE_ENV === "development"
    ? {
        client: "pg",
        connection: {
          host: process.env.DB_HOST,
          user: process.env.DB_USER,
          password: process.env.DB_PASS,
          database: process.env.DB_NAME,
        },
      }
    : {
        client: "pg",
        connection: {
          connectionString: process.env.DATABASE_URL_LOCAL,
          ssl: {
            rejectUnauthorized: true,
            ca: fs.readFileSync("./config/file.pem").toString(),
          },
        },
      }
);

const customFields = {
  usernameField: "un",
  passwordField: "pw",
};

const verifyCallback = (username, password, done) => {
  knex
    .select("*")
    .from("users")
    .where("username", username)
    .then((user) => {
      if (user[0] === undefined) {
        return done(null, false);
      } else {
        return ValidPassword(password, user[0].pw).then((result) => {
          if (result) {
            let usercurrent = {
              usercurrent: {
                user_id: user[0].user_id,
                hassignedup: user[0].hassignedup,
              },
            };
            return done(null, usercurrent);
          } else {
            return done(null, false);
          }
        });
      }
    })
    .catch((err) => {
      done(err);
    });
};

const strategy = new LocalStrategy(customFields, verifyCallback);

passport.use(strategy);

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

passport.deserializeUser((user, done) => {
  //console.log("deserial", user.usercurrent);
  knex
    .select("userid")
    .from("users")
    .where("userid", user.usercurrent.user_id)
    .then((userobtained) => {
      done(null, user.usercurrent);
    })
    .catch((err) => done(err));
});

passwordUtils.js

const bcrypt = require("bcrypt");

function genPassword(password) {
  return bcrypt.hash(password, x).then((result) => {
    return { hash: result };
  });
}

function ValidPassword(password, hash) {
  return bcrypt.compare(password, hash).then((result) => {
    return result;
  });
}

module.exports.ValidPassword = ValidPassword;
module.exports.genPassword = genPassword;

login_Verification.js

const isAuth = (req, res, next) => {
 
  if (req.isAuthenticated()) {
    return next();
  } else {
    return res.status(401).json("not in");
  }
};

module.exports = {
  isAuth,
};

frontend.js ReactJS front end

....
onLogin=()=>{
axios({
          method: "post",
          url:
            process.env.NODE_ENV === "development"
              ? "http://localhost:3000/login"
              : "https://backend.com/login",
          headers: {
            "Access-Control-Allow-Origin":
              process.env.NODE_ENV === "development"
                ? "http://localhost:3000"
                : "https://frontend.com",
            "Content-Type": "application/json",
          },
          data: {
            un: this.state.username,
            pw: this.state.pwd,
          },
          withCredentials: true,
        }).then((result) => {
          console.log("log in", result.data);
         }

       }
....

I have tried to do the common solutions Found throughout a good summary of the solutions out there here but I still have the problem. Some people suggested to add a delay just don't know where the delay goes or if where I placed it is a good place, any help would be appreciated

I have tried: -create delay (dont know if correct place) -make sure session and initialize are in correct order -cors has credentials set to true -withcredentials in the front end -use a more implicit way to log in -in session declaration set secure to true

seems to be the way the browser interacts with backend not sure where to go or what to try problem seems to be there since at least 2016

Apoorva Chikara
  • 8,277
  • 3
  • 20
  • 35
VericalId
  • 105
  • 12

1 Answers1

0

After realizing that since heroku servers SSL requests are req.connection.encrypted always undefined according to this PassportJS callback switch between http and https just add one line as follows

app.set('trust proxy', 1);
VericalId
  • 105
  • 12