Set password and verify email in one step - firebase

Lots of questions about email verification here on SO, but none seem to cover my scenario.
We would like to add users ourselves after an intake meeting. Our representative has a form to enter some details like company name, VAT number, contact data (which contains an email field), ... This data is saved in Firestore.
After this, an email is sent to the supplied email address which contains a link that takes the user to a form where his/her email address is displayed with a password and a password confirmation input field. When submitting this field, the user is created.
But now the user receives an email asking to confirm their email address. I assume, for security and privacy reasons, there's no way I can set the user's email address as verified.
I've looked at customizing the verification email, but that doesn't seem to solve my problem.
Creating the user with a random password after the intake meeting also doesn't seem to be a solution, as the user still has to verify and then reset the password in 2 steps. Or can I somehow redirect after the email verification to the 'set password' page? That would be an acceptable solution.
Is there any way to achieve the desired flow described above?

As a general workflow, you could achieve this using a Cloud Function along with either database system. You can also make use of App Check to further secure this process.
Representative adds base user information in their portal. Store the data securely in the database of your choice.
Send the user an invite email containing a short-lived verification token linked with the email added by the representative (this could be generated and fired off using an onCreate Cloud Function once the invitee's data is added to the database). This token should follow some standard like JWT so you can deserialize the contained email address or be exchangeable for the underlying email address.
When user clicks/copies the link to their browser, present them with an input form asking for the desired email and password. Note: the email field should be editable! The rep may have used an email the new user doesn't want to use with your platform.
If the token is still valid and not consumed, continue with the next steps.
If the token has expired and not consumed, send another email to reconfirm their email and restart this step.
If the token is already consumed, show an error and don't continue.
Submit the email, password and emailed token to your backend via a Callable Cloud Function.
Sign the user in using the authentication token returned by the function on success. Show an error otherwise.
In the callable function for creating the user:
Confirm the request comes from your app (if using App Check)
Confirm the validity of the emailed token
Pull the data the representative entered from the database linked with the emailed token's original email address.
Using that data, the updated email, the new password, and emailVerified=true, call the createUser API.
Using the User ID from the returned UserRecord, create the user's profile data in the database and also create a Custom Authentication Token.
Once their data has been created and the token generated, return the authentication token as the result of the request.

Related

How do I Check if an email address is real or fake in flutter

I use createUserWithEmailAndPassword(string, string) in flutter, but I noticed if the user used a fake email address, like making us some random Gmail or yahoo account that doesn't exist, the user would still be registered, is there a solution to this
Or some logic that checks if the email account is real, then I can use the result in an if else statement to create the account
If you are looking for a solution that doesn't involve blocking the user experience, you'll be disappointed. We could come up with a new solution for checking whether an email exists or not, but this doesn't guarantee you anything. The user may use an existing email that doesn't belong to him/her.
The best you can do is send a verification email to your user, which is supported by Firebase. However, the user experience is going to be blocked until the user verifies the email.
Update
Check here how to send the user the verification email and here how to see if the email has been verified.

Firebase: Securing records by email address when users can use fake addresses

I'm making a web app where you pay to use it first and then sign in. The sign up workflow is this:
Once a payment is made on my website, the client receives an order ID that is associated with their email address. The client sends this to a Firebase Function endpoint to activate their order.
The Firebase Function checks the order ID is valid and creates a Firebase user with a long random password (to prevent anyone from signing in), then sends a password reset email. A "payment" record is created in Firestore and associated with the user ID.
The user follows the password reset email then logs into my app. The paid features are activated if Firestore contains a payment associated with that user ID.
This all seems fine except:
A malicious user Bob could outside of my control creates a user for email "x#example.com" that he doesn't own and sign in using the Firebase client SDK.
Alice then makes a payment for her email "x#example.com".
Bob will still be signed in and can now use the features Alice paid for.
How do I prevent this?
One idea I had was the above Firebase Function could check if user "x#example.com" exists with an unverified email address and if so it would 1) delete that user and 2) create a user for that email address again (creating a new unique user ID). Bob would then have a different user ID than the one associated with the email address so couldn't access the payment record. However, this breaks if Alice makes two payments without validating her email after the first payment. What's a robust way of solving this?
Consider verifying the email before processing the transaction.
One option is to use sign in with email link. This will sign in the user and verify their email. You can also set a password after if you want. If an existing unverified provider is linked to the account, it will be unlinked and any existing session that a malicious user had previously set up will be revoked.

