firebase multi-location updates user authentication and database - javascript

I have a Form to signup new User with email, password, full name and phone number.
I can use firebase.auth().createUserWithEmailAndPassword to create new user if successfully. Then I use firebase.database().ref('users/..').set(..)to save fullname and phone number to firebase database.
But If the saving processing to database occur error (By rule write:false for example), I STILL have an user Identifier created in User Authentication. So an user exist without phone number and full number.
How can I can multi-location insert user authentication and database. If one of these two failed firebase auto reject inserting new identifier and inserting into database. (The processing only return success if both success).

There is no way to make the combined Auth and Database operation atomic. If you want to be atomic, you should use only one service: the database or authentication.
To make this atomic you could pass username, password, full name, and phone number to a HTTP function in Cloud Functions. This then creates a user with the email and password, then writes the full name and phone number to the database.
But note that this still isn't guaranteed to be atomic: the same glitch that you're anticipating on the phone, could happen on the server. While chances are much smaller, there's no guarantee.
This means you'll need to make sure that your code is robust enough to handle cases where the full name and phone number are missing. And if you need to do that in the server-side case, it will also work the same if you'd leave the cross-product code on the client.

Related

Firebase - Get the password of the current user in GCF

I have decided to implement some extra security processes in my app. Previously, I was updating the user password directly from the client side. I have decided to do it inside a Cloud Function, in order to also notify the user via email.
For this, I am passing the newPassword as param to my callable cloud function, where I execute:
admin.auth().updateUser(uid, {
password: newPassword,
});
I have thought that it will also be a good idea, to increase the security, to make sure that the user writes his current password in the form, in order to verify it in my cloud function, before updating the password.
How can I compare the current user’s password in admin mode (GCF)?

How to implement "forgot/reset password" feature properly in Node.js? (Using one time token)

I am implementing a forgot/reset password functionality in a Node.js app using NestJs.
That is the general flow:
A user types in his email in a "forgot password" form and submits the request
The server generates a jwt token with the user's ID as the payload, then sends an email with the token as the link to reset the password (example: GET: example.com/reset/generated_jwt_token)
User clicks the link from his email, the reset password page is rendered, he fills the form with the new password and submits the form with the password as the body (example: POST: example.com/reset/generated_jwt_token)
Server verifies the token (that is not expired + user ID from payload exists in the DB) and updates the password.
The main problem with this approach is that the jwt token can be used unlimited amount of times to reset the password (until it expires after X minutes).
Is there a way to solve this? some say to put the current password's hash as the payload since it will be changed anyway and will guarantee 1 time use, but I'm not a fan of this method.
EDIT: Another approach i encountered is creating a blacklist collection in the DB of jwt token that cannot be used more than once. Or using a cache in redis the same way, but it seems not very scalable.
When a token is generated, you could save it (or something unique embedded inside it) into the database under that user. Then, the server verifies the token:
(1) when the link from the reset email is clicked
(2) when the user submits the reset password page
by checking that the token is the same as the one for that user in the database.
Also, when the user successfully changes their password, clear the token from the database so it can't be used again.
I agree with the (accepted) answer of #CertainPerformance.
I would like to add - Consider using authentication-flows-js. You will not have to worry about the implementation at all!
It is a module that answers most flows - authentication, registration, forgot-password, change password etc., and it is secured enough so applications can use it without the fear that it will be easily hacked.
From an article I wrote:
Forgot Password
The user enters their email in the forgot password
form, and clicks submit. The server (AFM) verifies the account exists
and is not locked. If it is locked, AFM throws an error. Otherwise, an
email is sent to the user with a token. That token is stored in the DB
in the same row/document/record of the user.
Read the full article with more explanations here.

password reset with jwt structure

