PassportJS session not working in subsequent request in express - node.js

I am making google authentication using PassportJS and I came into a problem where I cannot see any value in req.user object in the subsequent requests.
GoogleStrategy
const express = require("express");
const dotenv = require("dotenv");
const passport = require("passport");
dotenv.config();
const GoogleStrategy = require("passport-google-oauth20").Strategy;
passport.use(
new GoogleStrategy(
{
clientID: process.env.client_id,
clientSecret: process.env.client_secret,
callbackURL: "/api/google/callback",
},
function (accessToken, refreshToken, profile, done) {
done(null, profile);
console.log(profile.id);
}
)
);
passport.serializeUser((user, done) => {
done(null, user);
console.log("serialize");
console.log(user);
});
passport.deserializeUser((user, done) => {
done(null, user);
console.log("deserialize");
console.log(user);
});
server.js
const express = require("express");
const { db } = require("../database/db.js");
const dotenv = require("dotenv");
const passport = require("passport");
const passportsetup = require("./middleware/facebookMiddleware");
const userLoginRoutes = require("./routes/userRoutes");
const facebookRoutes = require("./routes/facebookRoutes");
const cors = require("cors");
const app = express();
const session = require("express-session");
const cookieSession = require("cookie-session");
const PORT = process.env.PORT || 3001;
app.use(express.json());
app.use(
session({
secret: "secret-key",
resave: false,
saveUninitialized: false,
name: "usersession",
cookie: {
maxAge: 24 * 60 * 60 * 100,
secure: false,
},
})
);
// app.use(
// cookieSession({
// name: "session",
// keys: ["amaaa"],
// maxAge: 24 * 60 * 60 * 100,
// })
// );
app.use(
cors({
origin: "http://localhost:3000",
methods: "GET,POST,PUT,DELETE",
credentials: true,
})
);
// initializing passport
app.use(passport.initialize());
// for persistent logins
app.use(passport.session());
// userRoutes
app.use("/api/users", userLoginRoutes);
app.use("/api/google", facebookRoutes);
app.get("/api", (req, res) => {
res.send("Api is running");
});
app.listen(PORT, console.log("server is running"));
routes
const express = require("express");
const passport = require("passport");
const router = express.Router();
const CLIENT_URL = "http://localhost:3000/signup";
router.route("/login/success").get((req, res) => {
console.log("hiiiiiiiiiiii raaaaaan");
console.log(req.user);
if (req.user) {
res.status(200).json({
success: true,
message: "successfull",
user: req.user,
// cookies: req.cookies
});
console.log(req.user);
}
});
router.route("/login/failed").get((req, res) => {
res.status(401).json({
success: false,
message: "failure",
});
});
router.route("/logout").get((req, res) => {
req.logout();
res.redirect(CLIENT_URL);
});
router
.route("/auth")
.get(passport.authenticate("google", { scope: ["profile"] }));
router.route("/callback").get(
passport.authenticate("google", {
successRedirect: CLIENT_URL,
failureRedirect: "/login/failed",
})
);
module.exports = router;
After logging in with google, I get the profile of the user but when I hit api/google/login/success I expect to get value in req.user but it gives null value. Is there anything wrong with my implementation?
And the fact that I am not checking the database while deserializing is that I just want the current value and I do not need everytime to check database.
Please correct me if I am using serialize and deserialize in wrong way.
Thanks.

Related

Cannot GET /auth/google/callback | PassportJs

