req.session.user gives 'undifined' as output - mongodb

I am implementing a login authentication program in MERN stack.
When I enter correct user name and password, login function works fine.
There are some components which can be displayed only if the client is logged in. Therefore, to validate the client I have implemented authenticator function in the server which should return success message along with the session object.
Once I try to authenticate, req.session.user gives the output as 'undefined'. I referred several similar questions but couldn't solve my issue.How can I solve this issue?
Login function,
router.post('/login', (req, res) => {
const email = req.body.email;
const password = req.body.password;
if (!email || !password) {
return res.status(400).json({ msg: "Please enter all fields" });
}
//Find user
User.findOne({ email : email })
.then(user => {
if(!user){
console.log('Not a user')
}
//Password matching
bcrypt.compare(password, user.password, (err, isMatch) => {
if(err) throw err;
if(isMatch){
console.log('Logged in')
const userSession = {
id: user.id,
name : user.name,
email : user.email
};
req.session.user = userSession;
res.json({ msg: "Logged in successfully", userSession});
} else {
console.log('Incorrect username or password')
}
});
})
.catch(err => console.log(err));
});
server.js,
const express = require('express');
const expressLayouts = require('express-ejs-layouts');
const mongoose = require('mongoose');
const passport = require('passport');
const flash = require('connect-flash');
const session = require('express-session');
const cors = require('cors');
const MongoDBStore = require('connect-mongodb-session')(session);
const app = express();
const router = express.Router();
const {IS_PROD} = require('./config/config');
const MAX_AGE = 1000 * 60 * 2;
mongoose.connect("mongodb+srv://root:admin#cluster0-ynman.gcp.mongodb.net/test?retryWrites=true&w=majority", {useNewUrlParser:true, useCreateIndex:true, useUnifiedTopology:true})
.then(() => console.log('Mongo DB Connected'))
.catch(err => console.log(err));
//setting up connect-mongodb-session store
const mongoDBStore = new MongoDBStore({
uri: "mongodb+srv://root:admin#cluster0-ynman.gcp.mongodb.net/test?retryWrites=true&w=majority",
collection : "mySession"
})
//Bodyparser
app.use(express.urlencoded({extended:false}));
app.use(cors());
app.use(express.json());
//Express Session
app.use(session({
name: 'session',
secret: 'secret',
resave: true,
saveUninitialized: false,
store : mongoDBStore,
cookie :{
path : '/',
httpOnly: false,
maxAge : MAX_AGE,
sameSite: false,
secure : IS_PROD
}
}));
//Routes
app.use('/', require('./routes/index'));
app.use('/users', require('./routes/users'));
const PORT = process.env.PORT || 5000;
app.listen(PORT, console.log(`Server starts on port ${PORT}`));
Authenticate funtion,
router.get("/authenticator", (req, res) => {
const userSession = req.session.user;
console.log(userSession);
if(userSession){
return res.json({msg : "Authenticated successfully", userSession});
} else {
return res.status(401).json({msg : "Unauthorized"});
}
});

Related

MongooseError: Operation `users.findOne()` buffering timed out after 10000ms. How do I resolve this?

