Unable to retrieve email id of twitter using passportjs - email

const TwitterStrategy = require('passport-twitter').Strategy;
module.exports = (passport, User) => {
passport.use(new TwitterStrategy({
consumerKey: 'paLCHei1bz8uG5mzNK3ZmvWy7',
consumerSecret: 'djwTrPntW6T2hm3EJ6eIvUrqObMSymgKn6B1foMQyNeypjtbIK',
callbackURL: 'http://localhost:3000/auth/twitter/callback',
passReqToCallback: true
}, (req, accessToken, tokenSecret, profile, done) => {
User.findOne({ 'twitter.id': profile.id }, (err, x) => {
if (x) return done(null, x);
var user = {
image: profile._json.profile_image_url,
displayName: profile.displayName,
email: profile.emails[0].value,
twitter: {
id: profile.id,
email: profile.emails[0].value
}
};
User.create(user, (err, x) => done(null, x));
});
}));
};

You need to check the “Request email addresses from users” checkbox in your app permissions on Twitter. You can read more about it here

Related

How change name of parameter on express response

I'm using mongoose and I would like that when I get all users send me uid instead of _id.
const allUssers = (req, res, next) => {
try {
User.find({})
.select("username")
.select("email")
.select("image")
.exec((err, users) => {
if (err) {
return res.status(400).json({
ok: false,
msg: "Error listing users",
});
}
return res.status(200).json({
ok: true,
users: users,
});
});
} catch (err) {
return res.status(500).json({
ok: false,
msg: "Please contact with administrator",
});
}
};
You can update your schema to use an alias:
let User = new Schema({
_id: { type: String, alias: "uid" }
});
Or you can map your users to something different:
return res.status(200).json({
ok: true,
users: users.map(({ _id, ...user }) => ({ uid: _id, ...user }),
});

I am getting this error : Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client

When I am sending POST Request for Login, then show this Error. I have used mongoose & MongoDB Atlas.
If I send POST request with valid email & password, it also shows this error.
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent
to the client
But POST request for registration is working well.
User Model
const mongoose = require('mongoose')
const Schema = mongoose.Schema
const userSchema = new Schema({
name: {
type: String,
required: true,
trim: true
},
email: {
type: String,
required: true,
},
password: {
type: String,
required: true
},
balance: Number,
income: Number,
expense: Number,
transactions: {
type: [{
type: Schema.Types.ObjectId,
ref: 'Transaction'
}]
}
})
const User = mongoose.model('User', userSchema)
module.exports = User
User Controller
const registorValidate = require('../validator/registrationValidate')
const User = require('../models/userModel')
const bcrypt = require('bcrypt')
const loginValidate = require('../validator/loginValidator')
const jwt = require('jsonwebtoken')
module.exports = {
login: (req, res) => {
const { email, password } = req.body
let logValidate = loginValidate({ email, password })
if (!logValidate.isValid) {
res.status(400).json(logValidate.error)
return
}
User.findOne({ email })
.then(user => {
if (!user) {
console.log(`${email} not found`)
res.json({
msg: `${email} not found`
})
}
bcrypt.compare(password, user.password, (err, result) => {
if (err) {
res.status(400).json({
msg: 'Error occured'
})
}
if (!result) {
res.status(404).json({
msg: `Password doesn't match`
})
}
let token = jwt.sign({
_id: user._id,
name: user.name,
email: user.email
}, 'SECRET', { expiresIn: '2h' })
res.status(200).json({
msg: 'Login successful',
token: `Bearer ${token}`
})
})
return
})
.catch(err => {
res.status(500).json({
msg: 'Error occured'
})
})
res.end()
},
registration: (req, res) => {
let { name, email, password, confirmPassword } = req.body
let validate = registorValidate({ name, email, password, confirmPassword })
if (!validate.isValid) {
res.status(400).json(validate.error)
} else {
User.findOne({ email })
.then(user => {
if (user) {
res.json({
msg: `${email} is already exist`
})
} else {
bcrypt.hash(password, 11, (err, hash) => {
if (err) {
res.status(500).json({
msg: 'Server error occured'
})
}
let user = new User({
name,
email,
password: hash
})
user.save()
.then(user => {
res.status(201).json({
msg: `Thanks ${name} for your registration`,
user
})
})
.catch(err => {
res.status(500).json({
msg: 'Error occured'
})
})
})
}
})
.catch(err => {
res.status(500).json({
msg: 'Error occured'
})
})
}
}
}
Login Validator
const validator = require('validator')
const validate = user => {
let error = {}
// Email validator
if (!user.email) {
error.email = 'Please provide an Email'
} else if (!validator.isEmail(user.email)) {
error.email = 'Please provide a valid Email'
}
// Password validate
if (!user.password) {
error.password = 'Please provide a password'
} else if (user.password.length < 6) {
error.password = 'Password Must be greater or Equal to 6 characters'
}
return {
error,
isValid: Object.keys(error).length === 0
}
}
module.exports = validate
Thanks.
You don't need to put res.end() because when you called res.json() earlier, it already sent the response.
Please be advised that you should return when you call res.end(), res.send(), 'res.json()' and other operations that send the response, just like what you did with res.status(400).json(logValidate.error)
This should be one of the ways prevent you from getting ERR_HTTP_HEADERS_SENT, but keep in mind that if you have nested callbacks, you should return from the outer scope as well

passport bookshelf is not inserting user into database

I'm using passport with bookshelf, and im having issues inserting a user in the database.
I'm using postman, and it shows that a user has been added to the db, but its not.
There doesn't seem to be much information about bookshelf, passport, and postgres used together. So it makes finding solutions like this hard.
routes/users
router.post('/register', (req, res, next) => {
passport.authenticate('register', (err, user, info) => {
if(err){
console.log(err)
}
if(info !== undefined){
console.log(info.message)
res.status(403).send(info.message)
}else{
req.logIn(user, err => {
const data = {
username: req.body.username.trim(),
password: req.body.password.trim(),
email: req.body.email.trim()
}
console.log(data);
User.forge({
username: data.username
}).fetch().then( (user) => {
console.log('user creatd in db');
res.status(200).send({
message:'user created'
})
})
})
}
})(req, res, next);
});
passport.js
import passport from 'passport';
import LocalStrategy from 'passport-local';
import User from '../models/User';
import bcrypt from 'bcrypt';
import JWTstrag from 'passport-jwt';
import ExtracJWT from 'passport-jwt';
const JWTstrategy = JWTstrag.Strategy
const ExtractJWT = ExtracJWT.ExtractJwt
const Local = LocalStrategy.Strategy
const opts = {
jwtFromRequest: ExtractJWT.fromAuthHeaderWithScheme('JWT'),
secretOrKey: process.env.JWT_SECRET,
};
passport.use('jwt', new JWTstrategy(opts, (jwt_payload, done) => {
try{
User.forge({username: jwt_payload._id})
.fetch()
.then( (user) => {
if(user){
console.log('user found in db in passport');
done(null, user)
}else{
console.log('user not found in db');
done(null, false)
}
})
} catch(err){
done(err)
}
}))
passport.use(
'register',
new Local(
{
usernameField: 'username',
passwordField: 'password',
// passReqToCallback: true,
session: false,
},
(req, username, password, done) => {
try {
User.forge({username: username}, {email: req.body.email}).fetch().then(user => {
if (user != null) {
console.log('username or email already taken');
return done(null, false, {
message: 'username or email already taken',
});
} else {
bcrypt.hash(password, 12).then(hashedPassword => {
const user = new User({
username: req.body.username,
password: hashedPassword,
email: req.body.email
})
user.save().then( () => {
res.status(200).send('user created')
return done(null, user);
})
});
}
});
} catch (err) {
return done(err);
}
},
),
);
// passport.use(new Local ( (username, password, done) => {
// User.findOne({username: username} , (err, user) =>{
// if(err){
// return done(err)
// }
// if(!user){
// return done(null, false, {message: "Incorrect username."})
// }
// if(!user.validPassword(password)){
// return done(null, false, {message: 'Incorrect password'})
// }
// return done (null, user)
// })
// }))
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(user, done) {
User
.forge({id: user})
.fetch()
.then((usr) => {
done(null, usr);
})
.catch((err) => {
done(err);
});
});
main.js
import 'dotenv/config';
import cors from 'cors';
import express from 'express';
import logger from 'morgan';
import path from 'path';
import bodyParser from 'body-parser';
import cookieParser from 'cookie-parser';
import userRoute from './routes/users';
import passport from 'passport';
import session from 'express-session';
import './config/passport';
const app = express();
app.use(cors());
app.use(logger('dev'));
// For React Stuff if need be
// app.use(express.static(path.join(__dirname, 'public')));
app.use(express.static(path.join(__dirname, 'build')));
app.use(cookieParser());
app.use(bodyParser.json());
// you need body parser urlencoded so passport will not give a Missing Credentials error
app.use(bodyParser.urlencoded({ extended:false}));
app.use(session({
saveUninitialized: false,
resave:false,
cookie: { maxAge: 30 * 24 * 60 * 60 * 1000 }, // 30 days
secret : process.env.JWT_SECRET,
}));
app.use(passport.initialize());
app.use(passport.session());
app.get('/', (req, res) => {
res.send('Hello World!');
});
app.use('/users', userRoute);
app.use(() => (req, res, next) =>{
res.locals.user = req.user; // This is the important line
// req.session.user = user
console.log(res.locals.user);
next();
});
//build mode
// app.get('*', (req, res) => {
// res.sendFile(path.join(__dirname+'/client/public/index.html'));
// })
// module.parent prevents the
// Node / Express: EADDRINUSE, Address already in use error when unit testing
if(!module.parent){
app.listen(process.env.PORT, () =>
console.log(`Example app listening on port ${process.env.PORT}!`),
);
}
export default app;
Fixed it, there were a number of errors.
One being the
done is not a function
Which will be fixed by uncommenting
passReqToCallback: true,
two being res thats not supposed to be in the passport.js file but route file.
so remove
res.status(200).send('user created')
Now everything should be working.
passport.js
passport.use(
'register',
new Local(
{
usernameField: 'username',
passwordField: 'password',
passReqToCallback: true,
session: false,
},
(req, username, password, done) => {
try {
User.forge({username: username}, {email: req.body.email}).fetch().then(user => {
if (user != null) {
console.log('username or email already taken');
return done(null, false, {
message: 'username or email already taken',
});
} else {
bcrypt.hash(password, 12).then(hashedPassword => {
const user = new User({
username: req.body.username,
password: hashedPassword,
email: req.body.email
})
user.save().then( () => {
return done(null, user);
})
});
}
});
} catch (err) {
return done(err);
}
},
),
);
routes/users
router.post('/register', (req, res, next) => {
passport.authenticate('register', (err, user, info) => {
if(err){
console.log(err)
}
if(info !== undefined){
console.log(info.message)
res.status(403).send(info.message)
}else{
req.logIn(user, err => {
const data = {
username: req.body.username.trim(),
password: req.body.password.trim(),
email: req.body.email.trim()
}
console.log(data);
User.forge({
username: data.username
}).fetch().then( (user) => {
console.log('user creatd in db');
res.status(200).send({
message:'user created'
})
})
})
}
})(req, res, next);
});