Why I'm getting this error! Cannot GET /auth/google/callback after choosing an account from the google login page I got redirected to a white page with the above error, its been a week working on this google login thing!
This is index.js file:
const mongoose = require("mongoose");
const authRoute = require("./routes/auth");
const cors = require("cors");
const app = express();
const cookieSession = require("cookie-session");
const passportSetup = require("./passport");
const passport = require ("passport");
app.use(cookieSession({name: "session", keys: ["mokhtarah"],
maxAge: 24 * 60 * 60 * 100 })
);
// Passport middleware
app.use(passport.initialize());
app.use(passport.session());
app.use(cors({origin: "http://localhost:3000",
methods: "GET,POST,PUT,DELETE",
credentials: true,}));
app.use(express.json());
app.use(express.urlencoded({extended: true}));
app.use("/api/auth", authRoute);
app.use("/api/users", userRoute);
app.listen("4000", () => {
console.log("Backend is running.");
});
This is the passport.js file:
const User = require("./models/User");
const mongoose = require("mongoose");
const passport = require("passport");
const GoogleStrategy = require("passport-google-oauth20").Strategy;
passport.use(
new GoogleStrategy(
{
clientID: "",
clientSecret: "",
callbackURL: "/auth/google/callback",
},
function (accessToken, refreshToken, profile, done) {
done(null, profile);
console.log(profile)
}
)
)
passport.serializeUser((user, done) => {
done(null, user);
});
passport.deserializeUser((user, done) => {
done(null, user);
});
This is the auth.js file:
const router = require("express").Router();
const User = require("../models/User");
const passport = require("passport");
router.get("/google", passport.authenticate("google", { scope: ["profile"] }))
router.get(
"/google/callback",
passport.authenticate("google", {
successRedirect: 'http://localhost:3000/',
failureRedirect: 'http://localhost:4000/auth/google'
})
)
//LOGIN WITHOUT PASSPORTJS
router.post("/login", async (req, res) => {
try {
const user = await User.findOne({ email: req.body.email });
// if(!user) return res.status(400).json("Wrong credentials!");
!user && res.status(400).json("Wrong credentials!");
const validated = await bcrypt.compare(req.body.password, user.password);
// if(!validated) return res.status(400).json("Wrong credentials!");
!validated && res.status(400).json("Wrong credentials!");
const { password, ...others } = user._doc;
return res.status(200).json(others);
} catch (err) {
return res.status(500).json(err);
}
});
Login without passportjs works fine no issues only the google login, I just want the profile data to appear on my console log!
The Google Cloud Console:
In the auth.js file add /auth as a prefix in /google/callback route and in the index.js file remove /api/auth.
auth.js
router.get('/auth/google/callback', // add **/auth**
(req,res,next)=>{
passport.authenticate('google', { failureRedirect: '/auth/google/error' }, async (error, user , info) => {
if (error){
return res.send({ message:error.message });
}
if (user){
try {
// your success code
return res.send({
data: result.data,
message:'Login Successful'
});
} catch (error) {
// error msg
return res.send({ message: error.message });
}
}
})(req,res,next);
});
index.js
const mongoose = require("mongoose");
const authRoute = require("./routes/auth");
const cors = require("cors");
const app = express();
const cookieSession = require("cookie-session");
const passportSetup = require("./passport");
const passport = require ("passport");
app.use(cookieSession({name: "session", keys: ["mokhtarah"],
maxAge: 24 * 60 * 60 * 100 })
);
// Passport middleware
app.use(passport.initialize());
app.use(passport.session());
app.use(cors({origin: "http://localhost:3000",
methods: "GET,POST,PUT,DELETE",
credentials: true,}));
app.use(express.json());
app.use(express.urlencoded({extended: true}));
app.use("/", authRoute); // ====> change here
app.use("/api/users", userRoute);
app.listen("4000", () => {
console.log("Backend is running.");
});

how to add passport js (local-strategy) in all routes

