Node.js, express, passport authentication "Bad Request" - javascript

I'm using Cloud 9 to setup a basic social media website and I am having trouble with registration and authentication of users. I'm using Node.js, express and passport for authentication, and mongoDB as a database.
// PASSPORT Setup //
app.use(require("express-session")({
secret: "I am the best",
resave: false,
saveUninitialized: false
}));
app.use(passport.initialize());
app.use(passport.session());
passport.use(new LocalStrategy(User.authenticate()));
passport.serializeUser(User.serializeUser());
passport.deserializeUser(User.deserializeUser());
// INDEX Page
app.get("/", function(req, res) {
res.render("landing-page");
});
// REGISTER NEW
app.get("/register", function(req, res) {
res.render("user/register");
});
// REGISTER CREATE
app.post("/register", function(req, res) {
var user = req.body.user;
var newUser = new User({
username: user.email,
firstName: user.firstName,
lastName: user.lastName,
});
User.register(newUser, user.password, function(err, user) {
if(err) {
console.log(err);
return res.render("user/register");
}
passport.authenticate("local")(req, res, function() {
res.redirect("/");
});
});
});
// Login routes
app.get("/login", function(req, res) {
res.render("login");
});
app.post("/login", passport.authenticate("local", {
successRedirect: "/",
failureRedirect: "/login"
}) , function(req, res) {
});
// Logout route
app.get("/logout", function(req, res) {
req.logout();
res.redirect("/");
});
However whenever I run this, when I sign up a new user, it gives me a webpage with just "Bad Request", however the user is created in the database.

Look at this answer; the bad request is not a problem with your passport method: that indicates the request you try to make is not correct:
Did you set the head at: Content-Type: application-json?
Also update the bodyParser to the last version. This solved a similar problem I had.

Related

My code for Authentification on Google is giving me the error ReferenceError: id is not defined

So this is my code that is giving me problems with the authentification. I dont know how to get the id since is already created.
require('dotenv').config()
const express = require ("express");
const bodyParser = require ("body-parser");
const ejs = require ("ejs");
const mongoose = require ("mongoose")
const md5 = require ("md5");
const saltRounds = 10;
var bcrypt = require('bcryptjs');
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(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});
const userSchema = new mongoose.Schema({
email: String,
password: String,
googleID: 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",
},
function(accessToken, refreshToken, profile, cb) {
console.log(profile);
User.findOrCreate({ googleId: profile.id }, function (err, user) {
return cb(err, user);
});
}
));
app.use(express.static("public"));
app.set("view engine", "ejs");
app.use (bodyParser.urlencoded({
extended:true
}));
app.get ("/", function (req, res) {
res.render("home");
});
app.get('/auth/google',
passport.authenticate('google', {scope: ['profile', 'email']})
);
app.get('/auth/google/callback',
passport.authenticate('google', {
successRedirect: '/profile',
failureRedirect: '/fail'
})
);
app.get('/auth/google/secrets',
passport.authenticate('google', { 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");
});
app.get("/secrets", function (req,res) {
if (req.isAuthenticated()){
res.render("secrets");
}else {
res.rendirect("/login");
}
})
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.authenticated("local")(req,res, function() {
res.redirect("/secrets");
});
}
});
});
app.listen(3000, function() {
console.log("Server started on port 3000")
});
So when Im trying to run my code but the same error appears all the time in my system.
ReferenceError: id is not defined
at /Users/vivianaandrango/Desktop/Alberto/Secrets code/app.js:55:20
at pass (/Users/vivianaandrango/Desktop/Alberto/Secrets code/node_modules/passport/lib/authenticator.js:291:9)
at Authenticator.serializeUser (/Users/vivianaandrango/Desktop/Alberto/Secrets code/node_modules/passport/lib/authenticator.js:296:5)
at SessionManager.logIn (/Users/vivianaandrango/Desktop/Alberto/Secrets code/node_modules/passport/lib/sessionmanager.js:14:8)
at IncomingMessage.req.login.req.logIn (/Users/vivianaandrango/Desktop/Alberto/Secrets code/node_modules/passport/lib/http/request.js:39:26)
at Strategy.strategy.success (/Users/vivianaandrango/Desktop/Alberto/Secrets code/node_modules/passport/lib/middleware/authenticate.js:256:13)
at verified (/Users/vivianaandrango/Desktop/Alberto/Secrets code/node_modules/passport-oauth2/lib/strategy.js:189:20)
at /Users/vivianaandrango/Desktop/Alberto/Secrets code/app.js:73:14
at /Users/vivianaandrango/Desktop/Alberto/Secrets code/node_modules/mongoose-findorcreate/index.js:47:11
at /Users/vivianaandrango/Desktop/Alberto/Secrets code/node_modules/mongoose/lib/model.js:4999:1
UPDATE
When I add to the code
passport.serializeUser(function(user, done, id) {
done(null, user, id);
});
The system gives me back all my data but on Hyper I get all the information.

Passport Google Oauth does not redirect to successful route upon login

