I am trying to build an ionic application which does basic authentication.
My registration system is working in terms of pushing data into my Firebase URL and logging the user in, adding user into the Login and Auth system, but my login is not doing proper Authentication. Note, this is just the first step - my aim is the check if the user's UID matches the UID I have stored in firebaseurl/uids/firebasekey/uid. I get this error:
Login Failed! TypeError: Cannot read property 'email' of undefined(…)
this is the error that is caught.
Even though I know the user with that email exists in the Firebase instance.
Here is my LoginCtrl:
.controller('LoginCtrl', ['Auth', '$state', '$location', '$scope', '$rootScope', '$firebaseAuth', '$window',
function (Auth, $state, $location, $scope, $rootScope, $firebaseAuth, $window) {
// check session
//$rootScope.checkSession;
// Create a callback to handle the result of the authentication
$scope.user = {
email: this.email,
password: this.password
};
$scope.validateUser = function (user) {
$rootScope.show('Please wait.. Authenticating');
console.log('Please wait.. Authenticating');
var email = this.user.email;
var password = this.user.password;
/* Check user fields*/
if (!email || !password) {
$rootScope.hide();
$rootScope.notify('Error', 'Email or Password is incorrect!');
return;
}
/* All good, let's authentify */
Auth.$authWithPassword({
email: email,
password: password
}).then(function (authData) {
console.log(authData);
$rootScope.userEmail = user.email;
$window.location.href = ('#/app/meals');
$rootScope.hide();
}).catch(function (error) {
console.log("Login Failed!", error);
if (error.code == 'INVALID_EMAIL') {
$rootScope.notify('Invalid Email Address');
}
else if (error.code == 'INVALID_PASSWORD') {
$rootScope.notify('Invalid Password');
}
else if (error.code == 'INVALID_USER') {
$rootScope.notify('Invalid User');
}
else {
$rootScope.notify('Oops something went wrong. Please try again later');
}
$rootScope.hide();
//$rootScope.notify('Error', 'Email or Password is incorrect!');
});
};
this.loginWithGoogle = function loginWithGoogle() {
Auth.$authWithOAuthPopup('google')
.then(function (authData) {
$state.go($location.path('app/meals'));
});
};
this.loginWithFacebook = function loginWithFacebook() {
Auth.$authWithOAuthPopup('facebook')
//Use the authData factory
.then(function (authData) {
$state.go($location.path('app/meals'));
});
};
}
])
And here is my SignupCtrl:
.controller('SignUpCtrl', [
'$scope', '$rootScope', '$firebaseAuth', '$window', 'Auth',
function ($scope, $rootScope, $firebaseAuth, $window, Auth) {
$scope.user = {
firstname: this.firstname,
lastname: this.lastname,
email: "",
password: ""
};
$scope.createUser = function () {
var firstname = this.user.firstname;
var lastname = this.user.lastname;
var email = this.user.email;
var password = this.user.password;
//https://www.firebase.com/docs/web/guide/login/password.html
if (!email || !password) {
$rootScope.notify("Please enter valid credentials");
return false;
}
$rootScope.show('Please wait.. Registering');
$rootScope.auth.$createUser(
{email: email, password: password})
.then(function (user) {
console.log('user is created');
$rootScope.hide();
$rootScope.userEmail = user.email;
var usersRef = new Firebase('https://foodsharingapp.firebaseio.com/users');
var keyRef = usersRef.push({
'uid': user.uid,
'email': email,
'firstname': firstname,
'lastname': lastname
});
var uidRef = new Firebase('https://foodsharingapp.firebaseio.com/uids/' + user.uid + '/' + keyRef.key());
uidRef.set({'registered': true});
$window.location.href = ('#/app/meals');
}, function (error) {
console.log('error unfortunately');
$rootScope.hide();
if (error.code == 'INVALID_EMAIL') {
console.log('invalid email');
$rootScope.notify('Invalid Email Address');
}
else if (error.code == 'EMAIL_TAKEN') {
console.log('email taken');
$rootScope.notify('Email Address already taken');
}
else {
console.log('not sure what happened');
$rootScope.notify('Oops something went wrong. Please try again later');
}
});
}
Auth.$onAuth(function (user) {
if (user === null) {
console.log("Not logged in yet");
} else {
console.log("Logged in as", user.uid);
}
$scope.user = user; // This will display the user's name in our view
});
}
])
And here is my Auth factory:
app.factory('Auth', ['rootRef', '$firebaseAuth',function(rootRef, $firebaseAuth){
return $firebaseAuth(rootRef);
}]);
And here is my app.js related to Auth:
$rootScope.userEmail = null;
$rootScope.baseUrl = 'https://foodsharingapp.firebaseio.com/';
var authRef = new Firebase($rootScope.baseUrl);
$rootScope.auth = $firebaseAuth(authRef);
$rootScope.authData = authRef.getAuth();
$rootScope.logout = function() {
authRef.unauth();
$rootScope.authDataCallBack;
};
$rootScope.checkSession = function() {
if ($rootScope.authData) {
console.log("User " + authData.uid + " is logged in with " + authData.provider);
$rootScope.userEmail = user.email;
$window.location.href = ('#/app/meals');
} else {
console.log("No session so logout");
$rootScope.userEmail = null;
$window.location.href = '#/auth/signin';
}
}
$rootScope.authDataCallBack = function(authData) {
if ($rootScope.authData) {
console.log("User " + authData.uid + " is logged in with " + authData.provider);
} else {
console.log("User is logged out");
$window.location.href = '#/auth/signin';
}
};
//Listens for changes
authRef.onAuth($rootScope.authDataCallback);
Note, the other issue is that the onAuth function in the app.js function is not working.
How should I clean up my code? What am I doing wrong? I am using a bunch of tutorials etc and I don't think the right way.
I have figured out the issue.
$rootScope.userEmail = user.email;
I was calling this line when user is actually undefined as a variable (though $scope.user has been defined).
login controller code
function ($scope, $stateParams, $firebaseAuth, $state) {
$scope.user = {
'email': '',
'password': ''
};
$scope.signIn = function(){
$scope.errorBox = '';
const promise = firebase.auth().signInWithEmailAndPassword($scope.user.email, $scope.user.password);
promise.then(resp => {
$state.go('zazzycoinsActivities');
})
.catch(err => {
$scope.$apply(function(){
$scope.errorBox = err.message;
});
});
};
}
this might work for you too it worked for me......
Related
Hey I'm working on a Login system on my vue project and have the problem that there seems to be no response from the backend.
This is the backend function:
auth.post('/login', async function (req, res) {
const { email, password } = req.body;
console.log(req);
if(email !== "" && password !== "") {
const account = await User.findOne({ where: { email: email} });
if (account) {
if (await account.validPassword(password)) {
// Generate an access token
const accessToken = jwt.sign({ id: account.id }, SECRET);
const account_data =
{
'id': account.id,
'firstName': account.firstName,
'lastName': account.lastName,
'email': account.email,
'isAdmin': account.isAdmin
}
res.send({accessToken, account_data});
} else {
res.status(200).json("Username or password incorrect");
}
} else {
res.send('Username or password incorrect');
}
} else {
res.send('Username or password incorrect');
}
})
This is the method were I call the action
methods: {
async loginUser(){
let user = await this.$store.dispatch('loginUser', this.loginInfo);
if(user.error){
alert(user.error)
} else {
alert('Thank you for signing in, ' + user.firstName);
}
},
}
This is the action:
async loginUser({commit}, loginInfo){
console.log(loginInfo)
try{
let response = await axios({
method: 'POST',
url: 'http://localhost:4000/api/auth/login',
data: loginInfo,
headers: {
// Overwrite Axios's automatically set Content-Type
'Content-Type': 'application/json'
}});
let user = response.data;
console.log(user);
commit('SET_CURRENT_USER', user);
} catch (e){
alert(e);
return {e}
}
}
Neither the console.log in the try function or in the catch function is triggered.
Currently I'm working on a node.js application, with a register function. For this function I need to check a username is already taken or not. Unfortunately the SQL module in node just accepts a callback function from which I cannot send any booleans back.
Here is some code from my controller module:
async function createUser(req, res) {
try {
const salt = await bcrypt.genSalt(); //standard ist 10
const hashedPassword = await bcrypt.hash(req.body.password, salt);
const newUser = {
userName: req.body.username,
userPassword: hashedPassword
};
const userExists = model.checkIfUserExists(newUser.userName);
if (userExists == false){
// create new user
} else {
// Send json back "user already exists
}
res.status(201).json(newUser);
} catch {
res.status(500);
}
}
And here is the code of the model:
function checkIfUserExists(Username){
console.log("Checking if user exists");
let sql = "select * from users where user_name = ?";
db_conn.query(sql, Username, (err, result) => {
if (err){
throw err;
}
console.log(result);
if (result.length > 0){
return true;
} else {
return false;
}
});
}
Unfortunately the "checkIfUserExists" method never returns back a true or false which leads to the "userExists " variable to be null.
I'd like to know how to do return the bollean there or how to solve the problem in a more elegant way.
Please help me to fix this code. Thanks :)
You can either pass a callback to checkIfUserExists or use promises. If I were you, and since you are already using async/await, I would make your return of checkIfUserExists be a promise. So...your code could become
function checkIfUserExists(Username) {
return new Promise((resolve,reject) => {
console.log("Checking if user exists");
let sql = "select * from users where user_name = ?";
db_conn.query(sql, Username, (err, result) => {
if (err) {
throw err;
}
console.log(result);
if (result.length > 0) {
resolve()
} else {
reject()
}
});
})
}
Then, your code that calls this function would be:
async function createUser(req, res) {
try {
const salt = await bcrypt.genSalt(); //standard ist 10
const hashedPassword = await bcrypt.hash(req.body.password, salt);
const newUser = {
userName: req.body.username,
userPassword: hashedPassword
};
await model.checkIfUserExists(newUser.userName).catch(() => {
// Send json back "user already exists
});
// create user
res.status(201).json(newUser);
} catch {
res.status(500);
}
}
First check your catch statement and also add await before model.checkIfUserExists(newUser.userName)
async function createUser(req, res) {
try {
const salt = await bcrypt.genSalt(); //standard ist 10
const hashedPassword = await bcrypt.hash(req.body.password, salt);
const newUser = {
userName: req.body.username,
userPassword: hashedPassword
};
const userExists = await model.checkIfUserExists(newUser.userName);
if (userExists == false){
// create new user
} else {
// Send json back "user already exists
}
res.status(201).json(newUser);
} catch(ex) {
res.status(500);
}
}
return promise from this function:
function checkIfUserExists(Username){
return new Promise((resolve, reject) => {
console.log("Checking if user exists");
let sql = "select * from users where user_name = ?";
db_conn.query(sql, Username, (err, result) => {
if (err){
return reject(err);
}
console.log(result);
if (result.length > 0){
return resolve(true);
} else {
return resolve(false);
}
});
})
}
I'm trying to use the default <'LoginButton ... > for login in the app through Facebook login, but I can't manage to get the user's email.
This is my button:
<LoginButton
publishPermissions={["email"]}
onLoginFinished={
(error, result) => {
if (error) {
alert("Login failed with error: " + error.message);
} else if (result.isCancelled) {
alert("Login was cancelled");
} else {
alert("Login was successful with permissions: " + result.grantedPermissions)
}
}
}
onLogoutFinished={() => alert("User logged out")}
/>
And this is how i try to get the user's details:
async FBGraphRequest(fields, callback) {
const accessData = await AccessToken.getCurrentAccessToken();
console.log("token= ", accessData.accessToken )
// Create a graph request asking for user information
const infoRequest = new GraphRequest('/me', {
accessToken: accessData.accessToken,
parameters: {
fields: {
string: fields
}
}
}, this.FBLoginCallback.bind(this));
// Execute the graph request created above
new GraphRequestManager().addRequest(infoRequest).start();
}
async FBLoginCallback(error, result) {
if (error) {
this.setState({
showLoadingModal: false,
notificationMessage: "facebook error"
});
} else {
// Retrieve and save user details in state. In our case with
// Redux and custom action saveUser
this.setState({
id: result.id,
email: result.email,
name: result.name
});
console.log("facebook login",result)
}
}
The console.log("facebook login",result) line returns me only the account name and id, but there is no field for te email...
What am I doing wrong?
PS.: I've also tryed to use a "custom function", but it doesn't work too (for the email, the login worked and i get only the user details like name and id):
async facebookLogin() {
// native_only config will fail in the case that the user has
// not installed in his device the Facebook app. In this case we
// need to go for webview.
let result;
try {
this.setState({showLoadingModal: true});
LoginManager.setLoginBehavior('NATIVE_ONLY');
result = await LoginManager.logInWithReadPermissions(['public_profile', 'email']);
} catch (nativeError) {
try {
LoginManager.setLoginBehavior('WEB_ONLY');
result = await LoginManager.logInWithReadPermissions(['email']);
} catch (webError) {
// show error message to the user if none of the FB screens
// did not open
}
}
console.log("facebook result 1: ", result)
// handle the case that users clicks cancel button in Login view
if (result.isCancelled) {
this.setState({
showLoadingModal: false,
notificationMessage: I18n.t('welcome.FACEBOOK_CANCEL_LOGIN')
});
} else {
// Create a graph request asking for user information
this.FBGraphRequest('id, email, name', this.FBLoginCallback);
}
}
.
.
.
<LoginButton
publishPermissions={["email"]}
onPress={
this.facebookLogin()
}
onLogoutFinished={() => alert("User logged out")}
/>
this are the field request by the app. I need to insert also the user's Email:
!!!RESOLVED!!!
the <'LoginButton ...> props for the permission is "permissions", not "readPermission"...
so the button code is:
<LoginButton
permissions={['public_profile', 'email', 'user_birthday', ]}
onClick={this.facebookLogin}
/>
// imports
import {
Settings,
AccessToken,
LoginManager,
AuthenticationToken,
Profile,
GraphRequest,
GraphRequestManager,
} from 'react-native-fbsdk-next';
//put this lines in useEffect
Settings.setAppID('2920461228193006');
Settings.initializeSDK();
LoginManager.setLoginBehavior('web_only');
// put this method on button press
LoginManager.logInWithPermissions(['public_profile', 'email'])
.then(async data => {
if (!data.isCancelled) {
console.log(data, 'this is data');
if (Platform.OS === 'ios') {
let token =
await AuthenticationToken.getAuthenticationTokenIOS();
console.log(token, 'ios token');
} else {
let token = await AccessToken.getCurrentAccessToken();
console.log(token, 'android token');
}
const infoRequest = new GraphRequest(
'/me?fields=email,name,first_name,last_name',
null,
(err, res) => {
console.log({err, res}, 'this is');
if (Object.keys(res).length != 0) {
doSocialLogin({
registerBy: 2,
token: res.id,
user: {
firstName: res.first_name,
email: res.email,
lastName: res.last_name,
},
});
}
},
);
new GraphRequestManager().addRequest(infoRequest).start();
}
})
.catch(err => {
console.log(err, 'this is fb error');
});
I got stuck on hashed password validation with bcrypt-nodejs, nodeJS (expressJS) and mongoose. User can register and code generates hashed password but when I try to validate that password with comparePassword function in login page it does not work and gives me error user.comparePassword is not a function
Here is the code:
Database:
UserSchema.pre('save', async function(next){
var user = this;
if(!user.isModified('password')) return next();
bcrypt.genSalt(SALT_WORK_FACTOR, function(err, salt){
if(err) return next(err)
bcrypt.hash(user.password, salt,null, function(err,hash){
if(err) return next(err)
user.password = hash
next()
})
})
})
UserSchema.methods.comparePassword = async function(candidatePassword, cb){
bcrypt.compare(candidatePassword, this.password, function(err, isMatch){
if(err) return cb(err);
cb(null, isMatch)
})
}
Route:
router.post('/', async (req, res) => {
try {
const {username, password} = req.body;
const user = await User.findOne({username}).lean();
if (!user) {
return res.status(404).send({
message: 'user is not registered'
});
}
if(username.trim().length < 1 && password.trim().length < 1){
return res.status(409).send({message: 'username & password is required'})
}
// if (user.password !== password) {
// return res.status(403).send({
// message: 'user password invalid'
//});
//}
user.comparePassword(password, function(err, isMatch){
if(err){
return res.status(500).send({message: err.message})
}
if(!isMatch){
return res.status(403).send({
message: 'user password invali'
});
}
req.session.user = user;
const redirectTo = '/dashboard';
if (
req.is('application/json') // request content type is json
|| // or
req.xhr // is ajax
) {
// respond with json response
return res.status(200).send({redirectTo});
}
// not ajax request
// then respond redirect header
res.redirect(redirectTo);
})
const mongoose = require('mongoose');
var bcrypt = require('bcrypt-nodejs');
SALT_WORK_FACTOR = 10;
const userDataModal = mongoose.Schema({
username: {
type: String,
required : true,
unique:true
},
password: {
type: String,
required : true
}
});
userDataModal.pre('save', function(next) {
var user = this;
// only hash the password if it has been modified (or is new)
if (!user.isModified('password')) return next();
// generate a salt
bcrypt.genSalt(SALT_WORK_FACTOR, function(err, salt) {
if (err) return next(err);
// hash the password using our new salt
bcrypt.hash(user.password, salt, null, function(err, hash) {
if (err) return next(err);
// override the cleartext password with the hashed one
user.password = hash;
next();
});
});
});
userDataModal.methods.comparePassword = function(candidatePassword, cb) {
bcrypt.compare(candidatePassword, this.password, function(err, isMatch) {
if (err) return cb(err);
cb(null, isMatch);
});
};
// Users.index({ emaiId: "emaiId", fname : "fname", lname: "lname" });
const userDatamodal = module.exports = mongoose.model("usertemplates" , userDataModal)
//inserting document
userDataModel.findOne({ username: reqData.username }).then(doc => {
console.log(doc)
if (doc == null) {
let userDataMode = new userDataModel(reqData);
// userDataMode.password = userDataMode.generateHash(reqData.password);
userDataMode.save({new:true}).then(data=>{
let obj={
success:true,
message: "New user registered successfully",
data:data
}
resolve(obj)
}).catch(err=>{
reject(err)
})
}
else {
resolve({
success: true,
docExists: true,
message: "already user registered",
data: doc
}
)
}
}).catch(err => {
console.log(err)
reject(err)
})
//retriving and checking
// test a matching password
user.comparePassword(requestData.password, function(err, isMatch) {
if (err){
reject({
'status': 'Error',
'data': err
});
throw err;
} else {
if(isMatch){
resolve({
'status': true,
'data': user,
'loginStatus' : "successfully Login"
});
console.log('Password123:', isMatch); // -> Password123: true
}
I am trying to reset the user password using the following code and Postman.
But what I realised is that there is no user after I generate the token. the console is saying null;
// Reset User Password
exports.resetPassword = function (req, res) {
User.findOne({
reset_password_token: req.body.token,
reset_password_expires: {
$gt: Date.now()
}
}).exec(function (err, user) {
console.log('this user: ' + user)
if (!err && user) {
if (req.body.newPassword === req.body.verifyPassword) {
user.hash_password = bcrypt.hashSync(req.body.newPassword, 10);
user.reset_password_token = undefined;
user.reset_password_expires = undefined;
user.save(function (err) {
if (err) {
return res.status(422).send({
message: err
});
} else {
console.log(user.hash_password)
}
});
} else {
return res.status(422).send({
message: 'Passwords do not match'
});
}
} else {
return res.status(400).send({
message: 'Password reset token is invalid or has expired.'
});
}
});
};
This is how I use it in Postman
{
"newPassword": "cocacola",
"verifyPassword": "cocacola",
"token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiI1YjI3NjAyNDAwOWI1NDA5ZjMwNzAzZWYiLCJpYXQiOjE1MzA5NjA2NDEwOTN9.1LjroayiTWDNevShnH30n3LxUGCrazmTaJlHgOUNvJ0"
}
and the response in Postman is message from status 400