How to read registered users list from mean stack server

I would like to be able to read the registered users list from the Mean Stack Mongo DB server and display it on my Web App.
So far, I've only been able to access this list, which is encrypted, through the terminal by running the Mongo shell.
Any ideas? This is the code piece where "getUsers" should be implemented, but my "getUsers" attempts have not been successful so far.
const bcrypt = require("bcryptjs");
const jwt = require("jsonwebtoken");
const User = require("../models/user");
exports.createUser = (req, res, next) => {
bcrypt.hash(req.body.password, 10).then(hash => {
const user = new User({
email: req.body.email,
password: hash
});
if(req.body.adminCode === "secretCode123") {
newUser.isAdmin === true;
}
user
.save()
.then(result => {
res.status(201).json({
message: "User created!",
result: result
});
})
.catch(err => {
res.status(500).json({
message: "Invalid authentication credentials!"
});
});
});
};
// Here we create the token
exports.userLogin = (req, res, next) => {
let fetchedUser; // Otherwise user would only exist in the first then block
User.findOne({ email: req.body.email })
.then(user => {
if (!user) {
return res.status(401).json({
message: "Authentication failed"
});
}
fetchedUser = user;
console.log("The fetched user is " + fetchedUser);
console.log("The user is " + user);
console.log("The encrypted req.body.password is " + req.body.password);
console.log("The user.password is " + user.password);
return bcrypt.compare(req.body.password, user.password);
})
.then(result => {
console.log("The result is " + result); // It is either false or true
if (!result) {
return res.status(401).json({
message: "Authentication failed" // "Return" prevents execution of next part of code
});
}
const token = jwt.sign(
{ email: fetchedUser.email, userId: fetchedUser._id },
process.env.JWT_KEY,
{ expiresIn: "1h" }
);
res.status(200).json({
token: token, // No need to return because no code afterwards
expiresIn: 3600,
userId: fetchedUser._id
});
console.log("The token is " + token)
})
.catch(err => {
return res.status(401).json({
message: "invalid authentication credentials!"
});
});
};
/* exports.getUsers = (req, res, next) => {
const listofUsers = [
{ id: 12, email: "Narco#test.com" },
{ id: 13, email: "Bombasto#test.com" },
{ id: 14, email: "Celeritas#test.com" },
{ id: 15, email: "Magneta#test.com" },
{ id: 16, email: "RubberMan#test.com" },
{ id: 17, email: "Dynama#test.com" },
{ id: 19, email: "Magma#test.com" },
{ id: 20, email: "Tornado#test.com" }
];
res.status(200).json({
message: "Dummy User ID fetched from the server",
admin: listofUsers
})
} */
exports.getUsers = (req, res, next) => {
const userQuery = User.find();
let fetchedUsers;
userQuery
.then(userDocuments => {
const token = jwt.sign(
{ email: fetchedUser.email, userId: fetchedUser._id },
process.env.JWT_KEY,
{ expiresIn: "1h" }
);
res.status(200).json({
token: token, // No need to return because no code afterwards
expiresIn: 3600,
userId: fetchedUser._id
});
console.log("The token is " + token)
fetchedUsers = userDocuments;
console.log("The fetchedUsers are: "+ fetchedUsers);
return User.count();
})
.then(count => {
res.status(200).json({
message: "Users fetched successfully!",
users: fetchedUsers,
maxUsers: count
});
console.log(fetchedUsers);
})
.catch(error => {
res.status(500).json({
message: "Fetching users failed!"
});
});
}
Thanks
GB

