Unable to receive email address in sailsjs from passportjs - facebook

I'm unable to get the email address from facebook when i'm making the following call...
// https://developers.facebook.com/docs/
// https://developers.facebook.com/docs/reference/login/
facebook: function(req, res) {
passport.authenticate('facebook', { scope : ['email'] }, function(err, user) {
req.logIn(user, function(err) {
if (err) {
return;
}
res.redirect('/');
return;
});
})(req, res);
},
This is how the response is handled and is basically the PassportJS docs code.
customMiddleware: function(app) {
passport.use(new FacebookStrategy({
clientID: "5xxxxxxxxxxxxx6",
clientSecret: "exxxxxxxxxxxxxxxxxxxxxxxxxxxd9",
callbackURL: "http://localhost:1337/auth/facebook/callback"
}, verifyHandler));
app.use(passport.initialize());
app.use(passport.session());
}
And here is the handler.
var passport = require('passport')
, FacebookStrategy = require('passport-facebook').Strategy;
var verifyHandler = function(token, tokenSecret, profile, done) {
process.nextTick(function() {
sails.log.info(profile);
Serviceseeker.findOne({uid: profile.id}, function(err, serviceseeker) {
if (serviceseeker) {
return done(null, serviceseeker);
}
else {
var data = {
provider: profile.provider,
uid: profile.id,
name: profile.displayName
};
if (profile.emails && profile.emails[0] && profile.emails[0].value) {
data.email = profile.emails[0].value;
}
if (profile.name && profile.name.givenName) {
data.firstName = profile.name.givenName;
}
if (profile.name && profile.name.familyName) {
data.lastName = profile.name.familyName;
}
Serviceseeker.create(data, function(err, serviceseeker) {
return done(err, serviceseeker);
});
}
});
});
};
And this is the response that I'm getting
info: info: { id: '1xxxxxxxxxxxxxx9',
username: undefined,
displayName: 'Txxxx Slxxxxn',
name:
{ familyName: undefined,
givenName: undefined,
middleName: undefined },
gender: undefined,
profileUrl: undefined,
provider: 'facebook',
_raw: '{"name":"Txxxx Slxxxxn","id":"1xxxxxxxxxxxxxx9"}',
_json: { name: 'Txxxx Slxxxxn', id: '1xxxxxxxxxxxxxx9' } }

