I am building a website in which logging in with Google and typing email and password were working fine, but when I introduced logging in with Facebook, mongoDb is giving following error-
MongoError: E11000 duplicate key error collection: userDB.users index: username_1 dup key: { username: null }
//jshint esversion:6
require('dotenv').config();
const express = require("express");
const bodyParser = require("body-parser");
const ejs= require("ejs");
const mongoose = require("mongoose");
const session = require("express-session");
const passport = require("passport");
const passportLocalMongoose = require("passport-local-mongoose");
const GoogleStrategy = require('passport-google-oauth20').Strategy;
const FacebookStrategy = require('passport-facebook').Strategy;
const findOrCreate = require("mongoose-findorcreate");
const app = express();
console.log(process.env.API_KEY);
app.use(express.static("public"));
app.set('view engine', 'ejs');
app.use(bodyParser.urlencoded({
extended: true
}));
app.use(session({
secret: "Our little secret.",
resave: false,
saveIninitialized: false
}));
app.use(passport.initialize());
app.use(passport.session());
mongoose.connect("mongodb://localhost:27017/userDB",{ useUnifiedTopology: true });
mongoose.set("useCreateIndex", true);
const userSchema = new mongoose.Schema ({
email: String,
password: String,
googleId: String,
facebookId: String,
secret: String
});
userSchema.plugin(passportLocalMongoose);
userSchema.plugin(findOrCreate);
const User = new mongoose.model("User", userSchema);
passport.use(User.createStrategy());
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
User.findById(id, function(err, user) {
done(err, user);
});
});
passport.use(new GoogleStrategy({
clientID: process.env.CLIENT_ID,
clientSecret: process.env.CLIENT_SECRET,
callbackURL: "http://localhost:3000/auth/google/secrets",
userProfileURL: "https://www.googleapis.com/oauth2/v3/userinfo"
},
function(accessToken, refreshToken, profile, cb) {
User.findOrCreate({ googleId: profile.id }, function (err, user) {
return cb(err, user);
});
}
));
passport.use(new FacebookStrategy({
clientID: process.env.FACEBOOK_APP_ID,
clientSecret: process.env.FACEBOOK_APP_SECRET,
callbackURL: "http://localhost:3000/auth/facebook/secrets"
},
function(accessToken, refreshToken, profile, cb) {
User.findOrCreate({ facebookId: profile.id }, function (err, user) {
return cb(err, user);
});
}
));
app.get("/",function(req,res){
res.render("home")
});
app.get('/auth/google',
passport.authenticate('google', { scope: ['profile'] })
);
app.get('/auth/google/secrets',
passport.authenticate('google', { failureRedirect: '/login' }),
function(req, res) {
// Successful authentication, redirect to secrets.
res.redirect('/secrets');
});
app.get('/auth/facebook',
passport.authenticate('facebook'));
app.get('/auth/facebook/secrets',
passport.authenticate('facebook', { failureRedirect: '/login' }),
function(req, res) {
// Successful authentication, redirect home.
res.redirect('/secrets');
});
app.get("/login",function(req,res){
res.render("login")
});
app.get("/register",function(req,res){
res.render("register")
});
...
How to solve this issue so that I can login via both google and facebook one after the other or vice-versa?
see the solution here:
Setting Up Facebook Authentication with MongoDB Atlas and Passport.js
the problem is with the code above that both facebook and google users create a document in database which has no username. and MongoD set username as unique by default. so just drop the indexes from username and that solves the issue.
Related
I'm having some issues with setting up passport. The information gets to the console.log(req.body). and the user is being saved in the mongodb database with all the salting and hashing
passport.authenticate is not woking while signing up new users. but
and Express sessions are not being created.
const express = require("express");
const bodyParser = require("body-parser");
const mongoose = require("mongoose");
const cors = require('cors');
const session = require('express-session');
const passport = require("passport");
const LocalStrategy = require("passport-local");
const passportLocalMongoose = require("passport-local-mongoose");
const findOrCreate = require("mongoose-findorcreate");
const app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(express.static("public"));
app.use(
cors({
origin: true,
credentials: true,
optionsSuccessStatus: 200
}));
mongoose.set("strictQuery", false);
app.use(session({
secret: "our little secret.",
resave: false,
saveUninitialized: false
}));
app.use(passport.initialize());
app.use(passport.session());
mongoose.connect("mongodb://localhost:27017/blogDB");
const userSchema = new mongoose.Schema(
{
name: String,
username: String,
password: String,
posts: [{
title: String,
content: String,
timestamp: Date
}]
}
);
userSchema.plugin(passportLocalMongoose);
userSchema.plugin(findOrCreate);
const User = new mongoose.model("user", userSchema);
passport.use(new LocalStrategy(User.authenticate()));
// passport.use(User.createStrategy());
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
User.findById(id, function(err, user) {
done(err, user);
});
});
app.post("/signup", function (req, res) {
User.register(
{ name:req.body.name,
username:req.body.email },
req.body.password,
function (err, user) {
if (err) {
console.log(err);
} else {
res.send(user);
passport.authenticate('local', function (err, user, info) {
if (!err) {
console.log("authenticated");
}
})(req, res)
}
})
})
i have been searching the whole web tring to find a solution, tried a so many solutions but nothing worked
so I am learning google OAuth, and I wrote this:
//jshint esversion:6
require('dotenv').config();
const express = require("express");
const bp = require("body-parser");
const ejs = require("ejs");
const mongoose = require("mongoose");
const session = require("express-session");
const passport = require("passport");
const findOrCreate = require("mongoose-findorcreate");
const passportLocalMongoose = require("passport-local-mongoose");
const GoogleStrategy = require("passport-google-oauth20").Strategy;
const app = express();
app.use(express.static('public'));
app.set("view engine", "ejs");
app.use(bp.urlencoded({ extended: true }));
app.use(session({
secret: "Our little secret.",
resave: false,
saveUninitialized: false
}));
app.use(passport.initialize());
app.use(passport.session());
mongoose.connect("mongodb://localhost:27017/userDB", { useNewUrlParser: true, useUnifiedTopology: true });
mongoose.set("useCreateIndex", true);
const userSchema = new mongoose.Schema({
email: String,
password: String
});
userSchema.plugin(passportLocalMongoose);
userSchema.plugin(findOrCreate);
const User = mongoose.model("User", userSchema);
passport.use(User.createStrategy());
passport.serializeUser(User.serializeUser());
passport.deserializeUser(User.deserializeUser());
passport.use(new GoogleStrategy({
clientID: process.env.CLIENT_ID,
clientSecret: process.env.CLIENT_SECRET,
callbackURL: "http://localhost:3000/auth/google/secrets",
userProfileURL: "https://www.googleapis.com/oauth2/v3/userinfo"
},
function(accessToken, refreshToken, profile, cb) {
User.findOrCreate({ googleId: profile.id }, function (err, user) {
return cb(err, user);
});
}
));
app.get("/", function(req, res){
res.render("home");
});
app.get("/auth/google", function(req, res){
passport.authenticate(("google", { scope: ["profile"] }), function(err){
if(err){
console.log(err);
}
});
});
app.get("/login", function(req, res){
res.render("login");
});
app.get("/register", function(req, res){
res.render("register");
});
app.get("/logout", function(req, res){
req.logout();
res.redirect("/login");
});
app.get("/secrets", function(req, res){
if(req.isAuthenticated()){
res.render("secrets");
}else{
res.redirect("/login");
}
});
app.post("/register", function(req, res){
User.register({username: req.body.username}, req.body.password, function(err, user){
if(err){
res.redirect("register");
}else{
passport.authenticate("local")(req, res, function(){
res.redirect("/secrets");
});
}
});
});
app.post("/login", function(req, res){
const user = new User({
username: req.body.username,
password: req.body.password
});
req.login(user, function(err){
if(err){
console.log(err);
}else{
passport.authenticate("local")(req, res, function(){
res.redirect("/secrets");
});
}
});
});
app.listen(3000);
but when I try to register with google the authentication screen does not show up, I created the app on the google developers console and they were saying this:
"Your app will only be accessible to people on your test user list. Once your app is ready for publishing, you may need to validate it."
don't know what to do, it's my first time with Google OAuth.
Go to google developer console under consent screen you will find
While your application has not been verified you can add additional users here these are your developers who will be able to access your application while it is still in development.
I have a video which walks you through how to add the users. Google OAuth Error 403: access_denied easy fix.
I get an error TypeError: Cannot read property 'register' of undefined while attempting to register any user to the database using a post request via postman on route http:localhost:3000/signup, I searched for similar errors and tried the following:
1- installing and using bodyparser and using it on server.js
2- declaring express session before passport initialization and declaration of passport.session
and i use body to pass json data to the route on postman enter image description here
/backend/routes/signup.js
const router = require("express").Router();
const passport = require("passport");
const User = require("../models/users").default;
router.route("/signup").get((req, res) => {
res.render("/signup");
});
router.route("/signup").post((req, res) => {
const registeredUser = {
firstName: req.body.firstName,
lastName: req.body.lastName,
username: req.body.username,
email: req.body.email
}
User.register(registeredUser, req.body.password, function(err, user) {
if (err) {
console.log(err);
} else {
passport.authenticate("local")(req, res, function() {
res.json("User registered");
res.redirect("/notes/:username");
// redirect user or do whatever you want
});
}
// Value 'result' is set to false. The user could not be authenticated since the user is not active
});
});
// const newUser = new User({
// firstName,
// lastName,
// username,
// email,
// password
// });
// newUser.save()
// .then(() => res.json("User " + username + " is registered to database!"))
// .catch(err => res.status(400).json("Error" + err
module.exports = router;
/backend/server.js
//jshint esversion:6
const express = require("express");
const cors = require("cors");
const bodyParser = require('body-parser');
const mongoose = require("mongoose");
const passport = require("passport");
const passportLocalMongoose = require("passport-local-mongoose");
const User = require("./models/users");
const Note = require("./models/notes");
const notesRouter = require("./routes/notes");
const registerRouter = require("./routes/signup");
const loginRouter = require("./routes/signin");
require('dotenv').config();
const app = express();
const port = process.env.PORT || 3000;
app.use(cors());
app.use(express.json());
app.set('view engine', 'ejs');
app.use( bodyParser.json());
app.use(bodyParser.urlencoded({
extended: true
}));
app.use(require("express-session")({
secret:"This is keeper clone",
resave: false,
saveUninitialized: false
}));
app.use(passport.initialize());
app.use(passport.session());
passport.serializeUser(User.serializeUser());
passport.deserializeUser(User.deserializeUser());
const uri = process.env.ATLAS_URI;
mongoose.connect(uri, { useNewUrlParser: true, useCreateIndex: true, useUnifiedTopology: true});
mongoose.set("useCreateIndex", true);
const connection = mongoose.connection;
connection.once("open", () => {
console.log("MongoDb database connection established successfully");
});
app.use("/", notesRouter);
app.use("/", registerRouter);
app.use("/", loginRouter);
app.listen(port, () => {
console.log("Server is running on port 3000!");
});
/backend/models/users.js
const mongoose = require("mongoose");
const passportLocalMongoose = require("passport-local-mongoose");
const Schema = mongoose.Schema;
const userSchema = new Schema({
firstName: {
type: String,
required: true
},
lastName: {
type: String,
required: true
},
username: {
type: String,
required: true,
unique: true,
trim: true,
minlength: 3
},
email: {
type: String,
required: true,
unique: true,
trim: true,
},
password: {
type: String,
required: true,
minlength: 8
},
googleId: {
type: String
}
},
{
timestamps: true,
});
userSchema.plugin(passportLocalMongoose);
const User = mongoose.model("User", userSchema);
module.exports = User;
I have previously used the same approach in another project and it worked fine for me
//jshint esversion:6
require('dotenv').config();
const express = require("express");
const bodyParser = require("body-parser");
const ejs = require("ejs");
const mongoose = require("mongoose");
const session = require('express-session');
const passport = require("passport");
const passportLocalMongoose = require("passport-local-mongoose");
const GoogleStrategy = require('passport-google-oauth20').Strategy;
const FacebookStrategy = require("passport-facebook").Strategy;
const findOrCreate = require('mongoose-findorcreate');
const app = express();
app.use(express.static("public"));
app.set('view engine', 'ejs');
app.use(bodyParser.urlencoded({
extended: true
}));
app.use(session({
secret: "Our little secret.",
resave: false,
saveUninitialized: false
}));
app.use(passport.initialize());
app.use(passport.session());
mongoose.connect("mongodb://localhost:27017/userDB", {useNewUrlParser: true, useUnifiedTopology: true});
mongoose.set("useCreateIndex", true);
const userSchema = new mongoose.Schema ({
email: String,
password: String,
googleId: String,
facebookId: String,
secret: String
});
userSchema.plugin(passportLocalMongoose);
userSchema.plugin(findOrCreate);
const User = new mongoose.model("User", userSchema);
passport.use(User.createStrategy());
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
User.findById(id, function(err, user) {
done(err, user);
});
});
passport.use(new GoogleStrategy({
clientID: process.env.CLIENT_ID,
clientSecret: process.env.CLIENT_SECRET,
callbackURL: "http://localhost:3000/auth/google/secrets",
userProfileURL: "https://www.googleapis.com/oauth2/v3/userinfo"
},
function(accessToken, refreshToken, profile, cb) {
console.log(profile);
User.findOrCreate({ googleId: profile.id }, function (err, user) {
return cb(err, user);
});
}
));
passport.use(new FacebookStrategy({
clientID: process.env.APP_ID,
clientSecret: process.env.APP_SECRET,
callbackURL: "http://localhost:3000/auth/facebook/secrets"
},
function(accessToken, refreshToken, profile, done) {
User.findOrCreate({ facebookId: profile.id }, function(err, user) {
if (err) { return done(err); }
done(null, user);
});
}
));
app.get("/", function(req, res){
res.render("home");
});
app.get("/auth/google",
passport.authenticate('google', { scope: ["profile"] })
);
app.get("/auth/google/secrets",
passport.authenticate('google', { failureRedirect: "/login" }),
function(req, res) {
// Successful authentication, redirect to secrets.
res.redirect("/secrets");
});
app.get('/auth/facebook', passport.authenticate('facebook'));
app.get('/auth/facebook/secrets',
passport.authenticate('facebook', { successRedirect: '/secrets',
failureRedirect: '/login' }));
app.get("/login", function(req, res){
res.render("login");
});
app.get("/register", function(req, res){
res.render("register");
});
app.get("/secrets", function(req, res){
User.find({"secret": {$ne: null}}, function(err, foundUsers){
if (err){
console.log(err);
} else {
if (foundUsers) {
res.render("secrets", {usersWithSecrets: foundUsers});
}
}
});
});
app.get("/submit", function(req, res){
if (req.isAuthenticated()){
res.render("submit");
} else {
res.redirect("/login");
}
});
app.post("/submit", function(req, res){
const submittedSecret = req.body.secret;
//Once the user is authenticated and their session gets saved, their user details are saved to req.user.
// console.log(req.user.id);
User.findById(req.user.id, function(err, foundUser){
if (err) {
console.log(err);
} else {
if (foundUser) {
foundUser.secret = submittedSecret;
foundUser.save(function(){
res.redirect("/secrets");
});
}
}
});
});
app.get("/logout", function(req, res){
req.logout();
res.redirect("/");
});
app.post("/register", function(req, res){
User.register({username: req.body.username}, req.body.password, function(err, user){
if (err) {
console.log(err);
res.redirect("/register");
} else {
passport.authenticate("local")(req, res, function(){
res.redirect("/secrets");
});
}
});
});
app.post("/login", function(req, res){
const user = new User({
username: req.body.username,
password: req.body.password
});
req.login(user, function(err){
if (err) {
console.log(err);
} else {
passport.authenticate("local")(req, res, function(){
res.redirect("/secrets");
});
}
});
});
app.listen(3000, function() {
console.log("Server started on port 3000.");
});
you use register function of User Model
User.register(registeredUser, req.body.password, function(err, user)
but you don't defined it, for defined register method in mongoose, you can use this documentation or use static method in mognoose
I have solved it by just removing .default from the User import statement in route file
const User = require("../models/users").default;
const User = require("../models/users");
I found simmilar questions on the platform but the answers they are providing is creating user schema. Tat i have already done, maybe. Please help me out.
mongoose.set("useCreateIndex", true);
const Schema = mongoose.Schema;
const userSchema = new Schema({
email: String,
password: String,
googleId: String
});
userSchema.plugin(passportLocalMongoose);
userSchema.plugin(findOrCreate);
const User = mongoose.model("User", userSchema);
passport.use(User.createStrategy());
I am trying to authenticate users with google login, when i try to register with google an error like this appears
ReferenceError: user is not defined.
My app is like so:
const express = require("express");
const ejs = require("ejs");
const bodyParser = require("body-parser");
const mongoose = require("mongoose");
const bcrypt = require("bcrypt");
const saltRounds = 10;
const session = require("express-session");
const passport = require("passport");
const passportLocalMongoose = require("passport-local-mongoose");
const GoogleStrategy = require('passport-google-oauth20').Strategy;
const findOrCreate = require("mongoose-findorcreate");
const app = express();
app.use(express.static("public"));
app.set('view engine', 'ejs');
app.use(bodyParser.urlencoded({
extended: true
}));
app.use(session({
secret: "we are on!",
resave: false,
saveUninitialized: false
}));
app.use(passport.initialize());
app.use(passport.session());
mongoose.connect("mongodb://localhost:27017/userDB", {
useNewUrlParser: true,
useUnifiedTopology: true
});
mongoose.set("useCreateIndex", true);
const Schema = mongoose.Schema;
const userSchema = new Schema({
email: String,
password: String,
googleId: String
});
userSchema.plugin(passportLocalMongoose);
userSchema.plugin(findOrCreate);
const User = mongoose.model("User", userSchema);
passport.use(User.createStrategy());
passport.serializeUser(function(id, done){
done(null, user.id);
});
passport.deserializeUser(function(id, done){
User.findById(id, function(err, user){
done(err, user);
});
});
passport.use(new GoogleStrategy({
clientID: process.env.CLIENT_ID,
clientSecret: process.env.CLIENT_SECRET,
callbackURL: "http://localhost:3000/auth/google/secrets",
userProfileURL: "https://www.googleapis.com/oauth2/v3/userinfo"
},
function(accessToken, refreshToken, profile, cb) {
console.log(profile);
User.findOrCreate({ googleId: profile.id }, function (err, user) {
console.log("THE USER: ", user);
return cb(err, user);
});
}
));
The error points out to the user inside deserializeUser, i do not know how to fix it. Please help!
I have solved it, i was calling a user i never declared.
Here is the solved code, just the errored part
passport.serializeUser(function(user, done){
done(null, user.id);
});
I understand that this question has been asked on here before, but the answers on those questions haven't helped me at all.
After the successful authentication of my user through passport with the "#oauth-everything/passport-discord" strategy, req.user is still undefined.
Here is the code in my main file,
// Modules
const compression = require("compression"),
cookieParser = require("cookie-parser"),
cors = require("cors"),
express = require("express"),
exphbs = require("express-handlebars"),
session = require("express-session"),
logger = require("morgan"),
path = require("path"),
createError = require("http-errors"),
mongoose = require("mongoose"),
debug = require("debug"),
flash = require("connect-flash"),
passport = require("passport");
// Local files
const setupPassport = require("./src/setupPassport");
// Passport
setupPassport(passport);
// Mongoose
mongoose.connect("mongodb://localhost/website", {
useNewUrlParser: true,
useUnifiedTopology: true
}).then(() => {
debug("sb:mongoose")("Successfully connected to mongodb.");
}).catch(e => {
debug("sb:mongoose")("Unable to connect to mongodb\n" + e);
});
// Routers
const indexRouter = require("./routes/index");
const loginRouter = require("./routes/login");
// App setup
const app = express();
app.set("views", path.join(__dirname, "views/pages"));
// View engine
app.engine("hbs", exphbs({
defaultLayout: "user",
layoutsDir: "./views/layouts/",
partialsDir: "./views/parials/",
extname: "hbs"
}));
app.set("view engine", "hbs");
// Middleware
app.use(logger("dev"));
app.use(compression());
app.use(express.json());
app.use(express.urlencoded({extended: false}));
app.use(cookieParser());
app.use(session({
secret: "replace with env secret",
resave: false,
saveUninitialized: true,
cookie: {secure: true}
}));
app.use(passport.initialize());
app.use(passport.session());
app.use(cors());
app.use(flash());
this is my setup passport file
const pprt = require("passport");
const { Strategy, Scope } = require("#oauth-everything/passport-discord");
const User = require("../models/user");
/**
* #param {pprt} passport
*/
module.exports = (passport) => {
passport.serializeUser((user, done) => {
return done(null, user.id);
});
passport.deserializeUser(async (id, done) => {
User.findById(id, (err, res) => {
if (err) return done(err);
return done(null, res);
});
});
passport.use(new Strategy(
{
clientID: "no",
clientSecret: "no way",
callbackURL: "http://localhost:3000/login/auth/callback",
scope: [Scope.EMAIL, Scope.IDENTIFY]
},
(accessToken, refreshToken, profile, cb) => {
User.findOne({user_id: profile.id}, (err, res) => {
if (err) return cb(err);
if (!res) {
let newUser = new User({
user_id: profile.id,
username: profile.username,
displayName: profile.displayName,
email: profile.emails[0].value,
verified: profile.emails[0].verified,
tokens: {
access: accessToken,
refresh: refreshToken
}
});
newUser.save().then(user => {
cb(null, user);
});
} else {
res.updateOne({
user_id: profile.id,
username: profile.username,
displayName: profile.displayName,
email: profile.emails[0].value,
verified: profile.emails[0].verified,
tokens: {
access: accessToken,
refresh: refreshToken
}
}, (err, user) => {
if (err) return cb(err);
cb(null, user);
});
}
});
}
));
};
as i said req.user still returns undefined even after successful authentication does anyone have any idea why?
I should also mention that the user object is saved to mongodb perfectly which is why this perplexes me so much.