Error:
MongooseError: Operation `users.findOne()` buffering timed out after 10000ms
at Timeout.<anonymous> (D:\Web Dev\Traversy\storybooks\node_modules\mongoose\lib\drivers\node-mongodb-native\collection.js:153:23)
at listOnTimeout (node:internal/timers:559:17)
at processTimers (node:internal/timers:502:7)
GET /auth/google/callback?code=4%2F0ARtbsJqsdI35M7-9iSldOa1xWXs9SXFW09MohqzZ94_K5I5jpc1YTKge6lGKuS8-jPRyZA&scope=profile+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.profile - - ms - -
What I tried to do:
mongoose.connect(...) code is loading except this is my code where I tried to comment out: useFindAndModify: true
db.js
const mongoose = require('mongoose')
const connectDB = async () => {
try {
const conn = await mongoose.connect(process.env.MONGO_URI, {
useNewUrlParser: true,
useUnifiedTopology: true,
// useFindAndModify: true
})
console.log(`MongoDB Connected: ${conn.connection.host}`)
} catch(err) {
console.error(err)
process.exit(1)
}
}
module.exports = connectDB
auth.js
const express = require('express')
const passport = require('passport')
const router = express.Router()
// #desc Auth with Google
// #route GET /auth/google
router.get('/google', passport.authenticate('google', { scope: ['profile'] }))
// #desc Google auth callback
// #route GET /auth/google/callback
router.get('/google/callback', passport.authenticate('google', { failureRedirect: '/' }),
(req, res) => {
res.redirect('/dashboard')
})
module.exports = router
passport.js
const GoogleStrategy = require('passport-google-oauth20').Strategy
const mongoose = require('mongoose')
const User = require('../models/User')
module.exports = function (passport) {
passport.use(new GoogleStrategy({
clientID: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
callbackURL: '/auth/google/callback'
},
async (accessToken, refreshToken, profile, done) => {
// console.log(profile)
const newUser = {
googleId: profile.id,
displayName: profile.displayName,
firstName: profile.name.givenName,
lastName: profile.name.familyName,
image: profile.photos[0].value
}
try {
let user = await User.findOne({ googleId: profile.id })
if (user) {
done(null, user)
} else {
user = await User.create(newUser)
done(null, user)
}
} catch (err) {
console.error(err)
}
}))
passport.serializeUser((user, done) => done(null, user.id))
passport.deserializeUser((id, done) => {
User.findById(id, (err, user) => done(err, user))
})
}
App.js
const path = require('path')
const express = require('express')
const dotenv = require('dotenv')
const morgan = require('morgan')
const exphbs = require('express-handlebars')
const passport = require('passport')
const session = require('express-session')
const connectDB = require('./config/db')
// Load config
dotenv.config({ path: './config/config.env' })
// Passport config
require('./config/passport')(passport)
connectDB()
const app = express()
// Logging
if (process.env.NODE_ENV === 'development') {
app.use(morgan('dev'))
}
// Handlebars (Source: https://www.npmjs.com/package/express-handlebars)
app.engine('.hbs', exphbs.engine({ defaultLayout: 'main', extname: '.hbs' }))
app.set('view engine', '.hbs')
// Sessions
app.use(session({
secret: 'keyboard cat',
resave: false,
saveUninitialized: false
}))
// Passport middleware
app.use(passport.initialize())
app.use(passport.session())
// Static folder
app.use(express.static(path.join(__dirname, 'public')))
// Routes
app.use('/', require('./routes/index'))
app.use('/auth', require('./routes/auth'))
const PORT = process.env.PORT || 3000
app.listen(PORT, console.log(`Server running in ${process.env.NODE_ENV} mode on port ${PORT}`))

Express mongoDB Integration testing for private/secured routes