I added the passport authenticated to my login route but I do not know how to add it to the other routes. now (req.isAuthenticated) is true in the login route but It's false in all of the other routes!!! How can I add it to all routes so that when the user is logged in, 'req.authenticated' becomes true on them?
login.js:
const express = require("express");
const router = express.Router();
const path = require("path");
const passport = require("passport");
const session = require("express-session");
const flash = require("express-flash");
const methodOverride = require('method-override');
const bodyParser = require('body-parser');
const { getAdmins } = require("../queries/queries");
//middlewares
router.use(flash());
router.use(
session({
secret: process.env.SESSION_SECRET,
resave: false,
saveUninitialized: false,
})
);
router.use(passport.initialize());
router.use(passport.session());
router.use(methodOverride('_method'));
//passport
const initializePassport = require("../passport-config");
initializePassport(
passport,
async (name) => {
let users = await getAdmins();
return users.find((user) => user.name == name)},
async (id) => {
let users = await getAdmins();
return users.find((user) => user.id == id)}
);
//get metod
router.get("/", checkAuthentication, (req, res) => {
res.render(path.join(__dirname, "../public/login.ejs"), {isLogin : req.isAuthenticated});
});
//post method
router.post(
"/",
passport.authenticate("local", {
successRedirect: "/messages",
failureRedirect: '/login',
failureFlash: true,
})
);
router.delete('/logout', (req, res)=>{
req.logOut();
res.redirect('/');
})
//check req authenticated
function checkAuthentication(req, res, next) {
if (req.isAuthenticated()) {
console.log('login:yes')
return next();
}
console.log('login:no');
return next();
}
module.exports = router;
passport-config.js:
const LocalStrategy = require("passport-local").Strategy;
function initialize(passport, getUserByName, getUserById) {
const authenticateUser = async (name, password, done) => {
const user = await getUserByName(name);
if (user == null) return done(null, false, { message: "sorry! user name is not exist" });
if(password == user.password){
return done(null, user);
} else done(null, false, {message : "incorrect password"});
};
passport.use(new LocalStrategy(authenticateUser));
passport.serializeUser((user, done)=> done(null, user.id));
passport.deserializeUser((id, done)=> done(null, getUserById(id)));
}
module.exports = initialize;
To solve this problem, I transferred this code from login.js to server.js:
//midlewares
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
const bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({extended : false}));
app.use(passport.initialize());
app.use(passport.session());
app.use(flash());

successRedirect is not working in passport login passport-local

I am using node.js express with sequelize and database postgreSql.the problem is in passport login failureRedirect works properly sucessRedirect does not redirect to the page that I want. It still loading and not responding anything and does not come any error.
when I submit login it will check for errors if errors it will work perfectly in failureRedirect but in Success it does not work like page has loading only not goes to the destination page and if I stop the project and restart the project it will be in destination page!! i dont know what is the problem help me.
mainController.js
const express = require("express");
const sessions = require("express-session");
require("../model/MasterUser.model");
const passport = require("passport");
var session = sessions;
const router = express.Router();
router.get("/dashboard", (req, res) => {
res.render('dashboard');
});
router.get("/login", (req, res) => {
res.render("login", { layout: "login.hbs" });
});
router.post(
"/login",
passport.authenticate("local", {
successRedirect: "/main/dashboard",
failureRedirect: "/main/login",
failureFlash: true,
})
);
module.exports = router;
passport.js
const LocalStrategy = require("passport-local").Strategy;
const bcrypt = require("bcryptjs");
const sequelize = require("sequelize");
const masterUser = require("../model/MasterUser.model");
module.exports = function (passport) {
passport.use(
new LocalStrategy(
{ usernameField: "user_name" },
(user_name, password, done) => {
// Match user
masterUser.findOne({ where: { user_name: user_name } }).then((user) => {
if (!user) {
return done(null, false, {
message: "This username is not registered",
});
}
// Match password
bcrypt.compare(password, user.password, (err, isMatch) => {
if (err) throw err;
if (isMatch) {
return done(null, user);
} else {
return done(null, false, { message: "Password incorrect" });
}
});
});
}
)
);
passport.serializeUser((user, done) => {
done(null, user.id);
});
passport.deserializeUser((id, done) => {
masterUser.findByPk(id, (err, user) => {
done(err, user);
});
});
};
index.js
const express = require("express");
const Handlebars = require("handlebars");
var flash = require("connect-flash");
const app = express();
const path = require("path");
const bodyparser = require("body-parser");
const expressHandlebars = require("express-handlebars");
const passport = require("passport");
const sessions = require("express-session");
var session = sessions;
const MainController = require("./controllers/MainController");
const db = require("./config/database");
//test db
db.authenticate()
.then(() => console.log("Database Connected..."))
.catch((err) => console.log("error" + err));
//for security purpose
const cors = require("cors");
app.use(
cors()
);
//Passport Config
require("./config/passport")(passport);
app.use(cookieParser());
//use body parser
app.use(bodyparser.json());
app.use(bodyparser.urlencoded({ extended: true }));
const {
allowInsecurePrototypeAccess,
} = require("#handlebars/allow-prototype-access");
app.use(
bodyparser.urlencoded({
urlencoded: true,
})
);
app.use(
sessions({
secret: "secret_key",
resave: false,
saveUninitialized: true,
cookie: { maxAge: 60000 },
})
);
// use flash for show messages
app.use(flash());
// Passport middleware
app.use(passport.initialize());
app.use(passport.session());
//flash messages
app.use((req, res, next) => {
res.locals.success_msg = req.flash("success_msg");
res.locals.error_msg = req.flash("error_msg");
res.locals.error = req.flash("error");
next();
});
//setting up view Engine
app.set("views", path.join(__dirname, "/views"));
//using the hbs
app.engine(
"hbs",
expressHandlebars({
extname: "hbs",
defaultLayout: "default",
layoutsDir: __dirname + "/views/layouts",
handlebars: allowInsecurePrototypeAccess(Handlebars),
})
);
app.set("view engine", "hbs");
//route for Main
app.use("/main", MainController);
//default
app.get("/", (req, res) => {
res.render("login");
});
app.listen(3000, () => {
console.log("App listening on port 3000!");
});
the problem has been solved guys I made done wrong code in deserializeUser.
passport.js before
passport.deserializeUser((id, done) => {
masterUser.findByPk(id, (err, user) => {
done(err, user);
});
});
};
passport.js after
passport.deserializeUser(function (id, done) {
masterUser.findOne({ where: { id: id } }).then((user) => {
done(null, user);
});
});
the problem is for sequelize get the user data is different so now its worked for me.this is useful for who using express with sequelize and passport with postgresql

