This is my node.js code. There are two inputs on site, one for username and one for the password. When users enter them, function client.logOn gets them. But there is a third step. The user need to enter the code which he gets on his phone. So, when the user enter the username and password, the script will check if they are good, and if they are, the script will ask me for "twoFactorCode" in cmd, and when I enter it there, everything works. But I want users to enter that code on the page. So how can I do it? In cmd, I only need to enter that 5 character code.
app.post('/api', (request, response) => {
console.log('i got request');
client.logOn({
accountName: request.body.uName,
password: request.body.uPassword,
});});
client.on('loggedOn', () => {
console.log("Logged in");
});
Related
I am designing 2 pages for a user signing up. The first page is where the user enters their email only. I then perform this code.
await createUserWithEmailAndPassword(auth, email.value, bcrypt.hashSync(email.value, 6))
.then(async (userCredential) => {
sendEmailVerification(userCredential.user)
loading = false
navigate('/verifyEmail')
})
.catch((error) => {
log.error(`Error registering user: ${error}`)
errorMessage = error.message
isEmailInvalid = true
loading = false
})
This sends the user a verification email, which they then click on to set their password and name:
let oobCode = ''
oobCode = window.location.href.split('oobCode=')[1].split('&')[0]
const email = window.location.href.split('email=')[1].split('/')[0]
let user = auth.currentUser
await applyActionCode(auth, oobCode)
.then(async (result) => {
console.log(auth.currentUser)
Promise.all([
updateProfile(auth.currentUser, {displayName: firstName + ' ' + lastName}),
updatePassword(auth.currentUser, password),
])
console.log('Welcome', firstName, lastName)
await setUser('local', undefined, auth.currentUser)
})
However at this point, auth.currentUser will be null if the user has clicked on this link on a different browser. A quick workaround would be to create a user with password 'password' and then sign them in after applying the action code. However this has a big security flaw obviously, my current idea just encrypts their email as a temporary password in hopes they cannot guess it and sign in.
I guess my question is, how do I update the user upon applying an action code? If I can't do this what flow of operations should I change?
My question is, how do I update the user upon applying an action code?
If the user is using another browser it is not possible since he/she does not know the password.
If I can't do this what flow of operations should I change?
IMHO you are overcomplexifying the onboarding process. The common approach is to create the account with the password being chosen by the user (which, in your case, should happen in the first screen) and send the email for verification.
In parallel you deny access to the Firebase back-ends (DBs, Cloud Storage, etc.) to users with non verified email via the Security Rules.
Upon email verification you sign in the user:
If it is from the same browser the users is actually already signed in (side effect of the use of createUserWithEmailAndPassword()
If it is in a different browser the user just has to enter his email and password (which he/she knows)
I'm a newbie at node.js, and trying to make a login page.
When I'm trying to login with the right credentials the page works as intended. Also worth noting is that when I try to login with no credentials the alert window pops up. But when I try to login with the wrong credentials, it just won't work. I've tracked the error back to "alert" function, but I cannot understand why in the world the alert function works when calling it to display the alert that no username nor password was inserted, but will crash when I'm trying to display that the username and password are wrong. I'm pretty certain that the error comes from the alert function.
The code is below.
Thanks alot!
app.post('/auth', function(request, response) {
var username = request.body.username;
var password = request.body.password;
if (username && password) {
connection.query('SELECT * FROM accounts WHERE username = ? AND password = ?', [username, password], function(error, results, fields) {
if (results.length > 0) {
request.session.loggedin = true;
request.session.username = username;
response.redirect('/home');
response.end();
} else {
alert('Incorrect Username and/or Password!');
}
});
} else {
alert('Please enter Username and Password!');
}
});
but I cannot understand why in the world the alert function works when calling it to display the alert that no username nor password was inserted
It shouldn't do.
alert isn't a function provided by Node.js. It belongs to browsers so it can show something in the browser UI.
To send something from a server built on Node.js back to the browser then:
The something needs to be data
You need to send it by calling a method (like render, json or send) on the response object.
My solution works, but I'm not sure this is safe and appropriate. On the front end I have a ReactJS app that send with axios a request with the login and password. On the back end I have NodeJS + ExpressJS handling the request as follows:
router.post('/', function(req, res, next) {
// get the records that match the login provided
const sql = "SELECT name, surname, login, password, blocked FROM users WHERE login=?";
query(sql, [req.body.login])
.then((result)=> {
// if there are 1 or more results, compare the passwords with bcrypt
if (result.length > 0) {
bcrypt.compare(req.body.password, result[0].password, function(err, success) {
if (success) {
// if the user is not blocked, send the status 200 with user's data
result[0].blocked ?
res.status(401).json({type: 'Warning', message: 'Your account has been blocked. Plase contact the admins.'})
:
res.status(200).json({name: result[0].name, surname: result[0].surname, email: result[0].email});
} else {
// send an error if the password is wrong
res.status(401).json({type: 'Error', message: 'Please check that your login and password are correct.'});
}
});
} else {
// send an error if the login was not found
res.status(401).json({type: 'Error', message: 'Please check that your login and password are correct.'});
}
});
});
Is it enough/safe to query the db for the provided login (it's unique) with if (result.length > 0)?
Is it ok to have the error message contained in the server response like this?
res.status(401).json({type: 'Warning', message: 'Your account has been blocked. Plase contact the admins.'})
I have the chance to let the user know if he typed the correct login but the wrong password; should I let him know that? I think it would give to malicious users the knowledge that the login actually exists, so for now I just send a generic login/pwd error. Is this ok?
Is ok to send the user's data from the server to the client if the login was successful?
Is it ok to have the error message contained in the server response like this?
I have the chance to let the user know if he typed the correct login but the wrong password; should I let him know that? I think it would give to malicious users the knowledge that the login actually exists, so for now I just send a generic login/pwd error. Is this ok?
Your implementation is good enough. It's also a good practice letting users know why they are unable to login without giving out too much information EVEN when it's a problem with their supplied credentials (something you are doing already).
Is it enough/safe to query the db for the provided login (it's unique) with if (result.length > 0)?
Yes, this is fine too. You may also want to add a LIMIT 1 to your query to give you a little performance boost since there is no point having your DB scan through all the records when you expect only one result.
It is also a good practice to only send the minimum amount of information and request for more on demand.
As a general observation of your code, you would benefit from the following:
Doing some error checking on your request object before querying the database at all (good practice too) as there is no guarantee that a valid or well formatted username/password would be sent with the request.
Moving the responses into another file to make your code cleaner and maintainable.
I am using passwordless authentication for a project, everything is working as expected, however I have one question about this authentication. I will talk about the scenario.
First step: as we all know, a new user needs an email and then proceeds to click the link to login.
That is the normal case, no problem with it, but what if a user has already done that step and say he/she logs out from the app? it seems like they need to do the first step I described above again.
Here is what I have tried so far:
login() {
const email = this.email;
this.$store
.dispatch("LOGIN", { email })
.then(resp => {
this.$router.replace("/");
})
.catch(err => {
this.autherror = true,
this.errorMessage = err.message;
});
}
LOGIN: ({ commit }, user) => {
return new Promise((resolve, reject) => {
// commit(AUTH_REQUEST)
firebase.auth().signInWithEmailLink(user.email, window.location.href)
.then((result) => {
window.localStorage.removeItem("emailForSignIn");
resolve(result);
})
.catch((err) => {
reject(err);
// Some error occurred, you can inspect the code: error.code
// Common errors could be invalid email and invalid or expired OTPs.
});
});
},
I will get an error "Invalid email link!" trying the above code and even if I put the url as the previous one I logged in with, It will also throw an error "The action code is invalid. This can happen if the code is malformed, expired, or has already been used"
I can understand the point why an email to login is always required but the main point am trying to say is, if a user log's in from the link at first and then log's out, they can sign in the app without needing to do first step again, how? that means if there is a way to store credentials in cookies/localstorage, and the only time they need to do the first step again is if they clear the cookies, storage etc. from all or that particular app/page requiring.
So is it possible? It is something that will definitely improve user experience.
You should read and understand how users work in Firebase (and basically the same in any oAuth type verification system) - https://firebase.google.com/docs/auth/users
and more particularly, how email is used - https://firebase.google.com/docs/auth/web/email-link-auth
In your code you should use the email confirmation steps as shown in the reference above (so, something like the code below - you may need some minor changes to fit your local scenario):
LOGIN: ({ commit }, user) => {
return new Promise((resolve, reject) => {
// Confirm the link is a sign-in with email link.
if (firebase.auth().isSignInWithEmailLink(window.location.href)) {
// Additional state parameters can also be passed via URL.
// This can be used to continue the user's intended action before triggering
// the sign-in operation.
// Get the email if available. This should be available if the user completes
// the flow on the same device where they started it.
var email = window.localStorage.getItem('emailForSignIn');
if (!email) {
// User opened the link on a different device. To prevent session fixation
// attacks, ask the user to provide the associated email again. For example:
email = window.prompt('Please provide your email for confirmation');
}
// commit(AUTH_REQUEST)
firebase.auth().signInWithEmailLink(email, window.location.href)
.then((result) => {
window.localStorage.removeItem("emailForSignIn");
resolve(result);
})
.catch((err) => {
reject(err);
// Some error occurred, you can inspect the code: error.code
// Common errors could be invalid email and invalid or expired OTPs.
});
});
}
},
Just indicate in your db that the person has been verified in case you don't want the local storage to store the data
I upgraded the version of Firebase for my app from 3.5.0 to 4.1.3 and noticed that the onAuthStateChange callback function is no longer called after a user successfully signs in for the first time after verifying their email address.
The app is written in JavaScript.
These are the relevant sections of my code:
Callback setup
firebase.auth().onAuthStateChanged(onAuthStateChange);
Callback
function onAuthStateChange (user) {
console.log(user); // Not appearing in console
}
Sign in
firebase.auth().signInWithEmailAndPassword(email, password)
.then(function (user) {
console.log("signInWithEmailAndPassword success"); // This appears in the console
})
.catch(function(error) {
console.log("signInWithEmailAndPassword", error);
self.signInError = error.message;
$timeout(function () {
$scope.$apply();
});
});
Edit - these are the steps to reproduce the problem (the typical action of a user of my app):
User downloads and launches app
User registers with email and password
App sends email verification email
User receives verification email and clicks on link
User goes to sign in page of app
User signs in triggering the console.log("signInWithEmailAndPassword success");
onAuthStateChanged callback is not called
For development and testing purposes (not what a user would do but I have done)
User reloads the app
User is now in the app
User signs out of the app
User signs in to the app triggering the console.log("signInWithEmailAndPassword success");
onAuthStateChanged callback is called
The problem is that auth().createUserWithEmailAndPassword() does in fact log in a type of user in.
You will find that if you type
firebase.auth().onAuthStateChanged(user => {
console.log("onAuthStateChanged()");
that createUserWithEmailAndPassword() does trigger the console log. However, there seems to be no valid "user" object, which would explain why nothing appears for you since you are only logging the user.
I ran into the exact same problems. At the sendEmailverification() step notice how it does require you to use auth().currentUser, signalling there must be some sort of user signed in (I am not sure how firebase handles the difference between email verified users and non-verified users behind the scenes)
You can simply called the signOut() function after sending the email verification and it should allow the onAuthStateChanged() function to call when logging in for the first time (without reloading the app)
firebase.auth().currentUser.sendEmailVerification()
.then(() => {
console.log("Email verification sent");
firebase.auth().signOut().then(() => {
console.log("Signed out!");
}).catch((err) => {
console.log("Error signing out!", err);
});
It is rather confusing that you can actually "Log in" successfully without causing a change in AuthStateChanged or returning any errors.
TLDR: Remember to use the auth().signOut() function after sending the email verification.
Try this way, i hope it'll work
firebase.auth().onAuthStateChanged(function(user){
console.log(user);
})