I am trying to run a integration test for one of the express routes in the application.
The routed is a protected route allows user to create supplier when user is authenticated.
I am trying to login user before making a request to the 'api/v1/supplier' (protected route) route but not able to login user before calling the Login API give 500 error back, the Login API is working as expected when tested separately.
Here is the test that I am trying. request help!
process.env.NODE_ENV = 'development';
const expect = require('chai').expect;
const request = require('supertest');
const app = require('../../../app.js');
const conn = require('../../../db/index.js');
describe('POST /api/v1/supplier ', () => {
let token = '';
before(done => {
conn
.connect()
.then(done())
.catch(err => done(err));
});
after(done => {
conn
.close()
.then(done())
.catch(err => done(err));
});
it('Error, on unauthorized POST Supplier request', done => {
request(app)
.post('/api/v1/users/login')
.send({ email: 'sgrmhdk00#gmail.com', password: '12345678' })
.end(function(err, res) {
token = res.body.token;
});
request(app)
.post('/api/v1/supplier')
.set('Authorization', 'Bearer' + token)
.send({ supplierID: '1234567' })
.then(res => {
const body = res.body;
expect(body).to.contain.property('status');
expect(body).to.contain.property('error');
done();
})
.catch(err => done(err));
});
});
db/index.js
const dotenv = require('dotenv');
const mongoose = require('mongoose');
const DB_URI = 'mongodb://localhost:27017/myapp';
function connect() {
return new Promise((resolve, reject) => {
dotenv.config({ path: './config.env' });
const setDatabase = () => {
if (process.env.NODE_ENV === 'development') {
const DB = process.env.DATABASE;
return DB;
} else {
const DB = process.env.DATABASE_PRODUCTION.replace(
'<PASSWORD>',
process.env.DATABASE_PASSWORD
);
return DB;
}
};
const DB = setDatabase();
mongoose
.connect(DB, {
useNewUrlParser: true,
useCreateIndex: true,
useFindAndModify: false
})
.then(() => console.log('DB connection successful!'));
});
}
function close() {
return mongoose.disconnect();
}
module.exports = { connect, close };
You need to call you API with token, but the two calls are asynchronous, you need call the second method inside the end of the first:
it('Error, on unauthorized POST Supplier request', done => {
request(app)
.post('/api/v1/users/login')
.send({ email: 'sgrmhdk00#gmail.com', password: '12345678' })
.end(function(err, res) {
if(err){
done(err)
return
}
token = res.body.token;
request(app)
.post('/api/v1/supplier')
.set('Authorization', 'Bearer' + token)
.send({ supplierID: '1234567' })
.then(res => {
const body = res.body;
expect(body).to.contain.property('status');
expect(body).to.contain.property('error');
done();
})
.catch(err => done(err));
});
});

Cannot Make POST or GET Request with Express API

I am trying to test my API and I am not sure what I am doing wrong. The only error I am getting is cannot post. After some research, I am suspecting something wrong with my controller class.
This is my first real large project and I have created an API similar to this just with mongo but this is my first time using seqealize, and MySQL (with node).
The api/student/register router just won't post, but when I remove the controller and but a function that returns just plain JSON it works, that is why I really do believe it has something to do with my controller class.
contoller/student.controller.js
const bcrypt = require('bcrypt');
const jwt = require('jsonwebtoken');
require('dotenv').config();
const secret = process.env.SERCRET_KEY;
const db = require('../models/index.js');
const Student = db.Student;
class StudentContoller {
static registerStudent(req, res) {
try {
let {
first_name,
last_name,
email,
password,
phone,
shirt_size,
grade,
teacher,
} = req.body;
Student.findAll({
where: {
email : email,
is_Archived: false,
}
})
.then(result => {
if (result.length > 0){
res.status(400).json({ message: 'Email is already registerd'});
} else {
let hashPassword = bcrypt.hashSync(password, 10);
let newStudent = {
first_name,
last_name,
email,
password: hashPassword,
phone,
shirt_size,
grade,
teacher,
school_id,
}
Student.Create(newStudent)
.then(data => {
if(data){
res.status(201).json({message: 'Student Created', student: data })
}
})
.catch(err => res.json({error : err.message}));
}
})
} catch (e) {
res.status(500).json({error: 'error caused in regiserted controller'})
}
}
static async login(req, res) {
let { email, password, } = req.body;
await Student.findAll({
where: {
email: email,
is_Archived: false,
}
})
.then(student => {
if(student.length === 0){
res.status(400).json({ message: 'Sorry, account does not exsist'})
} else {
let passwordIsValid = bcrypt.compareSync(req.body.password, student[0].password.trim());
if (passwordIsValid) {
let studentDetails = {
id: student[0].dataValues.id,
first_name: student[0].first_name,
last_name: student[0].last_name,
}
let token = jwt.sign({
student: studentDetails,
}, secret, {
expiresIn: '1d'
});
res.status(200).json({
success: true,
student: studentDetails,
message: 'Login successfull',
token: token,
});
} else {
res.status(401).json({
success: false,
message: 'Login failed',
});
}
}
})
.catch(err => res.status(500).json({error: err.message}));
}
static async updateStudent(req, res) {
try {
const {
first_name,
last_name,
email,
password,
phone,
shirt_size,
grade,
teacher,
} = req.body;
let hashpassword = bcrypt.hashSync(password, 10);
let updateStudent = {
first_name,
last_name,
email,
password : hashpassword,
phone,
shirt_size,
grade,
teacher,
}
Student.update(updateStudent, {
where: {
id: req.params.id
}
})
.then(response => {
res.status(200).json({success: true, message: "Student updated successfully"})
})
.then(err => res.json({err: err.message}));
} catch (e) {
res.status(500).json({ error: e});
}
}
static async archiveStudent(req, res) {
try{
let id = req.params.id
await Student.findAll({
where: {id: id}
})
.then(result => {
if (result.length == 1){
Student.update(
{is_Archived: true},
{ where: {id: id}}
)
}
})
} catch (e) {
res.status(500).json({ error: e});
}
}
}
module.exports = StudentContoller;
student.routs.js
const express = require('express');
const router = express.Router();
const jwt = require('jsonwebtoken');
const checkJWT = require('../middlewares/check-token');
const StudentController = require('../controllers/student.controller');
//
//
router.get('student/login', StudentController.login);
router.post('student/register', checkJWT,StudentController.registerStudent);
module.exports = router;
Sever js
const express = require('express');
const bodyParser = require('body-parser');
const cors = require('cors');
const morgan = require('morgan');
const helmet = require('helmet');
const app = express();
// Middlewars
app.use(cors()); // Enable Cors
app.use(morgan('dev')); // Enable Logging
app.use(helmet()); // Enables Security Headers
app.use(bodyParser.json()); // Parses requrests of type application/json
app.use(bodyParser.urlencoded({ extended: true})); // Parses request of application/x-www-form-urlencode
//Add database connection
const db = require('./models');
//db.sequelize.sync().then(()=> initial())
// Routing
app.get('/', (req, res)=> res.json({message: "Base API URL"}));
const studnetRoute = require('./routes/student.routes');
app.use('/', studnetRoute);
const PORT = process.env.PORT || 3300;
app.listen(PORT, () => console.log(`Server Running on port ${PORT}`));
you can do like this in your router file .
router.route('student/login')
.get(StudentController.login);
router.route('student/register')
.post(checkJWT, StudentController.registerStudent);