Why do I receive a type error "username of undefined" after properly following passport.js documentation for express?

After searching through a plethora of answers to the same problem, none of the answers work for me. So I am hoping that I can get some help. In Routes/profile.js I make a get request to localhost:8081/profile which gives me the error. I am using Express and mongodb.
server.js
Note:
authRoutes and profileRoutes are used as middleware for the routes
const express = require("express");
const app = express();
const authRoutes = require("./routes/authorize");
const profileRoutes = require("./routes/profile");
require("dotenv/config");
const PORT = process.env.PORT || 8081;
const cors = require("cors");
const morgan = require("morgan");
const bodyParser = require("body-parser");
const mongoose = require("mongoose");
const cookieSession = require("cookie-session");
const passport = require("passport");
const keys = require("./config/key.js");
const passportSetup = require("./config/passport.js");
app.use("/auth", authRoutes);
app.use("/profile", profileRoutes);
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
//Initialize passport
app.use(passport.initialize());
app.use(passport.session());
app.use(
cookieSession({
maxAge: 24 * 60 * 60 * 1000,
keys: [keys.session.cookieKey]
})
);
app.use(cors());
app.use(morgan("combined"));
mongoose.connect(
process.env.DB_CONNECTION,
{
useNewUrlParser: true,
useUnifiedTopology: true
},
() => console.log("mongo atlas")
);
app.listen(PORT, () => {
console.log(`Server is on port ${PORT}`);
});
passport.js
const passport = require("passport");
const GoogleStratedy = require("passport-google-oauth20");
const keys = require("./key.js");
const User = require("../models/userModel");
passport.serializeUser((user, done) => {
done(null, user.id);
});
passport.deserializeUser((id, done) => {
User.findById(id).then(user => {
done(null, user);
});
});
passport.use(
new GoogleStratedy(
{
//options for the google strategy
callbackURL: "/auth/google/redirect",
clientID: keys.google.clientID,
clientSecret: keys.google.clientSecret
},
(accessToken, refreshToken, profile, done) => {
//passport callback function
console.log("passport callback fired");
//Check if user already exist in Db
User.findOne({ googleId: profile.id }).then(currentUser => {
if (currentUser) {
//already have user
console.log(`user is: ${currentUser} ALREADY REGISTERED`);
done(null, currentUser);
} else {
//create new user
new User({
username: profile.displayName,
googleId: profile.id
})
.save()
.then(newUser => {
console.log(`new user created ${newUser}`);
done(null, newUser);
});
}
});
}
)
);
Routes/authorize.js
const express = require("express");
const router = express.Router();
const passport = require("passport");
//auth login
router.get("/login", (req, res) => {
res.send({
message: `Hello ${req.body.email}! Your user was registered`
});
});
//auth logout
router.get("/logout", (req, res) => {
res.send("it works");
});
//auth with google
router.get(
"/google",
passport.authenticate("google", {
scope: ["profile"]
})
);
router.get("/google/redirect", passport.authenticate("google"), (req, res) => {
res.redirect("/profile");
});
module.exports = router;
Routes/profile.js This is for redirect api
const router = require("express").Router();
const passport = require("passport");
router.get("/", (req, res) => {
console.log(req.user.username);
});
module.exports = router;
userModel.js
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const userSchema = new Schema({
username: String,
googleId: String
});
const User = mongoose.model("user", userSchema);
module.exports = User;
You need to register the session middleware (in your case that is cookieSession), which populates the req.session, before you register the passport middlewares. So, you have to change the order of your code to this:
//Initialize passport
app.use(
cookieSession({
maxAge: 24 * 60 * 60 * 1000,
keys: [keys.session.cookieKey]
})
);
app.use(passport.initialize());
app.use(passport.session());

