I am trying to use passportjs with facebook and on sails js.in the middleware, this is my implementation
var verifyHandler = function (token, tokenSecret, profile, done) {
process.nextTick(function () {
//check if the user exist or not
var uid=profile.id;
User.findOne({uid:profile.id}).done(function(err,user){
if(user)
{
console.log('found');
//done(null,user);
}
else
{
console.log('user does not exists');
}
});
};
The weird thing is that it is not able to search through the model.Where Am I doing it wrongly?
I have finally figured it out and I hope it will assist anyone having the same issue with MySQL.
1. Within your user model, the uid datatype should be a STRING not an INTEGER.Please make sure you have effect the same changes on the database table structure to VARCHAR.
2.Change middleware.js verifyHandler to this(omitting parseInt)
var passport = require('passport')
, GitHubStrategy = require('passport-github').Strategy
, FacebookStrategy = require('passport-facebook').Strategy
, GoogleStrategy = require('passport-google-oauth').OAuth2Strategy;
var verifyHandler = function (token, tokenSecret, profile, done) {
process.nextTick(function () {
User.findOne({uid: profile.id}).done(function (err, user) {
if (user) {
return done(null, user);
} 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;
}
User.create(data).done(function (err, user) {
return done(err, user);
});
}
});
});
};
passport.serializeUser(function (user, done) {
done(null, user.uid);
});
passport.deserializeUser(function (uid, done) {
User.findOne({uid:uid}).done(function (err, user) {
done(err, user)
});
});
module.exports = {
// Init custom express middleware
express: {
customMiddleware: function (app) {
passport.use(new FacebookStrategy({
clientID: "****",
clientSecret: "********",
callbackURL: "http://localhost:1337/auth/facebook/callback"
},
verifyHandler
));
app.use(passport.initialize());
app.use(passport.session());
}
}
};
Hope this helps someone out.Cheers!
Related
I am trying to pre save and hash password with bcrypt in mongoose in my next.js project, but password still unhashed. i tryed every link in stackoverflow and didnt solve it, the password still saved unHashed.
mongoose version: 6.9.1
this is my users.model file:
import {
models,
model,
Schema,
} from 'mongoose';
import bcrypt from 'bcrypt';
const UserSchema: Schema = new Schema({
email: {
type: String,
required: true,
unique: true,
},
password: {
type: String,
required: true,
},
displayName: {
type: String,
required: true,
},
role: {
type: String,
},
});
UserSchema.pre('save', function (next) {
console.log('Pre-Save Hash has fired.');
let user = this;
bcrypt.genSalt(10, (err, salt) => {
if (err) console.error(err);
bcrypt.hash(user.password, salt, (err, hash) => {
user.password = hash;
next();
});
});
});
const UserModel = models.Users || model('Users', UserSchema, 'users');
export default UserModel;
this is my adding function file:
import dbConnect from '#/utils/mongodb';
import UserModel from '#/models/user.model';
import { NextApiRequest, NextApiResponse } from 'next';
import { MongoError } from 'mongodb';
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
// const { email, password } = req.query;
try {
dbConnect();
const query = req.body;
const newUser = new UserModel(query);
const addedUser= await newUser.save(function (err: MongoError) {
if (err) {
throw err;
}
});
res.status(200).json(addedUser);
} catch (error) {
console.error(error);
res.status(500).json({ message: 'Internal server error' });
}
}
i cant see the 'Pre-Save Hash has fired.' in my console also..
// You need to add user.isModified("password")
userSchema.pre("save", function (next) {
var user = this;
if (user.isModified("password")) {
bcrypt.genSalt(SALT_I, (err, salt) => {
if (err) {
return next(err);
}
bcrypt.hash(user.password, salt, (err, hash) => {
if (err) {
return next(err);
}
user.password = hash;
next();
});
});
} else {
next();
}
});
userSchema.methods.comparePassword = function (candidatePassword, cb) {
bcrypt.compare(candidatePassword, this.password, (err, isMatch) => {
if (err) return cb(err);
cb(null, isMatch);
});
};
// to make register end point
import mongoose from "mongoose";
import User from "../../../models/User";
const dbConnect = async () => {
mongoose
.connect("mongodb://localhost:27017/test")
.then(() => {
console.log("Connected to mongoDb");
})
.catch((error) => {
console.log(error);
});
};
export default async function handler(req, res) {
try {
await dbConnect();
const query = req.body;
const newUser = new User(query);
await newUser.save(function (err, result) {
if (err) {
throw err;
} else {
res.status(200).json(result);
}
});
} catch (error) {
console.error(error);
res.status(500).json({ message: "Internal server error" });
}
}
thanks to all.
The problem was in my dbconnect file!
When the user tries to log in, the password that is being compared to the compare method of the Student model doesn't hash it.
For example, the value of candidatePassword is the String password the user enters which is compared to this.password, which is a hashed value of the password, thus logging, wrong password in console.
Not sure how to fix it exactly.
studentSchema.pre('save', function save(next) {
const student = this;
if (!student.isModified('password')) {
return next();
}
bcrypt.genSalt(10, (err, salt) => {
if (err) {
return next(err);
}
bcrypt.hash(student.password, salt, (err, hash) => {
if (err) {
return next(err);
}
student.password = hash;
next();
});
});
});
ComparePassword
studentSchema.methods.comparePassword = function (candidatePassword) {
bcrypt.compareSync(candidatePassword, this.password, (err, isMatch) => {
if (err) {
return err;
}
return isMatch;
});
};
LocalStrategy
passport.use('local', new LocalStrategy({
usernameField: 'email'
}, async (email, password, done) => {
const userFound = await STUDENT
.findOne({ email: email.toLowerCase() })
.populate([ '_college', 'enrolledClasses' ]);
if (!userFound) {
console.log('User Does Not Exist');
return done(null, false, 'User Does Not Exist');
}
if (!userFound.comparePassword(password)) {
console.log('Wrong Password'); // getting this error
return done(null, false, 'Wrong Password.');
}
return done(null, userFound);
}));
Login
app.post('/auth/login', passport.authenticate('local', {
successRedirect: '/home',
failureRedirect: '/login'
}));
bcrypt.compareSync does not take in the callback. It returns boolean value. So:
studentSchema.methods.comparePassword = function (candidatePassword) {
return bcrypt.compareSync(candidatePassword, this.password);
}
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.
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
We don’t allow questions seeking recommendations for books, tools, software libraries, and more. You can edit the question so it can be answered with facts and citations.
Closed last month.
Improve this question
Every tutorial or unfinished documentation out there doensn't work. This is why I ask here: Is there a simple tutorial, which really works, for passport and sails?
follow this steps two integrate passport with sails js
first :-
List these dependencies inside application_directory/package.json under dependencies
//application_directory/package.json
{
...
"dependencies": {
...
"passport": "~0.1.16",
"passport-local": "~0.1.6",
"bcrypt": "~0.7.6"
}
...
}
2-
To create user model run the following command:
sails generate model user
3- model user.js will look like the following
var bcrypt = require('bcrypt');
module.exports = {
attributes: {
username: {
type: 'string',
required: true,
unique: true
},
password: {
type: 'string',
required: true
},
toJSON: function() {
var obj = this.toObject();
delete obj.password;
return obj;
}
},
beforeCreate: function(user, cb) {
bcrypt.genSalt(10, function(err, salt) {
bcrypt.hash(user.password, salt, function(err, hash) {
if (err) {
console.log(err);
cb(err);
}else{
user.password = hash;
cb(null, user);
}
});
});
}
};
4- To create a controller in sails type the command
sails generate controller
AuthController will look like the following:
var passport = require('passport');
module.exports = {
login: function (req, res) {
res.view();
},
process: function(req, res){
passport.authenticate('local', function(err, user, info) {
if ((err) || (!user)) {
return res.send({
message: 'login failed'
});
res.send(err);
}
req.logIn(user, function(err) {
if (err) res.send(err);
return res.send({
message: 'login successful'
});
});
})(req, res);
},
logout: function (req,res){
req.logout();
res.send('logout successful');
}
};
module.exports.blueprints = {
actions: true,
rest: true,
shortcuts: true
};
5- add the following code to application_directory/config/routes.js
module.exports.routes = {
// (This would also work if you had a file at: `/views/home.ejs`)
'/': {
view: 'home/index'
},
'/login': {
controller: 'AuthController',
action: 'login'
},
'/logout': {
controller: 'AuthController',
action: 'logout'
}
......
}
6- Inside application_directory/config create a file passport.js and add the following code to that
var passport = require('passport'),
LocalStrategy = require('passport-local').Strategy;
module.exports = {
express: {
customMiddleware: function(app){
console.log('Express midleware for passport');
app.use(passport.initialize());
app.use(passport.session());
}
}
};
7- Inside /api/services/ create a file passport.js and add the following code to that
var passport = require('passport'),
LocalStrategy = require('passport-local').Strategy,
bcrypt = require('bcrypt'); < /code>
//helper functions
function findById(id, fn) {
User.findOne(id).done(function (err, user) {
if (err) {
return fn(null, null);
} else {
return fn(null, user);
}
});
}
function findByUsername(u, fn) {
User.findOne({
username: u
}).done(function (err, user) {
// Error handling
if (err) {
return fn(null, null);
// The User was found successfully!
} else {
return fn(null, user);
}
});
}
passport.serializeUser(function (user, done) {
done(null, user.id);
});
passport.deserializeUser(function (id, done) {
findById(id, function (err, user) {
done(err, user);
});
});
passport.use(new LocalStrategy(
function (username, password, done) {
// asynchronous verification, for effect...
process.nextTick(function () {
findByUsername(username, function (err, user) {
if (err)
return done(null, err);
if (!user) {
return done(null, false, {
message: 'Unknown user ' + username
});
}
bcrypt.compare(password, user.password, function (err, res) {
if (!res)
return done(null, false, {
message: 'Invalid Password'
});
var returnUser = {
username: user.username,
createdAt: user.createdAt,
id: user.id
};
return done(null, returnUser, {
message: 'Logged In Successfully'
});
});
})
});
}
));
8- Modify the authenticated.js file present inside /api/policies/
/**
* Allow any authenticated user.
*/
module.exports = function (req, res, ok) {
// User is allowed, proceed to controller
var is_auth = req.isAuthenticated()
if (is_auth) return next();
// User is not allowed
else return res.redirect("/login");
};
I have an application where the user logs in using facebook account, saving the id, name and email. I'm using https://github.com/jaredhanson/passport-facebook
UserSchema.statics.findOrCreateFaceBookUser = function(profile, done) {
var User = this;
User.findOne({
'email': profile.emails[0].value
}, function(err, user) {
if (err) {
throw err;
}
if (user) {
user.facebook = {
id: profile.id,
email: profile.emails[0].value,
name: profile.displayName
};
user.save(function(err) {
if (err) {
return next(err);
} else {
// done(null, user);
}
});
done(null, user);
} else {
User.findOne({
'facebook.id': profile.id
}, function(err, user) {
if (err) {
throw err;
}
//if (err) return done(err);
if (user) {
done(null, user);
} else {
User.create({
firstName:profile.name.givenName,
lastName:profile.name.familyName,
email: profile.emails[0].value,
gender:profile.gender,
image:"http://graph.facebook.com/"+profile.id+"/picture?type=normal",
facebook: {
id: profile.id,
email: profile.emails[0].value,
name: profile.displayName
}
}, function(err, user) {
if (err) {
throw err;
}
done(null, user);
});
}
});
}
});
The problem is that I need to fetch facebook friends who are also using the application, but the "id" returned by facebook graph does not match what I'm persisting in the application.
https://graph.facebook.com/me/friends?fields=id,name&access_token=xpto
The "profile.id" received the passport-facebook is different from the facebook graph field "id"