MongoDB & Mongoose: unable to populate a user's posts with .populate()

I've searched this site for days looking through the many different but similar questions on this topic to no avail.
Here's what I'd like to happen. A user signs in and their posts are automatically linked to the users collection. Eventually I'd like to link posts to the profile it was posted to, but i"m not quite there yet. Here's what I've tried so far.
In the User Schema:
const UserSchema = new Schema({
posts: [{
type: Schema.Types.ObjectId,
ref: 'posts'
}],
firstName: {
type: String,
required: true
},
lastName: {
type: String,
required: true
},
...
});
module.exports = User = mongoose.model('users', UserSchema);
In the Post Schema:
const PostSchema = new Schema({
user: {
type: Schema.Types.ObjectId,
ref: 'users'
},
text: {
type: String,
required: true
},
name: {
type: String
},
...
});
module.exports = Post = mongoose.model('posts', PostSchema);
In my users api, here's how I'm signing the user in and attempting to populate the user's posts:
const User = require('../../models/User');
router.post('/login', (req, res) => {
const { errors, isValid } = validateLoginInput(req.body);
// Check Validation
if (! isValid) {
return res.status(400).json(errors);
}
const email = req.body.email;
const password = req.body.password;
// Find user by email
User.findOne({ email })
.populate('posts')
.then(user => {
if (! user) {
errors.email = 'User not found';
return res.status(400).json(errors);
}
// Check password
bcrypt.compare(password, user.password).then(isMatch => {
if (isMatch) {
// User Matched
// Create JWT Payload
const payload = {
id: user.id,
firstName: user.firstName,
lastName: user.lastName,
name: user.firstName + ' ' + user.lastName,
avatar: user.avatar,
posts: user.posts
};
jwt.sign(
payload,
keys.secretOrKey,
{ expiresIn: 3600 }, (err, token) => {
res.json({
success: true,
token: 'Bearer ' + token,
payload
});
});
} else {
errors.password = 'Password is incorrect';
return res.status(400).json(errors);
}
});
});
});
In the posts api, here's how the post is being submitted:
router.post('/', passport.authenticate('jwt', { session: false }), (req, res) => {
const { errors, isValid } = validatePostInput(req.body);
if (! isValid) {
// Return errors with 400 status
return res.status(400).json(errors)
}
const newPost = new Post({
text: req.body.text,
name: req.body.name,
avatar: req.body.avatar,
user: req.user.id
});
newPost.save().then(post => res.json(post));
});
Currently, all I'm seeing is an empty array and no errors. I've been spinning my wheels on this one for a couple days now so any help would be appreciated. Thanks!
I think you forgot to save the _id of your new post to the User model so that the populate() can lookup the posts to populate:
newPost.save().then(post => {
User.update({ _id: req.user.id }, { $push: { posts: post._id }}, (err) => {
res.json(post));
});
});