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.
Related
I am new to the Passport.js. Whenever I login or register through the routes, req.isAuthenticated() always returns false and the secrets view is never rendered. Here is my app.js:
`
require("dotenv").config();
const express = require("express");
const bodyParser = require("body-parser");
const session = require("express-session");
const passport = require("passport");
const LocalStrategy = require("passport-local")
const passportLocalMongoose = require("passport-local-mongoose");
const mongoose = require("mongoose");
mongoose.set("strictQuery", true);
uri = "mongodb://localhost:27017/usersDB";
const userSchema = new mongoose.Schema({
username: String,
password: String
});
userSchema.plugin(passportLocalMongoose);
const User = new mongoose.model("User", userSchema);
passport.use(new LocalStrategy(User.authenticate()));
passport.serializeUser(User.serializeUser());
passport.deserializeUser(User.deserializeUser());
const app = express();
app.use(bodyParser.urlencoded({extended: true}));
app.use(express.static("public"));
app.set("view engine", "ejs");
app.use(session({
secret: "MyLittleSecret",
resave: false,
saveUninitialized: false
}));
app.use(passport.initialize());
app.use(passport.session());
app.get("/", function(req, res) {
res.render("home");
});
app.get("/secrets", function(req, res) {
if(req.isAuthenticated) {
res.render("secrets");
} else {
res.redirect("/login");
}
});
app.route("/register")
.get(function(req, res) {
res.render("register");
})
.post(async function(req, res) {
await User.register({username: req.body.username}, req.body.password, function(err, user) {
console.log("In the User.register callback function");
if(err) {
console.log(err);
res.redirect("/register");
} else {
passport.authenticate("local")(req, res, function() {
res.redirect("/secrets");
});
}
});
});
app.route("/login")
.get(function(req, res) {
res.render("login",{
errorMessage: ""
});
})
.post(async function(req, res) {
const userInstance = new User({
username: req.body.username,
password: req.body.password
});
req.login(userInstance, 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 listening to port 3000");
});
I searched on the web and tried the various orders of middleware. I could not solve the problem.
I'm working through a learning module on authentication and security and I'm trying to get passport up and running but I seem to be having trouble. The code included below all works as you'd expect, except that when users are redirected from the /register post route to the /secrets route, they are not authenticated, in spite of .register() having worked (otherwise the logic in the route would have redirected me back to the /register get route instead of the login page via the secrets route).
require("dotenv").config();
const express = require("express");
const bodyParser = require("body-parser");
const mongoose = require("mongoose");
const ejs = require("ejs");
const session = require("express-session");
const passport = require("passport");
const passportLocalMongoose = require("passport-local-mongoose");
const app = express();
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.use(express.static("public"));
app.set("view engine", "ejs");
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 });
mongoose.set("useCreateIndex", true);
const userSchema = new mongoose.Schema({
username: String,
password: String
});
userSchema.plugin(passportLocalMongoose);
const Users = new mongoose.model("Users", userSchema);
passport.serializeUser(Users.serializeUser());
passport.deserializeUser(Users.deserializeUser());
app.listen(3000, (req, res) => {
console.log("Listening on port 3000.");
});
app.get("/", (req, res) => {
res.render("home");
});
app.get("/login", (req, res) => {
res.render("login");
});
app.get("/register", (req, res) => {
res.render("register");
});
app.get("/secrets", (req, res) => {
console.log(req.isAuthenticated())
if (req.isAuthenticated()) {
res.render("secrets");
} else {
res.redirect("/login");
}
});
app.post("/register", (req, res) => {
console.log(req.body.username)
console.log(req.body.password)
Users.register(
{ username: req.body.username },
req.body.password,
(error, user) => {
if (error) {
console.log('there was an error: ', error);
res.redirect("/register");
} else {
passport.authenticate("local")(req, res, () => { //////////////not authenticating
res.redirect("/secrets");
});
}
}
);
});
app.post("/login", (req, res) => {});
any help figuring out why isAuthenticaed() is returning false would be greatly appreciated. thank you :)
You have to define your local strategy :
var passport = require('passport')
, LocalStrategy = require('passport-local').Strategy;
passport.use(new LocalStrategy(
function(username, password, done) {
User.findOne({ username: username }, function (err, user) {
if (err) { return done(err); }
if (!user) {
return done(null, false, { message: 'Incorrect username.' });
}
if (!user.validPassword(password)) {
return done(null, false, { message: 'Incorrect password.' });
}
return done(null, user);
});
}
));
here it has queried User information from the database ( Mongodb for instance) in case of successful response it will pass.
I am currently creating a small user authentication app using Node + Express + Passport. When the user logs in, they are rerouted automatically to the index page "/" and a session should be established with passports authentication. For some reason when trying to console.log(req.user), it is returning "undefined".
The authentication with passport seems to be working properly with the post route
app.post("/login", passport.authenticate("local", {
successRedirect: "/home",
failureRedirect: "/login"
}), (req, res) => {
})
But the session is not being established with the user model. I'd like to eventually store the userId in the session. Here is a look at my current set up with user model and passport implementation on the server file.
const mongoose = require("mongoose");
const passportLocalMongoose = require('passport-local-mongoose');
const userSchema = mongoose.Schema({
username: String,
email: String,
password: String
});
userSchema.plugin(passportLocalMongoose);
const user = mongoose.model("User", userSchema);
module.exports = user;
-----------------------------------------------------------------------------------------
const express = require("express"),
mongoose = require("mongoose"),
bodyParser = require("body-parser"),
session = require("express-session"),
User = require("./models/user"),
passport = require('passport'),
LocalStragety = require('passport-local'),
app = express();
mongoose.connect("mongodb://localhost/shopping_cart_app", { useNewUrlParser: true })
.then(console.log("MongoDB Connected"))
.catch(err => console.log(err));
app.set("view engine", "ejs");
app.use(bodyParser.urlencoded({ extended: true }));
app.use(express.static(__dirname + '/views'));
app.use(session({
secret: "secret",
resave: false,
saveUninitialized: true,
cookie: { secure: true }
}));
app.use(passport.initialize());
app.use(passport.session());
passport.use(new LocalStragety(User.authenticate()));
passport.serializeUser(User.serializeUser());
passport.deserializeUser(User.deserializeUser());
app.post("/login", passport.authenticate("local", {
successRedirect: "/home",
failureRedirect: "/login"
}), (req, res) => {
})
I've tried looking into Passports config a bit more but on the documentation provided, it states that once passport.authenticate runs, a session with the user is established. Any tips would be greatly appreciate.
Thanks
I know this may seem simple, but have you tried req.body.user?
The req.body contains the data submitted by the user. The documentation suggest that you use a body parser to populate the information because it's undefined by default. However, instead of using the app object I use express router without parsing.
const express = require("express");
const router = express.Router();
router.post("/login", passport.authenticate("local", {
successRedirect: "/home",
failureRedirect: "/login"
}), (req, res) => {
console.log(req.body.user);
})
for more information: req.body
Try this one, In my project, it is working.
LocalStrategy
var passport = require('passport'),
LocalStrategy = require('passport-local').Strategy;
var mongoose = require('mongoose');
var admins = mongoose.model('admins');
var bCrypt = require('bcrypt-nodejs');
var flash = require('connect-flash');
var moment = require('moment');
// User
passport.serializeUser(function(user, done) {
done(null, user._id);
});
passport.deserializeUser(function(obj, done) {
console.log("deserializing " + obj);
done(null, obj);
});
passport.use('adminlogin',new LocalStrategy(
function(username, password, done) {
admins.findOne({ 'email' : username },
function(err, user) {
//console.log(username);
if (err)
return done(err);
if (!user){
//console.log('Username '+username+' does not Exist. Pleasr try again.');
return done(null, false, { message: 'Incorrect Username/Password. Please try again.' });
}
if (!isValidPasswordAdmin(user, password)){
//console.log('Invalid Password');
return done(null, false, { message: 'Incorrect Password. Please try again.' });
}
return done(null, user);
}
);
})
);
var isValidPassword = function(user, app_pin){
return bCrypt.compareSync(app_pin, user.app_pin);
}
var isValidPasswordAdmin = function(user, password){
return bCrypt.compareSync(password, user.password);
}
module.exports = passport;
Login Route
router.post('/login', function (req, res, next) {
admins.find({}, function (err, user) {
if (err) {
console.log('internal database error');
req.flash('error', 'Database Error');
res.redirect('/admins');
} else {
passport.authenticate('adminlogin', function (err, user, info) {
if (err) {
console.log(err);
req.flash('error', 'Database Error');
res.redirect('/admins');
} else if (!user) {
req.flash('error', info.message);
res.redirect('/admins');
} else {
req.logIn(user, function (err) {
if (err) {
req.flash('error', 'Database Error');
res.redirect('/admins');
} else {
res.redirect('/admins/home');
}
});
}
})(req, res, next);
}
});
});
I'm a hobbyist coder, and I can usually solve errors with lots of searches, but this one I can't get it right.
when I hit my logout route it throws an error: Cast to ObjectId failed for value "logout" at path "_id" for model "Spot"
I tried mongoose version 4.7.2, it's not working. I can't imagine why is it associating my logout route with the spot model at all.
my app.js
var express = require("express"),
bodyParser = require("body-parser"),
mongoose = require("mongoose"),
passport = require("passport"),
passportFacebook = require("passport-facebook").Strategy,
User = require("./models/user.js"),
Spot = require("./models/spot.js");
mongoose.connect("mongodb://localhost/biketrialspots", { useNewUrlParser: true });
var app = express();
app.set("view engine","ejs");
app.use(bodyParser.urlencoded({extended:true}));
app.use(express.static('public'));
app.use(require("express-session")({
secret: "some secret",
resave: false,
saveUninitialized: false
}));
app.use(passport.initialize());
app.use(passport.session());
app.use(function(req, res, next){
res.locals.currentUser = req.user;
next();
});
passport.use(new passportFacebook({
clientID: "some id",
clientSecret: "some secret",
callbackURL: "somewebsite/auth/facebook/callback",
profileFields: ['id', 'displayName', 'picture.type(large)']
}, function(accessToken, refreshToken, profile, done) {
User.findOrCreate(profile, function(err, user) {
if (err)
{ return done(err); }
done(null, user);
});
}
));
passport.serializeUser(function(user, done) {
done(null, user._id);
});
passport.deserializeUser(function(id, done) {
User.findById(id, function(err, user) {
done(err, user);
});
});
app.get("/", function(req, res){
Spot.find({}, function(err, spots){
if(err){
console.log(err);
} else{
res.render("index", {spots:spots});
}
});
});
app.get("/new", ensureAuthenticated, function(req, res){
res.render("new");
});
app.post("/", function(req, res){
Spot.create(req.body.spot, function(err, result){
if(err){
console.log(err);
} else{
res.redirect("/");
}
});
});
app.get("/:id", function(req, res){
Spot.findById(req.params.id, function(err, spot){
if(err){
console.log(err);
} else{
res.render("spot", {spot: spot});
}
});
});
// Redirect the user to Facebook for authentication. When complete,
// Facebook will redirect the user back to the application at
// /auth/facebook/callback
app.get('/auth/facebook', passport.authenticate('facebook'));
// Facebook will redirect the user to this URL after approval. Finish the
// authentication process by attempting to obtain an access token. If
// access was granted, the user will be logged in. Otherwise,
// authentication has failed.
app.get('/auth/facebook/callback',
passport.authenticate('facebook', { successRedirect: '/',
failureRedirect: '/login' }));
app.get("/logout", function(req, res){
req.user.logout();
res.redirect('/');
});
function ensureAuthenticated(req, res, next) {
if (req.isAuthenticated()) { return next(); }
return res.redirect('/');
}
app.listen(process.env.PORT, process.env.IP, function(req, res){
console.log("APP HAS STARTED!!!!!");
});
user model
var mongoose = require("mongoose");
var userSchema = new mongoose.Schema({
facebookID:Number,
username:String,
photo:String
});
userSchema.statics.findOrCreate = function findOrCreate(profile, cb){
var userObj = new this();
this.findOne({facebookID : profile.id},function(err,result){
if(!result){
userObj.facebookID = profile.id;
userObj.username = profile.displayName;
userObj.photo = profile.photos[0].value;
userObj.save(cb);
} else{
cb(err,result);
}
});
};
module.exports = mongoose.model("User", userSchema);
Thank you
Because app.get("/:id", ...) is written before app.get("/logout", ...) in your code, I guess the request handler of /:id would be called when you get /logout. Then, req.params.id becomes "logout" and the error is thrown by Spot.findById().
How about trying to write app.get("/logout", ...) before app.get("/:id", ...)?
I've been trying to understand why I couldn't keep an user logged in once authenticated even though authentication itself was working. I even posted a question here: Passport.js - Local strategy doesn't authenticate
By trying to fix the issue, I finally worked out what's wrong.
The issue is the following: I have two different passport strategy, so I am serializing and deserializing the user twice. If I serialize the user with the local strategy first, local strategy will work, but Google's won't. And vice versa.
I put a comment to highlight the problem in app.js.
Here's the files:
app.js
const express = require("express"),
mongoose = require("mongoose"),
bodyParser = require("body-parser"),
cookieSession = require("cookie-session"),
localStrategy = require("passport-local"),
passport = require("passport");
const LocalUser = require("./models/localuser");
const keys = require("./config/keys"); // requiring keys
const authRoutes = require("./routes/auth"); // requiring auth routes
const mainRoutes = require("./routes/main");
//Initialize express app
const app = express();
mongoose.connect("mongodb://localhost/thoughtApp"); // connectiong database
app.use(express.static(__dirname + "/public"));
app.set("view engine", "ejs");
app.use(bodyParser.urlencoded({extended: true}));
app.use(cookieSession({
maxAge: 24 * 60 * 60 * 1000,
keys: [keys.session.cookieKey]
}));
//initialize passport
app.use(passport.initialize());
app.use(passport.session());
passport.use(new localStrategy(LocalUser.authenticate()));
passport.serializeUser(LocalUser.serializeUser());
passport.deserializeUser(LocalUser.deserializeUser());
app.use(function(req, res, next){
res.locals.user = req.user;
next();
});
app.use("/", mainRoutes); //main routes
app.use("/auth", authRoutes); // setup auth routes
const passportSetup = require("./config/passport-setup"); /// THIS IS THE ISSUE
// IF BeFORE LINE 33 ( passport.use(new localStrategy(LocalUser.authenticate()));, GOOGLE LOGIN WORKS BUT LOCAL DOESNT; IF AFTER, LOCAL WORKS BUT GOOGE DOESN'T; PROBABLY DUE TO SERIALIZE AND DESARIALIZE BEING USED ALREADY
app.listen(process.env.PORT || 3000, () => {
console.log("Server started.")
});
auth.js (auth routes)
const router = require("express").Router();
const passport = require("passport");
const LocalUser = require("../models/localuser");
const authCheck = function (req, res, next) {
if (!req.user) {
next();
} else {
res.redirect("/");
}
};
//login
router.get("/login", authCheck, (req, res) => {
res.render("login", {user: req.user});
});
router.post("/login", passport.authenticate("local", {
successRedirect: "/",
failureRedirect: "/login"
}), (req, res) => {
})
// logout
router.get("/logout", (req, res) => {
//handle with passport
req.logout();
res.redirect("/");
});
//register
router.get("/signup", authCheck, (req, res) => {
res.render("signup", {user: req.user});
});
router.post("/signup", (req, res) => {
LocalUser.register(new LocalUser({username: req.body.username}), req.body.password, (err, user) => {
if (err) {
console.log(err);
res.redirect("/auth/signup")
}
passport.authenticate("local")(req, res, () => {
console.log(user)
res.redirect("/");
})
})
})
// google auth
router.get("/google", authCheck, passport.authenticate("google", {
scope: ["profile"]
}))
//goes to google consent screen
// callback for google to redirect to
router.get("/google/redirect", passport.authenticate("google"), (req, res) => {
res.redirect("/profile");
});
module.exports = router;
passport-setup.js (google strategy setup)
const passport = require("passport");
const GoogleStrategy = require("passport-google-oauth20");
const keys = require("./keys");
const User = require("../models/user")
passport.serializeUser((user, done) => {
done(null, user.id);
});
passport.deserializeUser((id, done) => {
User.findById(id).then((user) => {
done(null, user);
});
});
passport.use(new GoogleStrategy({
//options for the google strategy
callbackURL: "/auth/google/redirect",
clientID : keys.google.clientID,
clientSecret : keys.google.clientSecret
}, (accessToken, refreshToken, profile, done) => {
//passport callback function
// check if user exists already
User.findOne({googleID: profile.id}).then((currentUser) => {
if (currentUser) {
console.log("user is: " + currentUser);
done(null, currentUser);
} else {
new User({
username: profile.displayName,
googleID: profile.id
}).save().then((newUser) => {
console.log("new user created: " + newUser);
done(null, newUser);
})
}
})
})
)
localuser.js
const mongoose = require("mongoose");
const passportLocalMongoose = require("passport-local-mongoose");
const localUserSchema = new mongoose.Schema({
username: String,
password: String
});
localUserSchema.plugin(passportLocalMongoose);
module.exports = mongoose.model("localUser", localUserSchema);
How can I solve this?
So I have been struggling with the same and I don't know if you found a solution but I stumbled upon this link,
Linking all accounts together
So basically, you first need to check is in the request is req.user exists, if so add the fields you want to serialize and call done(null,newUser)
This should do the trick,
I hope i was clear enough