passport does not save req.user after authentication

Currently a user can sign in with github, and i can see it gets the req.user in the callback function, and on passport github file
console.log(`frontid ${req.user.id}`) // logs user id
and passport
console.log(`backbro ${id}`); // logs an id
however, when i go on this route, the github user returns null and im not sure why. There were a few times, i see the signed in github user return in the current_user route, however its rare that i see it now. It sometimes shows, sometimes dont. Kinda wierd. Could it be a session issue ?
router.get("/current_user", (req, res) => {
if(req.user){
res.status(200).send({ user: req.user});
} else {
res.json({ user:null})
}
});
yes i looked at the following links, still no suitable answer.
Node + Express + Passport: req.user Undefined
req.user undefined after twitter authentication using express sever, passport.js
The way im accessing this link, is by explictily calling
localhost:8000/api/users/auth/github
in the address bar.
routes/users
router.get('/auth/github', passport.authenticate('github', {
scope:[ 'profile', 'id']
}));
router.get('/auth/github/callback',
passport.authenticate('github', { session:true, failureRedirect: 'http:localhost:8001/signIn' }),
function(req, res) {
// Successful authentication, redirect home.
// var token = jwt.sign({ id: req.user.id}, process.env.JWT_SECRET );
// // res.cookie("jwt", token, { expires: new Date(Date.now() + 10*1000*60*60*24)});
// jwt.verify(token, process.env.JWT_SECRET, function(err, data){
// console.log(err, data);
// })
const user = req.user
req.logIn(user, err => {
models.User.findOne({
where: {
id: req.user.id,
},
}).then(user => {
const token = jwt.sign({ id: user.id }, process.env.JWT_SECRET);
// res.cookie("jwt", token, { expires: new Date(Date.now() + 10*1000*60*60*24)});
jwt.verify(token, process.env.JWT_SECRET, function(err, data){
console.log(err, data);
})
res.redirect('http://localhost:8001');
// console.log(req.user)
});
});
console.log(`frontid ${req.user.id}`)
// res.redirect('')
// console.log('this works', token);
});
passport-github.js
const GitHubStrategy = require('passport-github2').Strategy;
const Sequelize = require('sequelize');
const Op = Sequelize.Op;
const models = require("../models/");
// passport.serializeUser((user, done) => {
// // push to session
// done(null, user.id);
// console.log(user.id)
// });
// passport.deserializeUser((id, done) => {
// models.User.findOne({
// where: {
// id,
// },
// }).then(user => done(null, user))
// .catch(done);
// });
module.exports = async (passport) => {
passport.use(
new GitHubStrategy(
{
clientID: process.env.clientID,
clientSecret: process.env.secret,
callbackURL: 'http://127.0.0.1:8000/api/users/auth/github/callback',
passReqToCallback: true,
profileFields: ['id', 'login']
},
(req, accessToken, refreshToken, profile, done) => {
const { id, login, email} = profile._json;
console.log(`backbro ${id}`);
// console.log(req)
models.User.findOne({
where:{
id: id
}
}).then( user => {
// if user is found
if(user){
return done(null, user)
}
// else create new user
else{
models.User.create({
id: id,
username:login,
email: email,
createdAt: Date.now()
}).then( user => {
console.log('github user created');
return done(null, user);
})
}
})
}
)
);
passport.serializeUser((user, done) => {
// push to session
return done(null, user.id);
});
passport.deserializeUser((userId, done) => {
// console.log('calling deserial' + userId);
// // TODO: findByPk syntax? findById deprecated? Try later after sucessfully record data in DB
models.User
.findOne({ where: { id: userId } })
.then(function(user){
// console.log(user);
return done(null, userId);
}).catch(function(err){
done(err, null);
});
// return done(null, id);
});
}
app.js
const express = require('express');
const app = express();
const userRoute = require('./routes/users');
const postRoute = require('./routes/posts');
const bodyParser = require('body-parser');
const logger = require('morgan');
const session = require('express-session');
const cookieParser = require('cookie-parser') ;
const dotenv = require('dotenv');
const env = dotenv.config();
const cors = require('cors');
const models = require('./models/');
const host = '0.0.0.0';
const PORT = process.env.PORT || 8000;
const passport = require('passport');
const path = require('path');
const Sequelize = require('sequelize');
const SequelizeStore = require('connect-session-sequelize')(session.Store);
const proxy = require('express-http-proxy');
app.use(function(req, res, next) {
res.locals.user = req.user; // This is the important line
// req.session.user = user
console.log(res.locals.user);
next();
});
app.use(cors({
origin: process.env.ALLOW_ORIGIN,
credentials: false,
allowedHeaders: 'X-Requested-With, Content-Type, Authorization',
methods: 'GET, POST, PATCH, PUT, POST, DELETE, OPTIONS',
exposedHeaders: ['Content-Length', 'X-Foo', 'X-Bar'],
}))
var sequelize = new Sequelize(
process.env.POSTGRES_DB,
process.env.POSTGRES_USER,
process.env.POSTGRES_PASSWORD,{
"dialect": "sqlite",
"storage": "./session.sqlite"
});
myStore = new SequelizeStore({
db:sequelize,
})
if (!process.env.PORT) {
require('dotenv').config()
}
// console.log(process.env.DATABASE_URL);
if (!process.env.PORT) {
console.log('[api][port] 8000 set as default')
console.log('[api][header] Access-Control-Allow-Origin: * set as default')
} else {
console.log('[api][node] Loaded ENV vars from .env file')
console.log(`[api][port] ${process.env.PORT}`)
console.log(`[api][header] Access-Control-Allow-Origin: ${process.env.ALLOW_ORIGIN}`)
}
app.use(logger('dev'));
app.use(express.static(path.join(__dirname, 'public')));
app.use(express.static(path.join(__dirname, 'build')));
// We need a store in order to save sessions, instead of the sessions clearing out on us :)
require('./config/passport')(passport); // PASSPORT Init
require('./config/passport-github')(passport); // PASSPORT Init
app.use(cookieParser());
app.use(bodyParser.json());
app.use(session({
store: myStore,
saveUninitialized: false,
resave:false,
cookie: { maxAge: 30 * 24 * 60 * 60 * 1000 }, // 30 days
secret : process.env.JWT_SECRET,
}));
myStore.sync();
app.use(passport.initialize());
app.use(passport.session());
app.use(bodyParser.urlencoded({ extended:false}));
// this code may be useless or useful, still trying to understand cors.
app.use('/api/users', userRoute );
app.use('/api/posts', postRoute );
// In order to use REACT + EXPRESS we need the following code, alone with a build
// in the client folder we run a npm run build in the client folder then it is referred
// in the following code.
app.use(express.static(path.join(__dirname, 'client/build')));
if(process.env.NODE_ENV === 'production') {
app.use(express.static(path.join(__dirname, 'client/build')));
//
app.get('*', (req, res) => {
res.sendfile(path.join(__dirname = 'client/build/index.html'));
})
}
//build mode
app.get('*', (req, res) => {
res.sendFile(path.join(__dirname+'/client/public/index.html'));
})
models.sequelize.sync().then(function() {
app.listen(PORT, host, () => {
console.log('[api][listen] http://localhost:' + PORT)
})
})

Resources