Related
I used postman to post to register a user with "http://localhost:3000/register?name=USER1&email=user1#testsite.com&password=pass1"
and seems like it doesn't get routed correctly. What could be the problem?
Errors: Postman shows Cannot POST /register.
Other than that, no errors, server runs ok in port 3000
App.js
require('dotenv').config();
const passport = require('passport');
require("./app_api/passport")
const path = require("path");
const express = require("express");
const bodyParser = require("body-parser");
const mongoose = require("mongoose");
const app = express();
const userRoutes = require("./app_api/routes/index");
mongoose
.connect(
"mongodb://127.0.0.1:27017"
, {useNewUrlParser: true, useUnifiedTopology: true, useCreateIndex:true}
) .then(() => {
console.log("Connected to database!");
})
.catch(() => {
console.log("Connection failed!");
});
app.use(passport.initialize());
app.use((req, res, next) => {
res.setHeader("Access-Control-Allow-Origin", "*");
res.setHeader(
"Access-Control-Allow-Headers",
"Origin, X-Requested-With, Content-Type, Accept, Authorization"
);
res.setHeader(
"Access-Control-Allow-Methods",
"GET, POST, PATCH, PUT, DELETE, OPTIONS"
);
next();
});
app.use("/register", userRoutes);
module.exports = app;
./routes/index.js
const express = require("express");
const ctrlAuth = require("../../controllers/authentication");
const router = express.Router();
router.post('/register', function(req, res){ctrlAuth.register});
router.post('/login', function(req, res){ctrlAuth.login});
module.exports = router;
./controllers/authentication.js
const passport = require('passport');
const mongoose = require('mongoose');
const User = require('../schema/user');
const register = (req, res) => {
if (!req.body.name || !req.body.email || !req.body.password) {
return res
.status(400)
.json({"message": "All fields required"});
const user = new User();
user.name = req.body.name;
user.email = req.body.email;
user.setPassword(req.body.password);
user.save((err) => {
if (err) {
res
.status(404)
.json(err);
} else {
const token = user.generateJwt();
res
.status(200)
.json({
token
,message: "User created!"
});
}
});
};
module.exports = {
register
};
const login = (req, res) => {
if (!req.body.email || !req.body.password) {
return res
.status(400)
.json({"message": "All fields required"});
}
passport.authenticate('local', (err, user, info) => {
let token;
if (err) {
return res
.status(404)
.json(err);
}
if (user) {
token = user.generateJwt();
res
.status(200)
.json({token});
} else {
res
.status(401)
.json(info);
}
})(req, res);
};
module.exports = {
login
};
change ./controllers/authentication.js exports functions like this
const passport = require("passport");
const mongoose = require("mongoose");
const User = require("../schema/user");
const register = (req, res) => {
if (!req.body.name || !req.body.email || !req.body.password) {
return res.status(400).json({ message: "All fields required" });
}
const user = new User();
user.name = req.body.name;
user.email = req.body.email;
user.setPassword(req.body.password);
user.save((err) => {
if (err) {
res.status(404).json(err);
} else {
const token = user.generateJwt();
res.status(200).json({
token,
message: "User created!",
});
}
});
};
const login = (req, res) => {
if (!req.body.email || !req.body.password) {
return res.status(400).json({ message: "All fields required" });
}
passport.authenticate("local", (err, user, info) => {
let token;
if (err) {
return res.status(404).json(err);
}
if (user) {
token = user.generateJwt();
res.status(200).json({ token });
} else {
res.status(401).json(info);
}
})(req, res);
};
exports.register = register;
exports.login = login;
and change your App.js, remove /register from route
require('dotenv').config();
const passport = require('passport');
require("./app_api/passport")
const path = require("path");
const express = require("express");
const bodyParser = require("body-parser");
const mongoose = require("mongoose");
const app = express();
const userRoutes = require("./app_api/routes/index");
mongoose
.connect(
"mongodb://127.0.0.1:27017"
, {useNewUrlParser: true, useUnifiedTopology: true, useCreateIndex:true}
) .then(() => {
console.log("Connected to database!");
})
.catch(() => {
console.log("Connection failed!");
});
app.use(passport.initialize());
app.use((req, res, next) => {
res.setHeader("Access-Control-Allow-Origin", "*");
res.setHeader(
"Access-Control-Allow-Headers",
"Origin, X-Requested-With, Content-Type, Accept, Authorization"
);
res.setHeader(
"Access-Control-Allow-Methods",
"GET, POST, PATCH, PUT, DELETE, OPTIONS"
);
next();
});
app.use("/", userRoutes);
module.exports = app;
change router like this :
const express = require("express");
const ctrlAuth = require("../../controllers/authentication");
const router = express.Router();
router.post('/register', ctrlAuth.register);
router.post('/login', ctrlAuth.login);
module.exports = router;
when I pass name: req.user.name to my ejs file it gives me undefined, Can you help me with that please. let me know if you need more information if you need. I have tried a lot of ways but non of then have worked. thanks for the help.
Error:
Cannot read property 'name' of undefined when i call it in index.js
app.js
const express = require("express");
const expressLayouts = require('express-ejs-layouts');
const mongoose = require("mongoose");
const app = express();
const passport = require('passport');
const flash = require('connect-flash');
const session = require('express-session');
const PORT = process.env.PORT || 3000;
const nodemailer = require("nodemailer");
const bodyParser = require("body-parser");
var exphbs = require('express-handlebars');
app.engine('handlebars', exphbs());
app.set('view engine', 'handlebars');
app.use(bodyParser.urlencoded({ extended: true }));
app.use(express.static("public"));
app.get("/home", function(req, res) {
res.sendFile(__dirname + "/index.html")
})
app.get("/login", function(req, res) {
res.sendFile(__dirname + "/login.ejs")
})
app.get("/signup", function(req, res) {
res.sendFile(__dirname + "/register.html")
})
app.get("/payment", function(req, res) {
res.sendFile(__dirname + "/payment.html")
})
app.get("/companyInfo", function(req, res) {
res.sendFile(__dirname + "/companyInfo.html")
})
app.get("/FAQ", function(req, res) {
res.sendFile(__dirname + "/Faq.html")
})
app.get("/contactUs", function(req, res) {
res.sendFile(__dirname + "/contactUs.html")
})
app.post("/contactUs", function(req, res) {
const output = `
<h1>You have a new feedback</h1>
<ul>
<h3>Full Name: ${req.body.name}</h3>
<h3>Full Email: ${req.body.email}</h3>
<h3>Order Number: ${req.body.orderNumber}</h3>
</ul>
<h1>The Subject</h3>
<h3>${req.body.subject}</h1>
`;
var transporter = nodemailer.createTransport({
service: 'gmail',
auth: {
user: "sziacustomer#gmail.com",
pass: "Sziaszia12"
}
});
var mailOptions = {
from: req.body.email,
to: 'TEAMSZIA#GMAIL.COM',
subject: 'Costumers Email',
html: output
};
transporter.sendMail(mailOptions, function(error, info) {
if (error) {
console.log(error);
res.sendFile(__dirname + ("/failed.html"), { msg: "email sent" });
} else {
console.log('Email sent: ' + info.response);
res.sendFile(__dirname + ("/success.html"), { msg: "email sent" });
}
});
});
//bodyparser
app.use(express.urlencoded({ extended: false }))
const db = require("./config/keys").mongoURI;
require('./config/passport')(passport);
// Express session
app.use(
session({
secret: 'secret',
resave: true,
saveUninitialized: true
})
);
// Passport middleware
app.use(passport.initialize());
app.use(passport.session());
// connect flash
app.use(flash());
// Global variables
app.use(function(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();
});
//connect mangodb using mongoose
mongoose.connect(db, { useNewUrlParser: true, useUnifiedTopology: true })
.then(() => console.log("mongoo bd connected"))
.catch(() => console.log(err));
//ejs
app.use(expressLayouts);
app.set('view engine', 'ejs');
app.use("/", require("./routes/index"));
app.use("/dashboard", require("./routes/index"));
app.use("/users", require("./routes/users"))
app.listen(PORT, console.log(`we are live on ${PORT}`));
*
index.js*
const express = require("express");
const router = express.Router();
const mongoose = require("mongoose");
const bcrypt = require('bcryptjs');
const User = require('../models/User');
const users = require("./users");
const LocalStrategy = require('passport-local').Strategy;
const { ensureAuthenticated } = require("../config/auth")
router.get("/", users, (req, res) =>
res.render("welcome", {
login: req.isAuthenticated(),
name: req.user.name //undefined
}))
user.js
const express = require("express");
const router = express.Router();
const bcrypt = require("bcryptjs");
const User = require("../models/User");
const passport = require("passport")
router.get("/login", (req, res) => res.render("login"));
router.get("/register", (req, res) => res.render("register"));
router.post('/register', (req, res) => {
const { name, email, password, password2 } = req.body;
let errors = [];
if (!name || !email || !password || !password2) {
errors.push({ msg: 'Please enter all fields' });
}
if (password != password2) {
errors.push({ msg: 'Passwords do not match' });
}
if (password.length < 6) {
errors.push({ msg: 'Password must be at least 6 characters' });
}
if (errors.length > 0) {
res.render('register', {
errors,
name,
email,
password,
password2
});
} else {
User.findOne({ email: email }).then(user => {
if (user) {
errors.push({ msg: 'Email already exists' });
res.render('register', {
errors,
name,
email,
password,
password2
});
} else {
const newUser = new User({
name,
email,
password
});
bcrypt.genSalt(10, (err, salt) => {
bcrypt.hash(newUser.password, salt, (err, hash) => {
if (err) throw err;
newUser.password = hash;
newUser
.save()
.then(user => {
req.flash(
'success_msg',
'You are now registered and can log in'
);
res.redirect('/users/login');
})
.catch(err => console.log(err));
});
});
}
});
}
});
// Login
router.post('/login', (req, res, next) => {
passport.authenticate('local', {
successRedirect: '/',
failureRedirect: '/users/login',
failureFlash: true,
})(req, res, next);
});
// Logout
router.get('/logout', (req, res) => {
req.logout();
req.flash('success_msg', 'You are logged out');
res.redirect('/users/login');
});
module.exports = router;
passport.js
const LocalStrategy = require('passport-local').Strategy;
const bcrypt = require('bcryptjs');
// Load User model
const User = require('../models/User');
module.exports = function(passport) {
passport.use(
new LocalStrategy({ usernameField: 'email' }, (email, password, done) => {
// Match user
User.findOne({
email: email
}).then(user => {
if (!user) {
return done(null, false, { message: 'That email 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(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
User.findById(id, function(err, user) {
done(err, user);
});
});
}
auth.js
module.exports = {
ensureAuthenticated: function(req, res, next) {
if (req.isAuthenticated()) {
return next();
}
req.flash('error_msg', 'Please log in to view that resource');
res.redirect('/users/login');
},
forwardAuthenticated: function(req, res, next) {
if (!req.isAuthenticated()) {
return next();
}
res.redirect('/');
}
}
When I am trying to send POST request, it returns 404, although all routes is right.
I've rummaged through tons of similar questions but I didn't find anything that seems to solve my problem.
Here's a code:
App.js
const http = require('http');
const url = require('url');
const express = require('express');
const mongoose = require('mongoose');
const path = require('path');
const bodyParser = require('body-parser');
const passport = require('passport');
mongoose.connect('mongodb://localhost:27017/mydb');
let db = mongoose.connection;
db.once('open', () => {
console.log('Connected to Database');
});
db.on('error', (err) => {
console.log(err);
});
const server = express();
server.use(express.static('dist', { extensions: ['html'] }));
let users = require('./routes/users');
server.use(users);
server.use(function (req, res, next) {
res.status(404).sendFile(path.join(__dirname+'/dist/404.html'));
});
const port = process.env.port || 3000;
server.listen(port, () => {
console.log(`Server has been established on port ${port}`)
});
./models/user.js
const User = mongoose.Schema({
name: {
type: String,
required: true
},
lastname: {
type: String,
required: true
},
login: {
type: String,
required: true
},
password: {
type: String,
required: true
},
b_day: {
type: String,
required: true
},
b_month: {
type: String,
required: true
},
b_year: {
type: String,
required: true
},
gender: {
type: String,
required: true
}
});
const user = module.exports = mongoose.model('User', User);
./routes/users.js
const router = express.Router();
const bcrypt = require('bcryptjs');
const passport = require('passport');
let User = require('../models/user');
//Register Form
router.get('/signup', (req, res) => {
console.log(res);
res.render('signup');
});
//Register Process
router.post('signup', (req, res) => {
const name = req.body.name;
const lastname = req.body.lastname;
const login = req.body.login;
const password = req.body.password;
const password2 = req.body.repeat_password;
const b_day = req.body.b_day;
const b_month = req.body.b_month;
const b_year = req.body.b_year;
const gender = req.body.gender;
req.checkBody('name', 'Name is required').notEmpty();
req.checkBody('lastname', 'Lastname is required').notEmpty();
req.checkBody('login', 'Login is required').notEmpty();
req.checkBody('password', 'Password is required').notEmpty();
req.checkBody('password2', 'Passwords do not match').equals(req.body.password);
req.checkBody('b_day', 'Birth day is required').notEmpty();
req.checkBody('b_month', 'Birth month is required').notEmpty();
req.checkBody('b_year', 'Birth year is required').notEmpty();
req.checkBody('gender', 'Gender is required').notEmpty();
let errors = req.validationErrors();
if(errors) {
res.render('signup', {
errors:errors
});
} else {
let newUser = new User({
name:name,
lastname:lastname,
login:login,
password:password,
gender:gender,
b_day:b_day,
b_month:b_month,
b_year:b_year
});
bcrypt.genSalt(10, (err, salt) => {
bcrypt.hash(newUser.password, salt, (err, hash) => {
if(err) {
console.log(err);
}
newUser.password = hash;
newUser.save((err) => {
if(err) {
console.log(err);
return;
} else {
req.flash('success', 'You are now registered');
res.redirect('signin');
}
});
});
});
}
});
router.get('signin', (req, res) => {
res.render('signin');
});
router.post('signin', (req, res, next) => {
passport.authenticate('local', {
successRedirect:'profile',
failureRedirect:'signin',
failureFlash: true
})(req, res, next);
});
router.get('logout', (req, res) => {
res.render('logout');
req.flash('success', 'You are logged out');
res.redirect('signin');
});
module.exports = router;
And also project structure
├── dist
├── routes
│ └── users.js
├── models
│ └── user.js
└── app.js
I expect it will process all data from sign up form and then redirect to sign in page.
Your routes are correct. Error 404 only comes if a route is not found. In your case, its happening because you have not added "/" before calling signup(post request) and signin routes as well in users.js.
Right now your api url is becoming like this :
localhost:3000/userssignin
which should be :
localhost:3000/users/signin
So, your routes should be :
router.post('/signup', (req, res) => {
router.get('/signin', (req, res) => {
router.post('/signin', (req, res) => {
i don't know, but from a first view, i think that you are missing dash before routes
router.get('signin', (req, res) => { // '/singin'
res.render('signin');
});
router.post('signin', (req, res, next) => { // '/singin'
passport.authenticate('local', {
successRedirect:'profile',
failureRedirect:'signin',
failureFlash: true
})(req, res, next);
});
router.get('logout', (req, res) => { // '/logout'
res.render('logout');
req.flash('success', 'You are logged out');
res.redirect('signin');
});
I have been browsing the forum but I am unable to find the error in my code , it always results in false and I am not able to solve it , Please help me...
Is there any other way to authenticate user instead of passport so that I can use it.I am adding more sentences as it is not allowing me to post my query,Sorry..
const http = require("http"),
hostname = "127.0.0.1",
port = 3000,
bodyParser = require("body-parser"),
mongoose = require("mongoose"),
express = require("express"),
passport = require("passport"),
localStrategy = require("passport-local"),
passportLocalMongoose = require("passport-local-mongoose"),
User = require("./models/user");
app = express();
mongoose.connect("mongodb://localhost/drive", { useNewUrlParser: true });
app.set("view engine", "ejs");
app.use(express.static("public"));
app.use(passport.initialize());
app.use(passport.session());
app.use(
require("express-session")({
secret: "Beta tumse na ho payega",
resave: false,
saveUninitialized: false
})
);
passport.use(new localStrategy(User.authenticate()));
passport.serializeUser(User.serializeUser());
passport.deserializeUser(User.deserializeUser());
app.use(bodyParser.urlencoded({ extended: true }));
const server = http.createServer((req, res) => {
res.statusCode = 200;
res.setHeader("Content-Type", "text/plain");
});
app.get("/", function(req, res) {
res.render("index");
});
app.get("/register", function(req, res) {
res.send("hello");
});
app.get("/login", function(req, res) {
res.render("login");
});
app.post(
"/login",
passport.authenticate("local", {
successRedirect: "/",
failureRedirect: "/login"
}),
function(req, res) {}
);
app.get("/logout", function(req, res) {
req.logout();
res.redirect("/");
});
function isLoggedIn(req, res, next) {
if (req.isAuthenticated()) {
return next();
} else {
console.log("Not logged");
res.redirect("/login");
}
}
app.get("/secret", isLoggedIn, function(req, res) {
res.send("You are logged in");
});
app.post("/register", function(req, res) {
if (req.body.password === req.body.cpassword) {
User.register(
new User({ username: req.body.username }),
req.body.password,
function(err, user) {
if (err) console.log(err);
else
passport.authenticate("local")(req, res, function() {
res.send("signed up");
});
}
);
} else res.send("Password Mismatch");
});
//DRIVE SCHEMA
//var driveSchema = mongoose.Schema({
// title: String,
// created: { type: Date, default: Date.now }
//});
app.listen(port, hostname, function() {
console.log("Server is running at " + hostname + "/" + port);
});
//./models/user.js file
const mongoose = require("mongoose"),
passportLocalMongoose = require("passport-local-mongoose");
var UserSchema = new mongoose.Schema({
username: String,
password: String
});
UserSchema.plugin(passportLocalMongoose);
module.exports = mongoose.model("User", UserSchema);
I have used passport and jwt library, to authenticate and maintain session for the user. There is no need to maintain user session on server side.
apis/apis.js : This file has all apis end points. /login url will authenticate user using passport and send a token to the client using jwt
const passport = require('passport')
const expRoute = require('express').Router();
let exporter = process.exporter;
expRoute.post('/login', (req, res, next) => {
passport.authenticate(
'local',
{
// successRedirect: '/',
// failureRedirect: '/login',
successFlash: 'Welcome!',
failureFlash: 'Invalid username or password.'
},
(err, user, info) => {
if (err) {
return res.status(500).json(err)
}
else if (user) {
return res.status(200).json({
token: exporter.generateToken(user)
})
}
else {
return res.status(400).json(info)
}
}
)(req, res, next);
})
expRoute.get('/view', exporter.authenticateToken, (req, res) => {
let param = req.finalTokenExtractedData
if (param && exporter.isObjectValid(param, 'tokenId', true, true)) {
let condition = {
_id: param.tokenId
}
let options = {
_id: 0,
password: 0,
__v: 0
}
process.USER.findOne(condition, options) // mongo find
.then((data) => {
res.status(200).json({
result: data,
msg: 'success'
})
})
.catch((mongoErr) => {
exporter.logNow(`USER mongo Error: ${mongoErr}`)
res.status(400).json({
msg: 'user not found'
})
})
}
else {
res.status(404).json({
msg: 'invalid token'
})
}
})
module.exports = expRoute
common/env.js: This file will initialise all connections such mongo, require few files will be used as global
process.CONFIG = require('../configs/config.json')
process.exporter = require("../lib/exporter.js")
process.dbInit = (globalName, mongoUrl, collectionName) => {
require("../models/db-init.js")(mongoUrl, collectionName)
.then((modelObj) => {
process[globalName] = modelObj // will be used as global
})
.catch((dbInitErr) => {
process.exporter.logNow(`dbInit Error: ${dbInitErr}`)
process.exit()
});
}
lib/exporter.js: This file has exporter class which consist of all major functions like mongo connection, authenticateToken, verifyPassword, etc.
const fs = require('fs'),
redis = require("redis"),
path = require("path"),
mongoose = require('mongoose'); mongoose.set('useCreateIndex', true);
const Schema = mongoose.Schema;
var bcrypt = require('bcryptjs')
var jwt = require('jsonwebtoken')
class Exporter {
mongoConnection(mongoURI, schemaObj) {
return new Promise(async (resolve, reject) => {
if (!mongoURI || typeof mongoURI == 'undefined' || mongoURI.length < 1)
return reject('invalid mongo connection url');
return resolve(mongoose.createConnection(mongoURI, { useNewUrlParser: true }))
})
}
createMongoSchema(schemaObj) {
return (new Schema(schemaObj));
}
createMongoModel(mongoDB, collectionName, newSchema) {
if (newSchema)
return mongoDB.model(collectionName, newSchema)
return mongoDB.model(collectionName)
}
authenticateToken(req, res, next) {
const bearerHeader = req.header('authorization')
if (typeof bearerHeader != 'undefined') {
const bearer = bearerHeader.split(' ')
const bearerToken = bearer[1]
jwt.verify(bearerToken, process.CONFIG.jwt.token.activated, (err, data) => {
if (err)
res.status(400).json({
msg: "Invalid token or please try to login again"
})
else {
process.exporter.getSingleHashKeysValuesFromRedis('expired_token', bearerToken)
.then((redisTokendata) => {
if (redisTokendata)
res.status(400).json({
msg: "token expired"
})
else {
req.finalTokenExtractedData = data
// if (req.originalUrl.trim() == process.logoutURL.trim())
req.jwtToken = {
token: bearerToken,
secret: process.CONFIG.jwt.token.activated
}
next()
}
})
.catch((redisTokenError) => {
process.exporter.logNow(`redis token error: ${redisTokenError}`)
res.status(400).json({
msg: "Some went wrong while checking token. Please try later."
})
})
}
})
}
else
res.status(400).json({
msg: "invalid token"
})
}
generateToken(data) {
let expiry = new Date();
// expiry.setDate(expiry.getDate() + 7)
expiry.setMinutes(expiry.getMinutes() + 5)
return jwt.sign({
tokenId: data._id,
exp: parseInt(expiry.getTime() / 1000),
}, process.CONFIG.jwt.token.activated)
}
createPassword(password) {
return new Promise((resolve, reject) => {
if (typeof password == 'undefined' && password == '')
return reject('password empty')
bcrypt.hash(password, 10, async (bErr, hash) => {
if (bErr)
reject(bErr)
else
resolve(hash)
})
})
}
verifyPassword(enteredPassword, savePassword) {
return bcrypt.compareSync(enteredPassword, savePassword)
}
}
module.exports = (new Exporter());
index.js: This is file which you will execute node index.js.
const express = require('express');
const path = require('path');
const bodyParser = require('body-parser');
const passport = require('passport');
require('./common/env')
require('./configs/passport')
const app = express()
const cors = require('cors')
app.use(cors());
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({ extended: true}))
app.use(passport.initialize())
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
next();
});
let apis = require('./apis/api')
app.use('/user', apis)
/**
* 404 Handler
*/
app.use((req, res, next)=>{
return res.status(404).send("Endpoint "+req.url +" not found");
})
/**
* if any error or exception occurred then write into a JS file so that app can be restarted
*/
process.on('uncaughtException', (err) => {
console.error(err.stack);
});
app.listen(3000, function(server) {
console.log("App listening at 3000");
});
When index.js file has been executed successfully and listening to a port 3000, then use this URL http://localhost:3000/user/login for authentication, it will accept your username and password, then authenticate using passport and send a token to the client as response. The token can contain user data in encrypted form and have expiry time.
Reference link: https://github.com/arjun-707/login-logout-jwt-nodejs
You need the express-session module.
server.js
// Require a possible config.js file with your configuration variables
const Config = require('./models/config.js');
// If the config module is formed as a class
const config = new Config();
const express = new('express');
const app = express();
const session = require('express-session');
const MongoStore = require('connect-mongo')(session);
const uuid = require('uuid/v4');
const mongoose = require('mongoose');
// Require your custom passport local strategy file
const passport = require('./models/sessions');
mongoose.connect('mongodb://localhost:27017/your_db_name', {
useNewUrlParser: true
});
// Set the session options
app.use(session({
// Use UUIDs for session IDs
genid: (req) => {
return uuid()
},
// If you want to store the session in MongoDB using mongoose
// Require your personal mon
store: new MongoStore({
mongooseConnection: mongoose.connection
}),
// Define the session secret in env variable or in config file
secret: process.env.SESSION_SECRET || config.sessionSecretKey,
resave: false,
saveUninitialized: true
}));
// Initialize the passport module
app.use(passport.initialize());
// Tell to passport to use session
app.use(passport.session());
./models/session.js
const passport = require('passport');
const LocalStrategy = require('passport-local').Strategy;
const bcrypt = require('bcrypt-nodejs');
// Your custom MongoDB connection module
const db = require('./db');
// Configure passport.js to use the local strategy
passport.use(new LocalStrategy({
usernameField: 'username'
},
(username, password, done) => {
db.User.find({
username: username // But it could use email as well
}).then(res => {
const user = JSON.parse(JSON.stringify(res[0]));
if (!user) {
return done(null, false, {
message: 'Invalid credentials.\n'
});
}
if (!bcrypt.compareSync(password, user.password)) {
return done(null, false, {
message: 'Invalid credentials.\n'
});
}
return done(null, user);
}).catch(error => done(error));
}
));
// Tell passport how to serialize the user
passport.serializeUser((user, done) => {
done(null, user._id);
});
// Tell passport how to deserialize the user
passport.deserializeUser((id, done) => {
db.User.find({
_id: id
}).then(res => {
const response = typeof res !== undefined && res.length != 0 ? JSON.parse(JSON.stringify(res[0])) : null;
done(null, response)
}).catch(error => done(error, false))
});
// Export passport for external usage
module.exports = passport;
./models/db.js
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const uuid = require('uuid/v4');
// Connect to MongoDB
mongoose.connect('mongodb://localhost:27017/your_db_name', {
useNewUrlParser: true
});
// Define the models container
let models = {};
// Prepare your user schema
const userSchema = Schema({
username: {
type: String,
required: true
},
password: {
type: String,
required: true
}
});
// Assign the user schema
models.User = mongoose.model('User', userSchema);
// Export for external usage
module.exports = models;
/*
In that way you can wrap in "models" all schemas:
const newSchema = Schema({
name: String
});
models.Newschema = mongoose.model('Newschema', newSchema);
module.exports = models;
And use it externally like:
const db = require('./models/db');
db.User.find({}).then(docs => {}).catch(err => {});
db.Newschema.find({}).then(docs => {}).catch(err => {});
Etc....
*/
./models/config.js
class Config {
constructor() {
this.sessionSecretKey = "my-awesome-secretkey";
/* And other configurations */
}
}
module.exports = Config;
/*
Externally use like:
const Config = require('./models/config');
const config = new Config();
let sessionSecretKey = config.sessionSecretKey;
*/
Then you can use the req.isAuthenticated() after the login:
// POST the username and password to '/login' router
app.post('/login', (req, res, next) => {
passport.authenticate('local', (err, user, info) => {
if (info) {
return res.send(info.message)
}
if (err) {
return next(err);
}
if (!user) {
return res.sendStatus(404); // Is a shortcut
// OR -> res.status(404).end();
// OR -> res.status(404).send('Not found'); as you like
}
req.login(user, (err) => {
if (err) return next(err);
// Store the user object retrieved from MongoDB in `req.session`
req.session.user = user;
return res.sendStatus(200); // Is a shortcut
// OR -> res.status(200).end();
// OR -> res.status(200).send('OK'); as you like
})
})(req, res, next);
});
// The logout logic
app.get('/logout', verifySession, function (req, res) {
req.session.destroy(function (err) {
req.logout();
res.redirect('/');
});
});
// Verify the session to protect private routers
function verifySession(req, res, next) {
if (req.isAuthenticated()) {
next();
} else {
// Forbidden
res.redirect('/');
// OR -> res.sendStatus(403);
// OR -> res.status(403).end();
// OR -> res.status(403).send('Forbidden'); as you like
}
}
Of course you have to run npm install with all the dependencies required defined in package.json file or manually instal with npm i express-session#latest --s for all the dependencies required: npm i module-name#latest --s.
Don't forget the
const server = app.listen(config.port || 3000, () => {
console.log(`Server running on ${server.address().port} port.`);
});
At the end of server.js file. I hope that it will be useful for you.
I am trying to code a mean authentication app. Right now i can create user in mongodb via postman but when i try to authenticate it,if it has wrong username or password it gives proper feedback,wrong password etc, but if it matches correct username and password on database, server shutdowns, it doesnt gives any feedback on postman and it gives the following error on server terminal:
(node:11262) DeprecationWarning: Mongoose: mpromise (mongoose's
default promise library) is deprecated, plug in your own promise
library instead: http://mongoosejs.com/docs/promises.html
/home/cagdas/Desktop/basictest/node_modules/jsonwebtoken/sign.js:90
throw err;
^
Error: Expected object
at validate
(/home/cagdas/Desktop/basictest/node_modules/jsonwebtoken
/sign.js:35:11) at Object.module.exports [as sign]
(/home/cagdas/Desktop/basictest/node_modules/jsonwebtoken
/sign.js:101:7) at User.comparePassword
(/home/cagdas/Desktop/basictest/routes/users.js:40:26)
at bcrypt.compare (/home/cagdas/Desktop/basictest/models/user.js:52:6)
at
/home/cagdas/Desktop/basictest/node_modules/bcryptjs/dist
/bcrypt.js:297:21
at /home/cagdas/Desktop/basictest/node_modules
/bcryptjs/dist/bcrypt.js:1353:21
at Immediate.next (/home/cagdas/Desktop/basictest/node_modules
/bcryptjs/dist/bcrypt.js:1233:21)
at runCallback (timers.js:672:20)
at tryOnImmediate (timers.js:645:5)
at processImmediate [as _immediateCallback] (timers.js:617:5)
This is my code:
app.js:
const express = require('express') ;
const path = require('path');
const bodyParser = require('body-parser');
const cors = require('cors');
const passport = require('passport');
const mongoose = require('mongoose');
const config = require('./config/database');
// Connect to Database
mongoose.connect(config.database, { useMongoClient: true });
// On Connection
mongoose.connection.on('connected', () => {
console.log('Connected to database '+config.database);
});
// On Error
mongoose.connection.on('error', (err) =>{
console.log('Database error: '+err);
});
const app = express();
const users = require('./routes/users');
// Port Number
const port = 3000;
// Cors Middleware
app.use(cors());
// Set Static Folder
app.use(express.static(path.join(__dirname, 'public')));
// Body Parser Middleware
app.use(bodyParser.json());
// Passport Middleware
app.use(passport.initialize());
app.use(passport.session());
require('./config/passport')(passport);
app.use('/users', users);
// Index Route
app.get('/', (req, res) => {
res.send('Invalid Endpoint');
});
// Start Server
app.listen(port, () => {
console.log('Server started on port '+port);
});
users.js:
const express = require('express');
const router = express.Router();
const passport = require('passport');
const jwt = require('jsonwebtoken');
const User = require('../models/user');
const config = require('../config/database');
// Register
router.post('/register', (req, res, next) => {
let newUser = new User({
name: req.body.name,
email: req.body.email,
username: req.body.username,
password: req.body.password
});
User.addUser(newUser, (err, user) =>{
if(err){
res.json({success: false, msg:'Failed to register user'});
} else {
res.json({success: true, msg:'User registered'});
}
});
});
// Authenticate
router.post('/authenticate', (req, res, next) => {
const username = req.body.username;
const password = req.body.password;
User.getUserByUsername(username, (err, user) => {
if(err) throw err;
if(!user){
return res.json({success: false, msg: 'User not found'});
}
User.comparePassword(password, user.password, (err, isMatch) => {
if(err) throw err;
if(isMatch){
const token = jwt.sign(user, config.secret, {
expiresIn: 86400 // 1 day
});
res.json({
success: true,
token: 'JWT ' +token,
user: {
id: user._id,
name: user.name,
username: user.username,
email: user.email
}
});
} else {
return res.json({success: false, msg: 'Wrong Password'});
}
});
})
});
// Profile
router.get('/profile', (req, res, next) => {
res.send('PROFILE');
});
module.exports = router;
database.js:
module.exports = {
database: 'mongodb://localhost:27017/basictest',
secret: '123456789'
}
user.js:
const mongoose = require('mongoose');
const bcrypt = require('bcryptjs');
const config =require('../config/database');
// User Schema
const UserSchema = mongoose.Schema({
name: {
type: String
},
email: {
type: String,
required: true
},
username: {
type: String,
required: true
},
password: {
type: String,
required: true
}
});
const User = module.exports = mongoose.model('User', UserSchema);
module.exports.getUserById = function(id, callback){
User.findById(id, callback);
}
module.exports.getUserByUsername = function(username, callback){
const query = {username: username}
User.findOne(query, callback);
}
module.exports.addUser = function(newUser, callback){
bcrypt.genSalt(10, (err, salt) => {
bcrypt.hash(newUser.password, salt, (err, hash) => {
if(err) throw err;
newUser.password = hash;
newUser.save(callback);
});
});
}
module.exports.comparePassword = function(candidatePassword, hash,
callback){
bcrypt.compare(candidatePassword, hash, (err, isMatch) => {
if(err) throw err;
callback(null, isMatch);
});
}
passport.js
const JwtStrategy = require('passport-jwt').Strategy;
const ExtractJwt = require('passport-jwt').ExtractJwt;
const User = require('../models/user');
const config = require('../config/database');
module.exports = function(passport){
let opts = {};
opts.jwtFromRequest = ExtractJwt.fromAuthHeaderWithScheme('jwt');
opts.secretOrKey = config.secret;
passport.use(new JwtStrategy(opts, (jwt_payload, done) => {
User.getUserById(jwt_payload._id, (err, user) => {
if(err){
return done (err, false);
}
if(user){
return done(null, user);
} else {
return done(null, false);
}
});
}));
}
Solution - not user only { data: user }
const token = jwt.sign({data: user}, config.secret, {
expiresIn: 604800 // 1 week
});
Got the same error for a while and I suggest that you recreate a new object user (without the hashed password for security reason) and insert it into the sign function.
let restrictedUser = {
id: user._id,
username: user.username,
name: user.name,
email: user.email
}
const token = jwt.sign(restrictedUser, config.secret, {
expiresIn: "7d"
})
Hope this will help.
Not sure about this, But you can try this
"npm remove mongoose"
Then
"npm install mongoose#4.10.8 --save"
Hope it will help you..
Thanks...