When do I verify the email before creating a subscription with stripe? - firebase

I know stripe doesn't have anything to do with verifying emails.
I have a form on my website where I collect a new user's email, password and cc info.
As of now I do not verfiy the user's email. I simply create the user in my system and create the strip user and subscription after I get the card token with stripe.js.
I want to verify the email address, but I am not sure at what point in the process to do it. I don't think it makes sense to charge the customer and start the subscription and then verify the email address.
Should I wait and start the stripe subscription when the customer verifies the email address? It seems like this is one of the most common scenario's online. Is their a best practice for this scenario?
Again, I am not asking technically how to verify the email address (I use firebase auth), I just want to know when I should and how it should fit into my onboarding flow.

You can after Firebase Auth account creation, check if the emailVerified is true. If not, send an email verification and pass a continueUrl to continue the subscription process, instructing the user to check their email to continue the subscription process. This is a common process for many subscriptions that require email verification.
You can learn more about passing continueUrl via email verifications:
https://firebase.google.com/docs/auth/web/passing-state-in-email-actions
You can build your own custom landing page where you continue the subscription using the following instructions: https://firebase.google.com/docs/auth/custom-email-handler
Make sure you check email_verified in the idToken after ID token verification to confirm verification, server side.

Related

What is the best practice for firebase resending sendEmailVerification()?

My auth flow:
Firebase sendEmailVerification() needs an already authenticated user to work as the first arg.
My auth flow at the moment works like this.
Signing up the user with email and password signUpWithEmailAndPassword()
Now the firebase auth object contains the currentUser
Sending a verification mail to the just signed up user sendEmailVerification()
Logging him out and redirecting him to /email-verification where he can send the verification mail again.
Problem:
Now the problem. When the user now wants to request to send the email verification again I have three options for what I know.
Store email and password in state before logging him out -> and then logging him in again on sendAgain and logging him out afterward. Would that be a security concern?
Let him logged in the whole time. Which doesn't feel too good as he wouldn't be able to log himself out again as he officially isn't signed in till he verifies his email.
Force him to input his email and password again every time he wants to send the verification mail again, which feels redundant and old school.
If you require that the user verifies their email address in order to sign in, consider using the email link provider of Firebase Authentication.
Let him logged in the whole time. Which doesn't feel too good as he wouldn't be able to log himself out again as he officially isn't signed in till he verifies his email.
This logic may apply to your application, but it is simply not how the email+password provider in Firebase Authentication works. When the user enters the correct credentials, they are signed in to Firebase Authentication. If your app requires them to have verified their email address before they can use it, that's the exact check I'd recommend implementing.
So if you want to continue using the email+password provider, reframe the statement to:
In order to use the app, the user needs to sign in with their credentials and verify their email address.
You can then implement that in these two steps:
Ask them to sign in if they're not signed in already.
Then if the account doesn't have a verified email address, ask them to find the email and click the link - and give them to option to send another verification email.

Set password and verify email in one step

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.

Is there a way to send a verification email to a custom email id (say to an admin) instead of the user's email id using Firebase Auth?

I am using flutter for this project. My goal is to send a verification email to the admin once the user has registered his/her account. The profile will be registered once the admin verifies it through email.
I am aware that we can send a verification email to the user itself to verify the email id by using Firebase Auth. I was wondering whether there is a way to change the reciever's address from the user to an admin's email id(custom email id). If no then is there any other way to perform this task ?
Thank you in advance for the help.
I am using Cloud Firestore as a database service.
You can use Cloud Functions to know when a user was created or deleted.
But if you want to get an email only after the email was confirmed, then you would have to do it inside your app, triggering some logic that sends you a message from inside your app once you detect the email is verified.
You can't change the destination of the verification email. It will always go to the email address that was used at the time of signup.
If your goal is to prevent the user from doing anything with some backend resource until after an admin authorizes them, what you can do is use custom claims to add a flag to the account that can be checked by security rules or your backend endpoint. The presence of that flag can be used to tell if an admin has authorized them. You will have to build out some amount of backend infrastructure to make all that work.
As far as I remember there are Firebase Authentication triggers that you can use to listen to new user creations. You need to setup a Firebase function that listens for user creation events.
functions.auth.user().onCreate((user) => {
//send email to admin
}
Another step that you can take is to disable the newly created account and also send email to the user as well telling him that his account is disabled until admin approves it. You can achieve this using Firebase Admin SDK. And maybe create another cloud function that admin activates to enable the account back. So maybe something like this:
functions.auth.user().onCreate((user) => {
// disable this account
// send user email to let him know that his account is disabled until approval
// send email to admin to ask for his approval for the account
}
() {// another cloud function that enables the user account called by admin}
This may not be the best solution but it will work.

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.

Resources