I'm trying to follow this tutorial to set up Google Oauth in my Express app using Passport.js.
Here are my routes, defined in a server.js file:
const passport = require("passport");
const express = require("express");
const app = express();
const cors = require("cors");
const bodyParser = require("body-parser");
const cookieSession = require("cookie-session");
require("./passport-setup");
app.use(cors());
// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.use(
cookieSession({
name: "tuto-session",
keys: ["key1", "key2"],
})
);
app.use(passport.initialize()); //initialises passport js and auth process
app.use(passport.session()); //manage using sessions
const isLoggedIn = (req, res, next) => {
if (req.user) {
next();
} else {
res.sendStatus(401);
}
};
app.get("/", (req, res) => res.send("Hello World! You're not logged in "));
// 1. You send your users to /google. This opens a google page, in passport-setup.js.
app.get(
"/google",
passport.authenticate("google", {
scope: ["profile", "email"],
})
);
app.get("auth/google/callback",
passport.authenticate("google", {
successRedirect: '/good',
failureRedirect: "/failed"
}),
function (req, res) {
res.redirect("http://localhost:19006/good");
}
);
app.get("/failed", (req, res) => res.send("You failed to log in!"));
app.get("/good", isLoggedIn, (req, res) =>
res.send(`You logged in! Welcome ${req.user.email}`)
);
app.get("/logout", (req, res) => {
req.session = null; // destroy session
req.logout(); //logout from passport
res.redirect("/"); //redirect to home.
});
app.listen(19006, () => console.log("Listening on port"));
server.js also imports passport-setup.js, where I stored the following configurations:
const passport = require('passport')
const GoogleStrategy = require('passport-google-oauth20').Strategy
// it will take the user, and take user.id. This makes the user smaller. Each time I'm directed to a route, will take the cookie in the session, go to deserializeUser
passport.serializeUser(function (user, done) {
console.log("serialise user")
done(null, user)
})
// this function takes the id, returns the user object.
passport.deserializeUser(function (user, done) {
console.log("deserialise user")
//User.findById(id, function (err, user) {
done(null, user)
//})
// so we will have the user in req.user. But for the purpose of this tutorial, no db.
})
// this /google page will take clientID, client secret to authenticate.
passport.use(new GoogleStrategy({
clientID: 'MY_CLIENT_ID',
clientSecret: 'MY_CLIENT_SECRET',
callbackURL: "http://localhost:19006/auth/google/callback",
passReqToCallback: true,
},
function (accessToken, refreshToken, profile, done) {
return done(null, profile)
}
))
When I start up my app, I go to localhost:19006/google, which redirects me to the Google Oauth's login page. However I get redirected to this link: http://localhost:19006/auth/google/callback?code=4%2F3AGyrRpoCivQNr2-7sXZDQETVzNi9JvxaOORhTmaAZoQjIHNPAf8nWqgBFkzrVprwhUF4qMo40ljxiGZLsBLn7U&scope=email+profile+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.profile+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email+openid&authuser=0&prompt=consent#
I also get a 404 error code, with the page showing "Cannot GET /auth/google/callback".
I checked the express routes and I have defined that route, so I don't get why the app is not showing this page.
I tried adding console.log messages to the following function:
// this /google page will take clientID, client secret to authenticate.
passport.use(new GoogleStrategy({
clientID: 'MY_CLIENT_ID',
clientSecret: 'MY_CLIENT_SECRET',
callbackURL: "http://localhost:19006/auth/google/callback",
passReqToCallback: true,
},
function (accessToken, refreshToken, profile, done) {
//added a console.log here
return done(null, profile)
}
app.get("/", (req, res) => res.send("Hello World! You're not logged in "));
// 1. You send your users to /google. This opens a google page, in passport-setup.js.
app.get(
"/google",
passport.authenticate("google", {
scope: ["profile", "email"],
})
);
app.get("auth/google/callback",
passport.authenticate("google", {
successRedirect: '/good',
failureRedirect: "/failed"
}),
function (req, res) {
// added console.log here
res.redirect("http://localhost:19006/good");
}
);
But my console did not end up logging anything.
What I have tried
In Google Developer Console, I set up the Client ID for web application with the following fields:
Image of credentials
I have tried replacing localhost with 127.0.0.1 in both the routes in my code and the Google Developer Screen, but it doesn't work.
You missed "/"
app.get("/auth/google/callback",
passport.authenticate("google", {
successRedirect: '/good',
failureRedirect: "/failed"
}),

How to flash a user's username after a successful login using Passport.js?

I am trying to flash the message "Welcome back "username here" " to a user once they have successuly logged in to the website.
The problem is that logging in with passport is not a regular request and response, the authentication happens as an argument to the post request. Below you can find my code:
var express = require("express");
var router = express.Router();
var user = require("../models/user");
var passport = require("passport");
router.get('/register', (req,res) =>{
res.render('register');
});
router.post('/register', (req,res) =>{
user.register(
new user({username: req.body.username}),
req.body.password,
(err, newUser) => {
if(err){
req.flash("error", err.message);
return res.redirect("/register");
}
passport.authenticate("local")(req, res, function(){
req.flash("success", "Successfully registered, welcome "+user.username.charAt(0).toUpperCase() + user.username.slice(1)+"!");
res.redirect("/");
});
}
);
});
router.get('/login', (req,res) =>{
res.render('login');
});
router.post('/login', passport.authenticate("local",{
successRedirect: "/",
failureRedirect: "/login",
failureFlash: true,
successFlash: 'Welcome back!'//HERE IS WHERE I AM INTERESTED
}), (req,res) =>{
});
router.get('/logout', (req,res) =>{
req.logout();
req.flash("success", "Successfully Logged Out")
res.redirect("/");
});
module.exports = router;
In the second argument to router.post, call passport.authenticate to handle the failureRedirect and failureFlash message. Then, for the third argument, write your callback function with req and res. In the body of this function is where you'll handle the "success" flash message and you'll have access to your username on the request object. And then you can do your res.redirect.
router.post(
"/login",
passport.authenticate("local", {
failureRedirect: "/login",
failureFlash: true
}),
(req,res) => {
req.flash("success", "Welcome back!"//add your username variable here);
res.redirect("/home");
});

React Router intercepting API call to Express server

I'm using React Router with Passport.js to set up Facebook login. I've set up the express routes and passport config, but every time I hit the
<a href="/api/auth/facebook"> link on my client side, it makes a request to RR because of my express app with this line:
app.get('/*', function(req, res) {
res.sendFile(path.resolve(__dirname, '../client', 'build', 'index.html'))
});
As I am making a call to the server side route, it returns this error:
Warning: [react-router] Location "/api/auth/facebook" did not match any routes
How can I bypass React Router for this one particular route?
my user_routes.js file looks like:
'user strict';
var bodyparser = require('body-parser');
var User = require('../models/User.js');
module.exports = function loadUserRoutes(router, passport) {
router.use(bodyparser.json());
router.get('/auth/facebook', passport.authenticate('facebook', {
session: false,
successRedirect: '/chat',
failureRedirect: '/'
}));
router.get('/auth/facebook/callback', passport.authenticate('facebook', {
session: false,
successRedirect: '/chat',
failureRedirect: '/'
}));
router.post('/sign_up', passport.authenticate('local-signup', { session: false}), function(req, res) {
res.json(req.user);
});
router.post('/sign_in', passport.authenticate('local-login', { session: false}), function(req, res) {
res.json(req.user);
});
router.get('/signout', function(req, res) {
req.logout();
res.end();
});
//get auth credentials from server
router.get('/load_auth_into_state', function(req, res) {
res.json(req.user);
});
// get usernames for validating whether a username is available
router.get('/all_usernames', function(req, res) {
User.find({'local.username': { $exists: true } }, {'local.username': 1, _id:0}, function(err, data) {
if(err) {
console.log(err);
return res.status(500).json({msg: 'internal server error'});
}
res.json(data);
});
})
};
In express routes are matches in the order they get defined.
So before your /* route you need something to handle api requests.
app.get('/api/auth/facebook', passport.authenticate('facebook'))
app.get('/*', function(req, res) {
res.sendFile(path.resolve(__dirname, '../client', 'build', 'index.html'))
});

how to place passport js configuration in a common file

I am using Passport js for authentication in my project. At server side i am using Express js. In app.js i have configuration for passport js and the code is:
passport.use(new Strategy({
passReqToCallback: true
},
function (req, username, password, done) {
req.models.users.find({ 'user_id' : username }, function (err, user) {
if (err) { return done(err); }
if (!user[0]) {
console.log("The username is Incorrect");
return done(null, false, { message: 'Incorrect username.' });
}
if (user[0].default_password!=password) {
console.log("The Password is Incorrect");
return done(null, false, { message: 'Incorrect password.' });
}
return done(null, user);
});
}
));
passport.serializeUser(function(user, done) {
done(null, user);
});
passport.deserializeUser(function(user, done) {
done(null, user);
});
and after this i am verifying the client request like this:
app.post('/login',
passport.authenticate('local', { failureRedirect: '/login' }),
function(req, res) {
res.redirect('/');
});
Till here everything is working fine.
Now i want to place this route app.post('/login',... in routes folder so i have given the path of the route in app.js like this:
var users = require('./routes/users/users');
app.use('/users', users);
My problem is: in this user route file i don't have passport configuration and i don't want to rewrite it again for all my other routes so i am thinking to place the passport configuration in a common file and reuse it but i don't know how to do it. If you have any idea please help. Thanks.
You can write a middleware, lets call it auth.js, that checks for session info and mount this for every route that you need.
'use strict';
const qs = require('querystring'),
router = require('express').Router();
router.use(function (req, res, next) {
// set this in res.locals
if (!req.user) {
return res.redirect('/?' + qs.stringify({
'r': req.originalUrl
}));
}
next();
});
module.exports = router;
If you use the above approach, you will need to add res.locals.user = req.user; in your server/app.js.
After this, you can require the above middleware on every route that needs to be authenticated.
router.verb('/path', require('./path-to-auth'));
router.verb('/path', (req, res, next) => {
// this route will only be executed if the user is authenticated
});

Categories