is it possible for users to choose any email at the time of password reset in frebase?

I am using ionic 3 and firebase for the backend.In my app I am trying to let users sign up with just username and password. Well firebase by default doesn't provide that option. So I am getting user's input as username (for example: 'mike123') then i add #myapp.com. so it looks like an email: 'mike123#myapp.com'. That is all fine, but a problem just came up when user's want to reset their passwords. Is it possible to let users type in any valid email address at the time they want to reset their password?.
You can change the password of the user by https://firebase.google.com/docs/auth/admin/manage-users#update_a_user. Note that this is in the Firebase Admin SDK, so will require that you run code in a trusted environment, such as a server you control or Cloud Functions.
But faking username+password by faking an email address is non-ideal. I'd consider creating a custom auth provider for your needs.
If the email provided when sending the Reset Password request doesn't exist for any user, then it will fail.
In Android, calling sendPasswordResetEmail with a non-existing email, it would return a:
FirebaseAuthInvalidUserException: There is no user record corresponding to this identifier. The user may have been deleted.
You should ask for a valid email from the user and save their preferred username separately upon the user creation.

How to login a new user by default after mail Invite in Meteor?

I have a requirement where I need to log in a new user to a Meteor application by default, and take the user to the reset password route after that.
I looked into this documentation, but I don't think it would apply here, because the password is not known. Here's my use case in detail :-
A user invites another new user by providing the invited user's email ID. The application sends email invite to the user, asking them to be taken to a route which normally requires logging into the application.
The new user who receives the email invite, is not yet signed up with the application. So, they need to pick a password to log in to the invited area of the application.
Currently, I am using the meteor-useraccounts:core package; to trigger the resetPasswd route for FlowRouter. Using the onSubmitHook, one can redirect the user to the proper location after successful reset of the password.
However, I am not able to figure out how to first log in the user automatically. Because if the user is not logged in, the reset password page won't open. Instead, it would show some error, indicating unauthorized action.
How could a link be sent via mail to the invited user, which would automatically log in the user?
I looked into this documentation, but I don't think it would apply
here, because the password is not known.
That is right, and because of that, in order to achieve that you have to create an account for that e-mail at the time the user enters a link sent by e-mail. Or create the account at time of invitation.
So possible solutions:
1) create an account for an e-mail provided in query (http://app/login?email=blabla#google.com) for a route, random password, reset password e-mail sent immediately after the login. (create login automatically login the user). That would also required some security key, so that no-one could create lots of accounts on different e-mail addresses.
2) create account at time of invitation, take random password and send it as a query parameter of the link sent to the invited user. When user enters the site, you take that password (and e-mail) and login him with that, and immediately send reset password for that e-mail

About Email Verification - What methods

I just wanted to ask the procedure of email verification, whats the best method. So far i have a class that stores the information from the register.aspx form, then i send out an email to the user, but what should i send him, should i send the user a guid?.
Also my membership class that stores the register data is stored in a session, is this a good idea, becuase if the user session times out then the membership class will be nothing and the user will be prompted to register again in a Session Timeout webpage, is this a good method?
But what if i send the user a guid and then store the user data to the database with the guid and then check the email guid with the corresponding user guid in the database, what should i do?
Also i have a Regular expression that checks that the email is valid, its not that good yet and i havent tested it properly, is there free email verification api's out there?
I am using ASP.NET VB.
Here is what I would do:
1) Ask for user's email
2) Validate the email using Regex
3) If valid, create a Timestamp (DateTime.Now), append with user's Id and any other useful information that I need. We can use some appropriate delimiters.
4) Encrypt the data and build a URL with the encrypted token and email to user
5) When user clicks, decrypt the information, check the timestamp (perhaps there is a timeout required) and use user's Id to get its data from database.
This is in addition to the already accepted answer - I wouldn't limit the email validation to checking the Regex syntax only.
There's a free email verification API I've been using that checks a number of factors, including syntax, typos, SMTP & MX-Records (which verifies the actual existence of the email address), if its a free or disposable email, etc.
They're offering a thousand monthly requests for free - mailboxlayer.com
Save the data to the database, including the GUID. Set the status of the record to "inactive". Send the email, with a link back that includes the GUID. When the link is clicked, set the registration record to "active". Only "active" records can log in.
You can't effectively validate an email address with a regexp - search this site for explanations of why.
In .Net you should validate email addresses like this. See this question for details.
MailAddress address = new MailAddress(input)
This throws an exception if the email address is invalid.

Resources