Cannot GET /auth/google/callback | PassportJs - node.js

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.");
});

Related

PassportJS session not working in subsequent request in express

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.

Passport Local Strategy returns not found

I'm trying to make a register/login with node, express and mongoose. I want to register and login users and if they aren't logged in they can't retrieve data from the api.
To make the login and register i have been watching this tutorial: Link it isn't as addecuate for my needs because half of the efforts and code goes into the ejs but i have been okay until the passport login.
I have created my local strategy in config/passport.js:
const LocalStrategy = require("passport-local").Strategy;
const bcrypt = require("bcryptjs");
const User = require("../models/user");
module.exports = function (passport) {
passport.use(
new LocalStrategy({ usernameField: "email" }, (email, password, done) => {
User.findOne({ email: email })
.then((user) => {
if (!user) {
return done(null, false, {
message: "That email is not registered",
});
}
bcrypt.compare(password, user.password, (err, isMatch) => {
if (err) console.log(err);
if (isMatch) {
return done(null, user);
} else {
done(null, false, { message: "Incorrect Password" });
}
});
})
.catch((err) => console.log(err));
})
);
passport.serializeUser((user, done) => {
done(null, user.id);
});
passport.deserializeUser((id, done) => {
User.findById(id, (err, user) => {
done(err, user);
});
});
};
My app.js looks like this:
const express = require("express");
const cors = require("cors");
const usersRouter = require("./routes/users");
const passport = require("passport");
const session = require("express-session");
require("dotenv").config();
const app = express();
require("./config/passport")(passport);
const connectDB = require("./db/connect");
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(
session({
secret: "*****",
resave: true,
saveUninitialized: true,
})
);
app.use(passport.initialize());
app.use(passport.session());
app.use(cors());
app.use("/api/v1/users", usersRouter);
const PORT = process.env.PORT || 5000;
const start = async () => {
try {
await connectDB(process.env.MONGO_URI);
app.listen(PORT, console.log(`Server is listening on port: ${PORT}....`));
} catch (error) {
console.log(error);
}
};
const notFound = require("./middleware/notFound");
app.use(notFound);
start();
My users router looks like this:
const express = require("express");
const router = express.Router();
const { postRegister } = require("../controllers/register");
router.route("/register").post(postRegister);
const { postLogin } = require("../controllers/login");
router.route("/login").post(postLogin);
module.exports = router;
The register works perfectly, but the login controller doesn't. Each time i post to that endpoint instead of getting a succesMessage or failureMessage i get the page not found router that is called at the end of app.js, i checked if the router calls the login function via a console log and it does. Here is the code for the login controller:
const passport = require("passport");
const postLogin = (req, res, next) => {
console.log("The function has been triggered");
passport.authenticate("local", {
successMessage: "Login authenticated",
failureMessage: "Login failed",
})(req, res, next);
};
module.exports = {
postLogin,
};
Why don't I get the responses from the login controller or my local strategy and instead i get page not found when the Login controller actually works?

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());

My passport auth doesnt work on Heroku, user is not returned

My app and auth is working perfectly localy, however after deploying the server to heroku I am unable to login, because user object is not returned.
Here is my passport file:
const passport = require('passport');
const localStrategy = require('passport-local').Strategy;
const mongoose = require('mongoose');
const User = mongoose.model('users');
passport.serializeUser((user, done) => {
// console.log({user})
done(null, user._id)
})
passport.deserializeUser((id, done) =>
User.findById(id).then((user) => {
if (user) {
done(null, user)
} else {
}
})
);
passport.use(new localStrategy((username, password, done) => {
// console.log({username}, {password})
User.findOne({ username: username }, (err, user) => {
if (err) { return done(err); }
if (!user) {
return done(null, false, { message: 'Username not found' });
}
if (!user.comparePassword(password, user.password)) {
return done(null, false, { message: 'Incorrect password.' });
}
// console.log('user', user)
return done(null, user);
});
}));
Routes:
const passport = require('passport');
const mongoose = require('mongoose');
const User = mongoose.model('users');
module.exports = (app) => {
app.post('/login',
passport.authenticate('local', {
successRedirect: '/loginSuccess',
failureRedirect: '/loginFailed',
})
);
app.get('/loginSuccess', (req, res) => {
res.send({ success: true, test:'test', user: req.user })
})
app.get('/loginFailed', (req, res) => {
res.send({ success: false, error: "Incorrect credentials" })
})
};
And I dont know if its helpful, but my index file:
const express = require('express');
const mongoose = require('mongoose');
const bodyParser = require('body-parser');
const passport = require('passport');
const cookieSession = require('cookie-session');
const keys = require('./config/keys');
require('./models/user');
require('./services/passport');
mongoose.connect(keys.mongoUri, { useNewUrlParser: true })
const app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(
cookieSession({
maxAge: 30 * 24 + 60 * 60 * 1000, //30 days
keys: [keys.cookieKey]
})
);
app.use(function (req, res, next) {
res.header("Access-Control-Allow-Origin", '*');
res.header("Access-Control-Allow-Credentials", true);
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS');
res.header("Access-Control-Allow-Headers", 'Origin,X-Requested-With,Content-Type,Accept,content-type,application/json');
next();
});
app.use(passport.initialize());
app.use(passport.session());
//ROUTES
require('./routes/auth')(app);
require('./routes/game')(app);
const PORT = process.env.PORT || 5000;
app.listen(PORT);
After login is successfull I send back object containing 3 other objects, success bool value, user object with user info and for the sake of testing, test object containing a string.
Everything is returned, except for user object. What could be the issue?

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