I'm trying to write the password reset part of my authentication app. I chose to use JWT, node.js and express where I use the following logic: first, the user enters their email and a token is generated and sent to the user's mail in a password reset link. second, when the user presses the link a function is set to check if the token is correct and if it's still valid and third i have a function to save the new password to the database.
What I'm uncertain about is the second step where the token is supposed to be checked. Some tutorials say that you're supposed to save the token to your database and then compare the token in the link to the token in the database. But isn't the point with using JWT to not save anything to the database as reference? Shouldn't I just use jwt.verify to get the information saved in the token and then check for the user in the database and if it's still active?
Is this the correct way of using JWT? Or would you recommend me to use session instead of JWT?
There's a good suggestion in this answer. You can use some hash of your currently stored password value as part of the password reset JWT.
So the payload might contain { sub: user_id, exp: "now + 10 minutes", purpose: "password_reset", key: hash(hashed_password_from_db).substr(0, 6) }. This token can only be used successfully once.
There is a simple flaw in the use of JWT for reset password implementation.
From your current implementation, A user can generate the reset password link multiple times. So a user can have many active reset token in a given time.
Yes, JWT statelessness can be adopted, but it is not efficient in this case as you can have multiple tokens which can be used to reset the password even after the user has reset the password(depending on your approach).
I work in an organisation where testing and security is paramount. Your implementation would not be allowed.
The rule is that only one reset password link can be active at a time.
So JWT token is not the best option for us.
So what I do is to generate a random token saved in the DB(also with the current time). This token is to identify the user and, the time is to validate that the user is resetting withing a given time.
While the token is active, if a user decides to generate the token again, the former token is made inactive before a new one is generated.
The advantage of this method is that you can only have one active token at a time.
Lastly, JWT should be used if you don't mind a user having multiple active tokens/links at a time.

how to password protect a single page (that's not apart of an authentication system)?

I'm building a Meteor app for contracts. A signed in user can create a contract. But I'd like for them to be able to send a contract to another party, who can view the contract without signing up or creating an account. The problem is that, even if the URL is long and random, www.example.com/docs/bM7GjrRq1wABYdxws3 -- I'm not sure it is private enough -- because maybe all these contracts could be easily crawled or end up in search like this.
I'd like the creator of the contract to set a password that can be emailed to the other party along with the link to the contract. Before the party can view the contract, they need to enter the password.
My solution is to allow a user to password protect the page (but without a username/email). But I'm not sure how to do it. How can I password protect a page with a password set by a user?
You could save password within the page object on mongodb.
Then when he creates or edit the page, he might choose to share publicly or with password.
The publish method could look somewhat like this.
Meteor.publish("page", function (){
if (!this.userId) {
return Pages.find({
_id: Session.get("pageId"),
private: true,
password: Session.get("pagePassword")
});
} else {
// code for logged in users
}
});
Of course it's a good idea to store a hash for the password and compare to the hash the user entered, instead of storing the raw password.

Meteor forgotPassword & sendResetPasswordEmail dataflow

I'm not fully understanding the process for processing a 'forgot password' request from the user. Just looking for a little clarification.
On the client you take the user's email and pass that to Accounts.forgotPassword which triggers a call to Accounts.sendResetPasswordEmail on the server. Accounts.forgotPassword only takes email as an argument.
So Accounts.sendResetPasswordEmail is triggered which actually sends the email to the user, but that's looking for a userId...
Just confused by the logic there. Why not just call sendResetPasswordEmail from the client with an email and a userId as arguments?
It's important to note that Accounts.sendResetPasswordEmail can only be called from the server, and is automatically called for you as the result of the call to Accounts.forgotPassword. So in general you don't need to directly call it, however you probably do want to customize the email (from, subject, body) via Accounts.emailTemplates.
Of course, you could call Accounts.sendResetPasswordEmail via a method but consider the most common use case:
I'm a user of the system, but I'm not logged in (no Meteor.userId()). I have an email which is attached to my account. I want to get a reset password email based only on that information. And that's exactly what Accounts.forgotPassword does for you. How convenient!
Note also that by requiring an email on a route that has to be exposed to the public, you are also inherently filtering out baddies which don't know the emails of your users.

Categories