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

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}`))

Related

express session with connect-mongodb-session not getting cookies in browser but postman works well

i am getting set-cookie in response header but my browser does not use it.
also, the cookie is not sent to the server there every time a new session is made on server side due to this.
I have checked my routes on postman everything working as expected i.e : cookies are receive and sent by postman but the browser completely ignores cookies.
zip file of project
index.js
const express = require('express');
const session = require('express-session')
const cookieParser = require('cookie-parser');
const mongoDBStore = require('connect-mongodb-session')(session)
const routes = require('./routes/routes')
require('./model/model');
require('./db/mongoose')
const app = express();
const store = new mongoDBStore({
uri: 'mongodb+srv://mny:QTCdKtdkjfdjfouJJWbUYN#cluster0.zxfwd.mongodb.net/MernDocker?retryWrites=true&w=majority',
collection: "mySessions"
})
// app.use(cookieParser())
app.use(express.json());
// app.use(express.urlencoded({ extended: false }));
app.use((req, res, next) => {
res.header("Access-Control-Allow-Origin", req.headers.origin);
res.header("Access-Control-Allow-Headers", "*");
res.header("Access-Control-Allow-Credentials", 'true')//true as string
// res.header('Access-Control-Expose-Headers',
// 'Date, Etag, Access-Control-Allow-Origin, Set-Cookie, Access-Control-Allow-Credentials')
if (req.method === "OPTIONS") {
res.header("Access-Control-Allow-Methods", "GET,PATCH,POST,DELETE");
return res.status(200).send()
}
next();
});
app.use(session({
secret: "mny",
saveUninitialized: true,
cookie: {
path: "/",//if / the cookies will be sent for all paths
httpOnly: false,// if true, the cookie cannot be accessed from within the client-side javascript code.
secure: true,// true->cookie has to be sent over HTTPS
maxAge: 2*24 * 60 * 60 * 1000,
sameSite: 'none',//- `none` will set the `SameSite` attribute to `None` for an explicit cross-site cookie.
},
store: store,
resave: false,
}))
app.use(routes);
const port = process.env.PORT || 3001;
app.listen((port), (error) => {
console.log(`lisning on port ${port}`)
})
const express = require('express');
const User = require('../model/model');
const routes = express.Router();
/*
routes.get('/', async (req, res, next) => {
console.log('req.headers.cookie get')
console.log(req.headers.cookie)
// console.log(req.headers.cookie.split(';')[1].split('=')[1])
res.send({
"post": req.session.postClick,
"patch": req.session.patchClick
})
})*/
routes.post('/', async (req, res) => {
console.log("req.headers.cookie post method")
console.log(req.headers)
// console.log(req.headers.cookie.split(';')[1])
const user = new User(req.body)
try {
await user.save()
if (!req.session.postClick) {
req.session.postClick = 0
console.log(req.session);
}
req.session.postClick++
res.send({ "user": user, "postClick": req.session.postClick });
} catch (e) {
res.send(e)
}
})
module.exports = routes;
app.js frontend
import logo from './logo.svg';
import './App.css';
import { useState } from 'react';
const url = 'http://localhost:3001'
console.log(document.cookie)
function App() {
const [inputValue, setInputValue] = useState({
name: '',
})
const handleChange = (e) => {
const { name, value } = e.target;
setInputValue({
...inputValue,
[name]: value
})
}
const handleOnAdd = (e) => {
e.preventDefault()
console.log(document.cookie)
const addData = async () => {
try {
const res = await fetch(`${url}`, {
method: 'POST',
headers: {
"mode": 'cors',
"Credentials": 'include',
'Content-Type': 'application/json',
'Accept': 'application/json',
'WithCredentials': true,
},
body: JSON.stringify(inputValue)
})
if (res.ok) {
let d = await res.json()
console.log(d)
} else {
alert('fetch add failed')
}
} catch (e) {
console.log(e)
}
}
addData()
// setInputValue({})
}
return (
<div>
<h1>session with mongodb</h1>
<form className='form' >
<label>name</label>
<input
name='name'
onChange={(e) => handleChange(e)}
value={inputValue.name}
/>
<button onClick={handleOnAdd}>Add</button>
</form>
</div>
)
}
export default App;

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));
});
});

req.session.user gives 'undifined' as output

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"});
}
});

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());