Did you try:
passport.use(new FacebookStrategy({
clientID: 'CLIENT_ID',
clientSecret: 'CLIENT_SECRET',
callbackURL: "http://www.example.com/auth/facebook/callback"
passReqToCallback : true,
profileFields: ['id', 'emails', 'name'] //This
},

Related

How do I retrieve what I return? (GraphQL query newbie)

I wrote 2 resolvers (signup and login). They return a JWToken. In playground, I'm testing the functions and it won't let me make a mutation without specifying some subfields to display. They all are null and sometimes I get a "Cannot return null for non-nullable field users._id". I'm using express and mongodb.
const { UserTC, UserSchema } = require("../models/user");
const bcrypt = require('bcrypt')
const jsonwebtoken = require('jsonwebtoken')
const resolver = function () {};
resolver.me = UserTC.addResolver({
name: "me",
type: UserTC,
args: { record: UserTC.getInputType() },
resolve: async ({ source, args }) => {
if (!args.record) {
throw new Error('You are not authenticated!')
}
return await UserSchema.findById(args.record._id)
}
});
resolver.signup = UserTC.addResolver({
name: "signup",
type: UserTC,
args: { record: UserTC.getInputType() },
resolve: async ({ source, args }) => {
const user = await UserSchema.create({
firstName: args.record.firstName,
lastName: args.record.lastName,
email: args.record.email,
password: await bcrypt.hash(args.record.password, 10)
});
return jsonwebtoken.sign(
{ id: user._id, email: user.email },
process.env.JWT_SECRET,
{ expiresIn: '1y' }
)
},
});
resolver.login = UserTC.addResolver({
name: "login",
type: UserTC,
args: { record: UserTC.getInputType() },
resolve: async ({ source, args }) => {
const user = await UserSchema.findOne({email: args.record.email });
if (!user) {
throw new Error('Incorrect email')
}
const valid = await bcrypt.compare(args.record.password, user.password);
if (!valid) {
throw new Error('Incorrect password')
}
return jsonwebtoken.sign(
{ id: user._id, email: user.email },
process.env.JWT_SECRET,
{ expiresIn: '1y' }
)
},
});
module.exports = resolver;
Here are the queries:
mutation {
signup(
record: {
firstName: "Ben2"
lastName: "Dormant"
email: "Ben2.Dormant#gmail.com"
password: "qwerty"
}
)
}
mutation {
login(record: {
email: "nicolas.sursock#gmail.com",
password: "azerty" })
}
I founded a bug, try like this because you can not use await in reutrn
resolver.me = UserTC.addResolver({
name: "me",
type: UserTC,
args: { record: UserTC.getInputType() },
resolve: async ({ source, args }) => {
if (!args.record) {
throw new Error('You are not authenticated!')
}
let result = await UserSchema.findById(args.record._id)
return result
}
});

I can't update a users info to add a password reset link

I'm having trouble getting a variable within a database user to update using lodash. It seems to update in one route (password in /resetpassword) but not in the other. (resetLink in /forgotpassword)
I need to have "resetLink" update to the new token generated by JWT, in order to create a link to reset the users password.
/forgotpassword
router.put('/forgotpassword', (req, res) => {
const { email } = req.body;
if (!email) {
return res.status(400).json({ msg: "Please enter all fields" });
} else {
// Find existing User by email address
User.findOne({ email }).then((user) => {
if (!user) return res.status(400).json({ msg: "That email doesn't exist with us..." });
const payload = {
id: user._id,
}
const secret = process.env.JWT_SECRET;
const token = jwt.sign(payload, secret, {
expiresIn: '15m'
});
const obj = {
resetLink: token
}
console.log("obj is " + JSON.stringify(obj));
console.log("User is " + user);
user = _.extend(user, obj);
user.save((err, result) => {
if (err) {
return res.status(400).json({{ error: "Something went wrong..." + err }});
} else {
return res.status(200).json({ msg: "Success! These should match: TOKEN - " + token + " / RESET LINK - " + user.resetLink })
}
})
});
};
});
/resetpassword
router.put('/resetpassword', (req, res) => {
const { resetLink, newPass } = req.body;
if (resetLink) {
jwt.verify(resetLink, process.env.JWT_SECRET, function (err, decodedData) {
if (err) {
return res.status(401).json({ msg: "Incorrect token or it is expired." });
}
User.findOne({ resetLink }, (err, user) => {
if (err || !user) {
return res.status(400).json({ error: "User with this token doesn't exist" });
}
// newPass will be hashed by jwt eventually
const obj = {
password: newPass
}
user = _.extend(user, obj);
user.save((err, result) => {
if (err) {
return res.status(400).json({ error: "Reset password error" });
} else {
return res.status(200).json({ message: "Your password has been changed" });
}
})
})
})
} else {
return res.status(401).json({ error: "Authentication error!" });
}
});
Mongoose User model
const UserSchema = new Schema({
name: {
type: String,
required: true,
},
email: {
type: String,
required: true,
unique: true,
lowercase: true,
},
password: {
type: String,
required: true,
},
register_date: {
type: Date,
default: Date.now,
},
resetLink: {
data: String,
default: '',
}
});
As always I appreciate any help at all. Thanks.
EDIT: Here is the returned error -
"error": "Something went wrong...ValidationError: resetLink: Cast to Object failed for value \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjVmM2JjN2MwNGVmMmRkNGE2ODkwZDEwYiIsImlhdCI6MTU5Nzc1NDY2MCwiZXhwIjoxNTk3NzU1NTYwfQ.BL8yYsqk2A5hGlNTPa2AxtD_iJ1lWELiCgtpcCkFB6I\" at path \"resetLink\""
My Schema was off. Apologies.
resetLink: {
data: String,
default: '',
}
Should be:
resetLink: {
Type: String,
default: '',
}

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

I have an error with passport.js implementation in Sails.js

I have a problem with Sails Passport implementation. This error appears in my terminal:
/home/tatico/sinGualichoPassport/config/passport.js:19
if (!user.validPassword(password)) {
^
TypeError: user.validPassword is not a function
at /home/tatico/sinGualichoPassport/config/passport.js:19:17
at returnResults (/home/tatico/.npm-global/lib/node_modules/sails/node_modules/waterline/lib/waterline/query/finders/basic.js:180:9)
at /home/tatico/.npm-global/lib/node_modules/sails/node_modules/waterline/lib/waterline/query/finders/basic.js:86:16
at /home/tatico/.npm-global/lib/node_modules/sails/node_modules/waterline/lib/waterline/query/finders/operations.js:83:7
at /home/tatico/.npm-global/lib/node_modules/sails/node_modules/waterline/node_modules/async/lib/async.js:52:16
at Object.async.forEachOf.async.eachOf (/home/tatico/.npm-global/lib/node_modules/sails/node_modules/waterline/node_modules/async/lib/async.js:236:30)
at Object.async.forEach.async.each (/home/tatico/.npm-global/lib/node_modules/sails/node_modules/waterline/node_modules/async/lib/async.js:209:22)
at /home/tatico/.npm-global/lib/node_modules/sails/node_modules/waterline/lib/waterline/query/finders/operations.js:436:11
at /home/tatico/.npm-global/lib/node_modules/sails/node_modules/waterline/lib/waterline/query/finders/operations.js:574:5
at /home/tatico/.npm-global/lib/node_modules/sails/node_modules/waterline/node_modules/async/lib/async.js:52:16
at Object.async.forEachOf.async.eachOf (/home/tatico/.npm-global/lib/node_modules/sails/node_modules/waterline/node_modules/async/lib/async.js:236:30)
at Object.async.forEach.async.each (/home/tatico/.npm-global/lib/node_modules/sails/node_modules/waterline/node_modules/async/lib/async.js:209:22)
at _buildChildOpts (/home/tatico/.npm-global/lib/node_modules/sails/node_modules/waterline/lib/waterline/query/finders/operations.js:464:9)
at _execChildOpts (/home/tatico/.npm-global/lib/node_modules/sails/node_modules/waterline/lib/waterline/query/finders/operations.js:432:8)
at /home/tatico/.npm-global/lib/node_modules/sails/node_modules/waterline/lib/waterline/query/finders/operations.js:81:10
at wrapper (/home/tatico/.npm-global/lib/node_modules/sails/node_modules/waterline/node_modules/lodash/index.js:3592:19)
at applyInOriginalCtx (/home/tatico/.npm-global/lib/node_modules/sails/node_modules/waterline/lib/waterline/utils/normalize.js:421:80)
at wrappedCallback (/home/tatico/.npm-global/lib/node_modules/sails/node_modules/waterline/lib/waterline/utils/normalize.js:324:18)
at callback.success (/home/tatico/.npm-global/lib/node_modules/sails/node_modules/waterline/node_modules/switchback/lib/normalize.js:33:31)
at _switch (/home/tatico/.npm-global/lib/node_modules/sails/node_modules/waterline/node_modules/switchback/lib/factory.js:58:28)
at /home/tatico/.npm-global/lib/node_modules/sails/node_modules/waterline/lib/waterline/adapter/dql.js:166:7
at wrapper (/home/tatico/.npm-global/lib/node_modules/sails/node_modules/waterline/node_modules/lodash/index.js:3592:19)
This is my Files:
config/passport.js:
var passport = require('passport'),
LocalStrategy = require('passport-local').Strategy
bcrypt = require('bcrypt');
passport.use(new LocalStrategy(
function(username, password, done) {
User.findOne({ username: username }, function(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(id, done) {
User.findById(id, function(err, user) {
done(err, user);
});
});
module.exports = {
http: {
customMiddleware: function(app){
console.log('Express midleware for passport');
app.use(express.static('public'));
app.use(express.cookieParser());
app.use(express.bodyParser());
app.use(express.session({ secret: 'keyboard cat' }));
app.use(passport.initialize());
app.use(passport.session());
app.use(app.router);
app.use(function(req,res,next){
// Set the loggedUser in locals *does it work?
// to get it from the view
res.locals.loggedUser = req.user;
next();
});
}
}
};
UserController.js
module.exports = {
auth: function(req, res) {
return res.view();
},
create: function(req, res, next) {
User.create( req.params.all(), function createdUser(err, user){
if (err) {
return res.negotiate(err);
}
req.session.authenticated = true;
req.session.user = user;
return res.json(user);
});
},
login: function(req, res, next) {
// Use Passport LocalStrategy
require('passport').authenticate('local', function(err, user, info){
if ((err) || (!user)) next(err);
req.login(user, function(err){
if (err) return res.redirect('/user/auth');
// Redirect to the user page.
return res.redirect('/user/' + user.id);
});
})(req, res);
},
logout: function(req, res){
// Call Passport method to destroy the session.
req.logout();
// Redirect to home page.
return res.redirect('/');
}
};
User.js:
module.exports = {
attributes: {
email: {
type: 'string',
required: true,
email: true,
unique: true
},
password: {
type: 'string',
required: true
},
username: {
type: 'string',
required: true,
unique: true
},
toJSON: function() {
var obj = this.toObject();
delete obj.password;
return obj;
}
},
// Lifecycle Callbacks
beforeCreate: function(values, next) {
hashPassword(values, next);
},
beforeUpdate: function(values, next) {
if(values.password) hashPassword(values, next);
else next();
}
}
var bcrypt = require('bcrypt');
function hashPassword(values, next) {
bcrypt.hash(values.password, 10, function(err, hash) {
if (err) return next(err);
values.password = hash;
next();
});
}
Im new in Sails, and I suppose this is a not good implementantion, Anyone can Help me and give a little feed back to improve my understanding of Sails and Passport? Thanks.
ValidPassword is not defined anywhere which is leading to this error.

Sails.js: cannot do POST for inserting into mongoDB

I am trying to write a toy program for submitting form and inserting into mongodb, but I keep getting DB error. Let me paste the relevant code here, and I hope to get some help.
I am using Sails ver 0.10.5 and the latest mongo 2.6.5, and my I run node on my Mac OSX 10.9:
Model: Employee.js
module.exports = {
attributes: {
name: {
type: "string",
required: true
},
email: {
type: "string",
required: true
},
password: {
type: "string",
required: true
}
},
beforeCreate: function(values, next) {
next();
}
};
route.js:
module.exports.routes = {
'/registeremployee': {
controller: 'employee',
action: 'register'
},
'/listemployees': {
controller: 'employee',
action: 'list_all'
}
};
EmployeeController.js
module.exports = {
index: function(req, res) {
res.send(200, {title: "employee index page"});
},
list_all: function(req, res) {
Employee.find().exec(function(err, employee) {
if (err) {
res.send(500, {title: 'error retrieving users'});
} else {
res.send(200, {'employees': employee});
}
});
},
register: function(req, res) {
if (req.method == "GET") {
res.view({title: "Form for registering employees"});
} else if (req.method == "POST") {
var username = req.param("username");
var password = req.param("password");
var email = req.param("email");
console.log("saving the username: " + username); //username printed as 'undefined'
Employee.create({username: username, password: password, email: email}).exec(function(error, employee) {
if (error) {
console.log('error');
res.send(500, {error: "DB error!"});
} else {
console.log('error');
res.send(200, employee);
console.log("saved employee: " + employee.username);
}
});
}
}
};
Lastly, the register.ejs template file:
List All Users
<h2>Form - Create a User</h2>
<form action="/registeremployee" method="POST">
<table>
<tr><td>Name</td><td><input type=”text” name=”username” required></td></tr>
<tr><td>Password</td><td><input type=”password” name=”password” required></td></tr>
<tr><td>Email</td><td><input type=”email” name=”email” required></td></tr>
<tr><td></td><td><input type="submit"></td>
</table>
</form>
It looks to me that the form does not submit data, as the parameters are printed as undefined/null in my controller.
I have this in my connections.js:
mongo: {
adapter: 'sails-mongo',
host: 'localhost',
port: 27017,
user: '',
password: '',
database: 'sailsApp1'
}
just replace name to username and you are able to save data in db.
module.exports = {
attributes: {
username: {
type: "string", required: true },
email: { type: "string", required: true },
password: { type: "string", required: true } },
beforeCreate: function(values, next) { next(); } };