I am trying to store my node rest api data to mongodb atlas. But getting insertion errors

I am trying to register the user to mongodb atlas for registration and login but i am geting an error 404.
here is full link to mycode
https://github.com/badrinathareddyr/falcon.git
server.js file
const express = require('express');
const app = express();
const bodyParser = require('body-parser');
const mongoose = require('mongoose');
const dotenv = require('dotenv');
const authRoute = require('../backend/routes/auth')
//connect to database
dotenv.config({ path: __dirname + '/.env' });
mongoose.connect(
process.env[DB_CONNECT], { useNewUrlParser: true }, () =>
console.log('connected to db!')
);
//Middleware
app.use(express.json());
//middlewareroutes
app.use('/register', authRoute);
app.listen(3000, () => console.log('server up and running'));
auth.js file
var express = require('express');
const router = express.Router();
const User = require('../models/User');
const bcrypt = require('bcryptjs');
router.post('/register', function (req, res) {
if (!req.body.email || !req.body.password) {
res.json({ success: false, msg: 'Please pass email and password.' });
} else {
var newUser = new User({
email: req.body.email,
password: req.body.password
});
// save the user
newUser.save(function (err) {
if (err) {
return res.json({ success: false, msg: 'Email already exists.' });
}
res.json({ success: true, msg: 'Successful created new user.' });
});
}
});
module.exports = router;
It's because of process.env.DB_CONNECT in your code is undefined. Change line 5 of your src/backend/server.js file like below:
const dotenv = require('dotenv').config({ path: __dirname + '/.env' });
then comment dotenv.config()
and copy .env to src/backend/.
Or change line 10 or the file like this:
dotenv.config({ path: __dirname + '/.env' });
You have const User = require('../models/User'); two time in backend/routes/auth.js. Comment line 9. It will give you error.
I fixed it and created pull request in github. Merge it.

