need assistance on mongoose model - database

I am new to mongoDB and mongoose. But what I am trying to do is be able to access the users I have stored in my database by their email, if a user was successfully retrieved the I will compare the password they wrote with the hashed password stored in the database
this is what I have for my Schema
UserSchema
var UserSchema = new Schema({
firstName: { type: String, required: true }, //require makes it so that the fields can't be left blank
lastName: {type: String, required: true},
emailAddress: {type: String, required: true},
password: {type: String, required: true}
});
var User = mongoose.model("User", UserSchema);
I am using the basic-auth package in my routes.js file in order to test this api in postman, this is the part where I am stuck, const user = User.find({'emailAddress': credentials.name, user.emailAddress} ); I am having trouble putting together a query to access user email from the database
//This middle-where function will authenticate users
const authenticateUser = (req, res, next) => {
let message = null;
// Parse the user's credentials from the Authorization header.
const credentials = auth(req);
// If the user's credentials are available...
if (credentials) {
// Attempt to retrieve the user from the data store
// by their email (i.e. the user's "key"
// from the Authorization header).
const user = User.find({'emailAddress': credentials.name, user.emailAddress} );
// If a user was successfully retrieved from the data store...
if (user) {
// Use the bcryptjs npm package to compare the user's password
// (from the Authorization header) to the user's password
// that was retrieved from the data store.
const authenticated = bcryptjs
.compareSync(credentials.pass, user.password);
in this express router I will be returning a user only after being authenticated
//GET /api/users 200, THIS WORKS IN POSTMAN
//This Route returns the currently authenticated user,
router.get('/users', authenticateUser, (req, res) => {
//within the route handler, the current authenticated user's information is retrieved from the Request object's currentUser property:
const user = req.currentUser;
//we use the Response object's json() method to return the current user's information formatted as JSON:
res.json({
firstName: user.firstName,
lastName: user.lastName,
});
});
Can someone help? For reference this is my repo https://github.com/SpaceXar20/rest_api-mongo-p9

here the way you find() is wrong
it should be either a callback or a exec() with async await.. this case just use callbacks
so instead of this code,
const user = User.find({'emailAddress': credentials.name, user.emailAddress} );
use this code
User.find({emailAddress:user.emailAddress},(err,user)={
if(err) throw err;
// do what you please
if (user) {
bcrypt.compare(password,hash,function(err,isMatch){
if(err) callback(err,null);
callback(null,isMatch);
});
} );

Related

Linking Twitter account to user account (twitter-passport)

Currently, a user is able to login in and sign up for my application no problem. I've then added a "Link your twitter user to account" button which when clicked takes the user to '/auth/twitter'. This then kicks off passport-twitter and the oAuth process begins.
Right now, I'm using passport-twitter as the package for twitter oAuth. This process works. I'm able to get the user successfully authenticated. Here is the code.
However two problems: I don't see a way to 1) keep the user signed into Twitter so they don't have to keep doing this flow of reconnecting their twitter every time they want to push content to it from my app. and 2) associate the Twitter user and the signed in user to my application. Long term, I plan to add other social media accounts, so the user will have multiple social media linked. Twitter will be just one.
Problem #2: I wasn't able to do an axios.get call from my redux store or from the front end to '/auth/twitter/' otherwise I could then just get the information back from the call and then post it to the user's table (right?). So, instead I'm accessing '/auth/twitter' from an tag in the front end to kick off the flow.
passport.use(
new TwitterStrategy(
{
consumerKey: "XXX",
consumerSecret: "XXX",
callbackURL: "http://localhost:8080/auth/twitter/callback",
// callbackURL: "http://www.localhost:8080/home",
includeEmail: true,
},
async(accessToken, refreshToken, profile, cb) => {
console.log('got the prodile')
const twitterIDforOAuth = profile.id
const { id, username } = profile;
let theuser = await User.findOne({
where: {
twitterID: id
}
})
if(theuser){
console.log('FOUND USER', '\n', theuser)
} else {
try {
console.log('NO USER FOUND')
var passwordUser = (Math.random() + 1).toString(36).substring(7);
console.log('CREATING USER')
theuser = await Promise.all([
User.create({
twitterID: id,
username : username,
password: passwordUser
})
])
console.log('USER CREATED');
} catch (error) {
console.log(error);
}
}
//this callback calls the auth/callback url to kick off the redirect process
// need to send username and password to /auth/signup
return cb(null, {username: username, password: passwordUser})
//Line below sends too much data that is irrelevant for the user... lets review it?
// return cb(null, {username: twitterIDforOAuth})
}
)
);
app.get('/auth/twitter', passport.authenticate("twitter"));
app.get(
"/auth/twitter/callback",
passport.authenticate("twitter", {
failureRedirect: "/login",
failureMessage: true,
session: false
}),
async (req, res) => {
var user = req.user;
console.log(user.username, user.password);
//GET USERNAME AND PASSWORD
var username = user.username;
var password = user.password;
///they need to login the app
//auth/login
res.redirect('/AccountSettings')
}
);
The user is being redirected to /AccountSettings while they go through this flow, so I know that the user is 100% authenticated and signed in with Twitter (otherwise they'd be pushed to /login, which isn't happen).
Most people in this flow create a user in their database using the information returned from Twitter.
However, I'm trying to link this information to the signed in user, and keep them signed into Twitter so the user doesn't need to keep reconnecting their Twitter account (at least not often). (With access to their Twitter account, my plan is to allow them to push content to it)
Currently I'm hitting the '/auth/twitter' route with an tag which's href takes it to '/auth/twitter'. Is this the right way about it or is this approach causing my linkage issue?
What are people's recommendation for this issue? Whats the right way to approach linking social media accounts to a signed in user's account?
I'm using Express, Redux, React, Postgres, and passport-twitter
SOLUTION: How to passing data in TwitterStrategy, PassportJS?
had to create a state object outside the /auth/twitter route and then added a id param to the /auth/twitter route so the full route was /auth/twitter/:id
once I got the id I saved it to a state route outside the route in the server file that was accessible to the callback function later in the proces.

How do I store more information in Firebase for a user than the Auth module allows?

The Authorization module in Firebase only allows me to store a user's email and password; but I want to store more information, like: name, phone number, list of games they own, etc. How do I do that in firebase?
Choosing Firebase for data storage is good choice in my view. Because, it is easy to use and less expensive.
Coming to the problem, you can't set additional data to the authentication table in Firebase console.
It just shows email and unique user id and doesn't show even password used for registration.
One of the easy way of storing user information in Firebase is as follows.
After success of login or signup of user, you will get user's unique id.
function(error, userData) {
if (error) {
console.log("Error creating user:", error);
} else {
console.log("Successfully created user account with uid:", userData.uid);
}
With that user id, you can create an object in Firebase database.
function(error, userData) {
if (error) {
console.log("Error creating user:", error);
} else {
var userId = userData.uid;
var ref = new Firebase('https://docs-examples.firebaseio.com/web/data');
var userRef = ref.child('users/' + userId);
userRef.set({
email: "userEmail",
name: "userName",
phoneNumber: "userPhoneNumber",
password: "userPassword",
interestedGames: {
"game1": true,
"game2": true,
"game3": true
}
});
}
You can retrieve the data of the user using childRef as I shown above,
that you can get when user logs in.

Getting Username from Firebase after email/password login [React Native]

I have created a simple login app using react native that let's users signup, login, and logout. my signup function takes a username that is then used in the createUser callback to generate a db entry with the uid as the key, and the username entered as a value. The answer in this post is the structure I followed - How do you include a username when storing email and password using Firebase (BaaS) in an Android app?
After the user is logged in, I'd like to get the username and display it but I'm having trouble figuring this out.
This is the code I currently have to attempt and do it:
var ref = new Firebase("https://myreactapp.firebaseio.com");
module.exports = React.createClass({
getInitialState: function() {
var authData = ref.getAuth();
var user = ref.child("users/" + authData.uid + "/username");
return {
username: user
};
},
This is how the code looks when I signup and the structure of my db.
var self = this;
let ref = new Firebase("https://myreactapp.firebaseio.com");
ref.createUser({
email : this.state.email,
password : this.state.password
}, function(error, authData) {
if (error) {
return this.setState({errorMessage: 'Error creating user'});
} else {
ref.child("users").child(authData.uid).set({
username: self.state.username
});
console.log("Successfully created user account with uid:", authData.uid);
ToastAndroid.show('Account Created', ToastAndroid.SHORT)
return self.props.navigator.pop();
}
});
----------------Not actual code-------------------------------------------------
DB
+users
--<uid>
-username -> value
--<uid>
-username -> value
I try to login and get an error of maximum call stack exceeded, but I have a feeling I'm going at this the wrong way. I've looked online, but everything I found was for retrieving data that is either being added, changed or deleted. All I want is to get this username once.

Using passport-facebook without Mongoose User (No Mongo in the MEAN stack)

I'm very new to the MEAN stack, and this might seem to be very naive or wrong approach, but I want to ask that when we authenticate using passport-facebook strategy, using the following code:
var FacebookStrategy = require('passport-facebook').Strategy;
var User = require('../models/user');
var fbConfig = require('../fb.js');
module.exports = function(passport) {
passport.use('facebook', new FacebookStrategy({
clientID : fbConfig.appID,
clientSecret : fbConfig.appSecret,
callbackURL : fbConfig.callbackUrl
},
// facebook will send back the tokens and profile
function(access_token, refresh_token, profile, done) {
console.log('profile', profile);
// asynchronous
process.nextTick(function() {
// find the user in the database based on their facebook id
User.findOne({ 'id' : profile.id }, function(err, user) {
// if there is an error, stop everything and return that
// ie an error connecting to the database
if (err)
return done(err);
// if the user is found, then log them in
if (user) {
return done(null, user); // user found, return that user
} else {
// if there is no user found with that facebook id, create them
var newUser = new User();
// set all of the facebook information in our user model
newUser.fb.id = profile.id; // set the users facebook id
newUser.fb.access_token = access_token; // we will save the token that facebook provides to the user
newUser.fb.firstName = profile.name.givenName;
newUser.fb.lastName = profile.name.familyName; // look at the passport user profile to see how names are returned
//newUser.fb.email = profile.emails[0].value; // facebook can return multiple emails so we'll take the first
// save our user to the database
newUser.save(function(err) {
if (err)
throw err;
// if successful, return the new user
return done(null, newUser);
});
}
});
});
}));
};
I don't need to store the user information in any data store. I want to store the token only for the time the user is logged into my web application, basically I don't have the need to use Mongo, because all the data that will be displayed in the web application will come from Facebook api, for example the posts for a profile, the number of likes on a particular posts etc. I don't need to have a backend as such, because if I store the data in any data store such as Mongo, the next time the user login then the data will be stale (in a way the Facebook api is kind of my backend), and I also want that the updates for information on any posts done on Facebook should be updated realtime on my web application for e.g. if someone likes a post on the actual Facebook page the number of likes on my web application should also be updated in realtime, so it seems unnecessary to first bring the data from the Facebook SDK and then store it in Mongo, why not just give it to the controller and from there the view can present the data. If my approach is wrong please do correct me.
So basically every time the user logs in an access token is created and used for that session, when the user logs out the access token is destroyed and so completely eliminates the need for storing the token and any data that is brought in using the Facebook SDK.
Replace the function call
User.findOne({ 'id' : profile.id }, function(err, user) {
With facebook sdk authentication call and return the user object when it's validated.
return done(null, user);
Please refer...
https://github.com/jaredhanson/passport-facebook
you need to create a new user template in the model folder. I have created the following: user.js
var facebook = module.exports.facebook = {
id : String,
token : String,
email : String,
name : String
}
and then change the passport.serializeUser and passport.deserializeUser functions.
passport.serializeUser(function(user, done) {
done(null, user.facebook.id);
});
// used to deserialize the user
//passport.deserializeUser(function(id, done) {
passport.deserializeUser(function(id, done) {
done(null, { id: User.facebook.id, token: User.facebook.token, name: User.facebook.name, email: User.facebook.email})
});
then the function: process.nextTick(function() {} replace the content by this code :
var newUser = User;
// set all of the facebook information in our user model
newUser.facebook.id = profile.id; // set the users facebook id
newUser.facebook.token = token; // we will save the token that facebook provides to the user
newUser.facebook.name = profile.name.givenName + ' ' + profile.name.familyName; // look at the passport user profile to see how names are returned
newUser.facebook.email = profile.emails[0].value; // facebook can return multiple emails so we'll take the first
return done(null, newUser);
add the line profileFields: ['id', 'displayName', 'photos', 'emails', 'name'] in function passport.use(new FacebookStrategy({}
change the profile.ejs file by removing the local information div and changing the properties <% = user.facebook.id%> to <% = user.id%> and so on in the others.

Firebase Angularfire authentication. Create user works but user data (email address) is not stored.

I've been struggling with this problem for a couple of days, I am able to create a user but I cannot save their email address under a users node.
register: function(user) {
return auth.$createUser({
email: user.email,
password: user.password
}).then(function(regUser) {
var ref = new Firebase(FIREBASE_URL+'users');
var userInfo = {
key : regUser.uid, // ex: simplelogin:29
date : Firebase.ServerValue.TIMESTAMP,
email : user.email,
}; // user info
ref.child(users).set(userInfo);
});
Here are a couple issues i see:
No specific shild node for each user. You are trying to save the userInfo directly in the users node instead of making a child node under users.
Firebase rules. Without knowing the rules you use i can't know for sure if this applies but can everyone write to that specific node or do you have to be logged in first?
Making the reference. Without knowing what FIREBASE_URL exactly is i can't tell if it's an isuue but if there isn't a / at the end doing + 'users' will give a wrong reference. I suggest using child as Frank also commented.
Resulting code would be something like this (don't forget to check your firebase rules):
register: function(user) {
return auth.$createUser({
email: user.email,
password: user.password
}, function(error) {
if (error) {
//catch possible errors
} else {
//no error, user has been created
//start with logging user in to have firebase write acces
auth.$authWithPassword({
email: user.email,
password: user.password
}, function(error, authData) {
if (error === null) {
//no error so log in succesfull
//Making the firebase reference
var ref = new Firebase(FIREBASE_URL).child("users");
//Get user id
var uid = authData.uid;
//Set data in firebase making a child using the user id
ref.child(uid).set({
key: regUser.uid, // ex: simplelogin:29
date: Firebase.ServerValue.TIMESTAMP,
email: user.email,
});
});
}
)};
}

Resources