Passport: Error: passport.initialize() middleware not in use;

I'm have an express server with MongoDB and Mongoose, and using passport to authenticate with JWT, but getting an error as in the title.
I'm following the passport-jwt documentation, but am still getting the error. What am I doing wrong?
Here is the error message when doing GET call on localhost3090 with a valid JWT:
::1 - - [16/Mar/2018:05:35:47 +0000] "GET / HTTP/1.1" 500 1677 "-" "PostmanRuntime/7.1.1"
Error: passport.initialize() middleware not in use
at IncomingMessage.req.login.req.logIn (/Users/okadachikara/react-courses/projects/server/node_modules/passport/lib/http/request.js:46:34)
at JwtStrategy.strategy.success (/Users/okadachikara/react-courses/projects/server/node_modules/passport/lib/middleware/authenticate.js:248:13)
at verified (/Users/okadachikara/react-courses/projects/server/node_modules/passport-jwt/lib/strategy.js:115:41)
at /Users/okadachikara/react-courses/projects/server/services/passport.js:34:7
at /Users/okadachikara/react-courses/projects/server/node_modules/mongoose/lib/model.js:3930:16
at _init (/Users/okadachikara/react-courses/projects/server/node_modules/mongoose/lib/query.js:2007:5)
at model.Document.init (/Users/okadachikara/react-courses/projects/server/node_modules/mongoose/lib/document.js:393:5)
at completeOne (/Users/okadachikara/react-courses/projects/server/node_modules/mongoose/lib/query.js:1993:12)
at Immediate.<anonymous> (/Users/okadachikara/react-courses/projects/server/node_modules/mongoose/lib/query.js:1520:11)
at Immediate._onImmediate (/Users/okadachikara/react-courses/projects/server/node_modules/mquery/lib/utils.js:119:16)
at runCallback (timers.js:773:18)
at tryOnImmediate (timers.js:734:5)
at processImmediate [as _immediateCallback] (timers.js:711:5)
My server/controllers/authentication.js:
const User = require('../models/user');
const jwt = require('jwt-simple');
const config = require('../config');
function tokenForUser(user) {
const timestamp = new Date().getTime();
return jwt.encode({ sub: user.id, iat: timestamp }, config.secret);
}
exports.signup = function (req, res, next) {
const email = req.body.email;
const password = req.body.password;
if (!email || !password) {
return res.status(422).send({ error: 'You must provide an email and
password' });
}
// see if user with the given email exists
User.findOne({ email: email }, function (err, existingUser) {
if (err) { return next(err); }
if (existingUser) {
return res.status(422).send({ error: 'A user with that email
already exists' });
}
const user = new User({
email: email,
password: password
});
user.save(function (err) {
if (err) { return next(err); }
res.json({ token: tokenForUser(user), iat: jwt.iat });
});
});
};
My server/services/passport.js
const passport = require('passport');
const JwtStrategy = require('passport-jwt').Strategy;
const ExtractJwt = require('passport-jwt').ExtractJwt;
const User = require('../models/user');
const config = require('../config');
const jwtOptions = {
jwtFromRequest: ExtractJwt.fromHeader('authorization'),
secretOrKey: config.secret
};
const jwtLogin = new JwtStrategy(jwtOptions, function (payload, done) {
User.findById(payload.sub, function (err, user) {
if (err) { return done(err, false); }
if (user) {
done(null, user);
} else {
done(null, false);
}
});
});
passport.use(jwtLogin);
My server/router.js
const passport = require('passport');
const Authentication = require('./controllers/authentication');
const passportService = require('./services/passport');
const requireAuth = passport.authenticate('jwt', { sesssion: false });
module.exports = function (app) {
app.get('/', requireAuth, function (req, res) {
res.send({ hi: 'there' });
});
app.post('/signup', Authentication.signup);
};
You need to initialize the passport module before using it:
let app = express();
app.use(passport.initialize());