Firebaseui-web: [Feature Request] Enforce mandatory email verification

Created on 24 Jun 2016  Â·  28Comments  Â·  Source: firebase/firebaseui-web

It does not seem to send a verification email automatically. It does work when manually using sendEmailVerification(), but then we need to track if we already sent it or not to prevent duplicates.

auth p2

Most helpful comment

Hey Anisse, currently, we do not send email verifications automatically. We are interested in adding that feature to firebaseui-web.

All 28 comments

Hey Anisse, currently, we do not send email verifications automatically. We are interested in adding that feature to firebaseui-web.

@bojeil-google I am trying to send a password reset email form the firebase console. I'm connected our third party email (an outlook account). The email has been successfully Verified. When I try to send a reset password email to a specific user, the console displays the error "An unknown error occurred while sending the password reset email." I attached a screen shot. Any clues as to the problem — or are there any details I could provide to help?
Thank you for your time.
reset-password-error

@itispeach on sidelines of topic, on privacy concerns suggest you to mask the email ids or any other personal information from panel in the screen shot attached.

@jalajc thanks for the caution. That was careless of me. I updated the image. Thanks again for your concern.

Hey @itispeach, does this happen to other users when you try to reset their passwords? or is this just specific to one user? Did you try testing calling firebase.auth().sendPasswordResetEmail('[email protected]') programmatically? If that works then this seems like a bug in the Firebase console.

@itispeach also observe with verified vs non-verified ids ./ the one with a non-null date in 'Signed in' column in panel. Seems you have added lot of ids from panel directly.

Yes, this seems like it would be a standard part of firebaseui-web via a config option on the EmailAuthProvider.

Exactly how would I call sendEmailVerification() after an account is created? I'm using email and google sign in, but aside from modifying the super-complex firebaseui.js how can I send an email for verification. The only way I see to do it is a cloud function, or some weird redirect but I'm sure there's an easier way.

You can actually do it without modifying FirebaseUI source code.
What you need to do is the following:
Add your custom signInSuccess callback. In that callback you check if the user is an email/password user that is new and unverified. In that case, you send an email verification by calling sendEmailVerification and notify the user to verify their email by showing your own UI with instructions.
Assuming you are using real time database, add a check in your rules to allow access only to users with email/password that have been verified.
In order to track if a user is new or not, you can on signInSuccess, add that user to the database. If the user is not already there, send the email and save that user. Otherwise, if the user is already saved, then this is an existing user that you already sent an email to. In that case you can show your UI telling the user to check their email for the verification link that was previously sent or give the user an option to resend it.

You can also use Firebase functions to do so too. You can use the sign up trigger. You would need to include the Firebase client node.js SDK and admin node.js SDK to send the email verification though. In that case you would still need to show some UI telling the user to check their email.

Email verification in firebase ui should be more convenient to configure, also I would like to propose that email verification through code in addition to link should also be configurable because for a developer verification through code is less complex to implement.

+1 - - there should be a more declarative way to adopt a policy (e.g. mandatory email verification) and have firebase UI implement it for you, rather than having to write all these handlers and verification steps.

+1 Yeah, definitely a bummer to have to implement this myself. Wish I could not worry about this part of the flow.

+1 !!! This should just be an option on the email provider.

I am facing the problem please help me.
when i try to check wether user provided email id is verified i get false everytime from user.isEmailVerified() in android firebase.
here is logcat if you want double check my code.

11-30 22:08:32.644 19033-19033/com.example.rktech.firebasetogettoken V/FA: onActivityCreated
11-30 22:08:32.713 19033-19033/com.example.rktech.firebasetogettoken I/TextInputLayout: EditText added is not a TextInputEditText. Please switch to using that class instead.
11-30 22:08:32.720 19033-19033/com.example.rktech.firebasetogettoken I/TextInputLayout: EditText added is not a TextInputEditText. Please switch to using that class instead.
11-30 22:08:32.744 19033-28780/com.example.rktech.firebasetogettoken V/FA: Using measurement service
11-30 22:08:32.745 19033-28780/com.example.rktech.firebasetogettoken V/FA: Connecting to remote service
11-30 22:08:32.749 19033-28780/com.example.rktech.firebasetogettoken V/FA: Activity resumed, time: 191714386
11-30 22:08:32.922 19033-28780/com.example.rktech.firebasetogettoken D/FA: Connected to remote service
11-30 22:08:32.922 19033-28780/com.example.rktech.firebasetogettoken V/FA: Processing queued up service tasks: 1
11-30 22:08:34.544 19033-19062/com.example.rktech.firebasetogettoken W/DynamiteModule: Local module descriptor class for com.google.firebase.auth not found.
11-30 22:08:34.546 19033-19062/com.example.rktech.firebasetogettoken W/DynamiteModule: Local module descriptor class for com.google.firebase.auth not found.
11-30 22:08:37.926 19033-28780/com.example.rktech.firebasetogettoken V/FA: Inactivity, disconnecting from the service
11-30 22:08:46.503 19033-19105/com.example.rktech.firebasetogettoken D/FirebaseAuth: Notifying listeners about user ( Q3ceRB5IZpdnKr5mwWdd9ex2s2n2 ).
11-30 22:08:46.504 19033-19033/com.example.rktech.firebasetogettoken D/FirebaseApp: Notifying auth state listeners.
11-30 22:08:46.504 19033-19033/com.example.rktech.firebasetogettoken D/FirebaseApp: Notified 0 auth state listeners.
11-30 22:08:47.668 19033-28780/com.example.rktech.firebasetogettoken V/FA: Recording user engagement, ms: 14923
11-30 22:08:47.669 19033-28780/com.example.rktech.firebasetogettoken V/FA: Using measurement service
11-30 22:08:47.669 19033-28780/com.example.rktech.firebasetogettoken V/FA: Connecting to remote service
11-30 22:08:47.673 19033-28780/com.example.rktech.firebasetogettoken V/FA: Activity paused, time: 191729309
11-30 22:08:47.676 19033-28780/com.example.rktech.firebasetogettoken D/FA: Logging event (FE): _e, Bundle[{_o=auto, _et=14923, _sc=LoginActivity, _si=3195814022951486795}]
11-30 22:08:47.694 19033-28780/com.example.rktech.firebasetogettoken V/FA: Using measurement service
11-30 22:08:47.695 19033-28780/com.example.rktech.firebasetogettoken V/FA: Connection attempt already in progress
11-30 22:08:47.718 19033-19033/com.example.rktech.firebasetogettoken V/FA: onActivityCreated
11-30 22:08:47.785 19033-28780/com.example.rktech.firebasetogettoken V/FA: Using measurement service
11-30 22:08:47.785 19033-28780/com.example.rktech.firebasetogettoken V/FA: Connection attempt already in progress
11-30 22:08:47.786 19033-28780/com.example.rktech.firebasetogettoken V/FA: Activity resumed, time: 191729427
11-30 22:08:47.844 19033-28780/com.example.rktech.firebasetogettoken D/FA: Connected to remote service
11-30 22:08:47.844 19033-28780/com.example.rktech.firebasetogettoken V/FA: Processing queued up service tasks: 3
11-30 22:08:47.905 19033-19033/com.example.rktech.firebasetogettoken W/IInputConnectionWrapper: finishComposingText on inactive InputConnection
11-30 22:08:47.906 19033-19033/com.example.rktech.firebasetogettoken W/IInputConnectionWrapper: finishComposingText on inactive InputConnection
11-30 22:08:47.907 19033-19033/com.example.rktech.firebasetogettoken W/IInputConnectionWrapper: finishComposingText on inactive InputConnection
11-30 22:08:49.009 19033-19105/com.example.rktech.firebasetogettoken D/FirebaseAuth: Notifying listeners about user ( Q3ceRB5IZpdnKr5mwWdd9ex2s2n2 ).
11-30 22:08:49.009 19033-19033/com.example.rktech.firebasetogettoken D/FirebaseApp: Notifying auth state listeners.
11-30 22:08:49.010 19033-19033/com.example.rktech.firebasetogettoken D/FirebaseApp: Notified 0 auth state listeners.
11-30 22:08:50.465 19033-19045/com.example.rktech.firebasetogettoken D/FirebaseAuth: Notifying listeners about user ( Q3ceRB5IZpdnKr5mwWdd9ex2s2n2 ).
11-30 22:08:50.465 19033-19033/com.example.rktech.firebasetogettoken D/FirebaseApp: Notifying auth state listeners.
11-30 22:08:50.465 19033-19033/com.example.rktech.firebasetogettoken D/FirebaseApp: Notified 0 auth state listeners.
11-30 22:08:52.888 19033-28780/com.example.rktech.firebasetogettoken V/FA: Inactivity, disconnecting from the service
11-30 22:08:55.590 19033-28780/com.example.rktech.firebasetogettoken V/FA: Recording user engagement, ms: 7805
11-30 22:08:55.591 19033-28780/com.example.rktech.firebasetogettoken V/FA: Using measurement service
11-30 22:08:55.592 19033-28780/com.example.rktech.firebasetogettoken V/FA: Connecting to remote service
11-30 22:08:55.597 19033-28780/com.example.rktech.firebasetogettoken V/FA: Activity paused, time: 191737231
11-30 22:08:55.603 19033-28780/com.example.rktech.firebasetogettoken D/FA: Logging event (FE): _e, Bundle[{_o=auto, _et=7805, _sc=successActivity, _si=3195814022951486796}]
11-30 22:08:55.624 19033-28780/com.example.rktech.firebasetogettoken V/FA: Using measurement service
11-30 22:08:55.625 19033-28780/com.example.rktech.firebasetogettoken V/FA: Connection attempt already in progress
11-30 22:08:55.625 19033-28780/com.example.rktech.firebasetogettoken V/FA: Using measurement service
11-30 22:08:55.625 19033-28780/com.example.rktech.firebasetogettoken V/FA: Connection attempt already in progress
11-30 22:08:55.627 19033-28780/com.example.rktech.firebasetogettoken V/FA: Activity resumed, time: 191737245
11-30 22:08:55.628 19033-28780/com.example.rktech.firebasetogettoken D/FA: Connected to remote service
11-30 22:08:55.628 19033-28780/com.example.rktech.firebasetogettoken V/FA: Processing queued up service tasks: 3
11-30 22:08:57.712 19033-19062/com.example.rktech.firebasetogettoken W/DynamiteModule: Local module descriptor class for com.google.firebase.auth not found.
11-30 22:09:00.657 19033-28780/com.example.rktech.firebasetogettoken V/FA: Inactivity, disconnecting from the service
11-30 22:09:03.333 19033-28780/com.example.rktech.firebasetogettoken V/FA: Recording user engagement, ms: 7730
11-30 22:09:03.334 19033-28780/com.example.rktech.firebasetogettoken V/FA: Using measurement service
11-30 22:09:03.335 19033-28780/com.example.rktech.firebasetogettoken V/FA: Connecting to remote service
11-30 22:09:03.341 19033-28780/com.example.rktech.firebasetogettoken V/FA: Activity paused, time: 191744974
11-30 22:09:03.347 19033-28780/com.example.rktech.firebasetogettoken D/FA: Logging event (FE): _e, Bundle[{_o=auto, _et=7730, _sc=LoginActivity, _si=3195814022951486795}]
11-30 22:09:03.364 19033-28780/com.example.rktech.firebasetogettoken V/FA: Using measurement service
11-30 22:09:03.364 19033-28780/com.example.rktech.firebasetogettoken V/FA: Connection attempt already in progress
11-30 22:09:03.442 19033-28780/com.example.rktech.firebasetogettoken D/FA: Connected to remote service
11-30 22:09:03.442 19033-28780/com.example.rktech.firebasetogettoken V/FA: Processing queued up service tasks: 2
11-30 22:09:04.400 19033-19033/com.example.rktech.firebasetogettoken W/IInputConnectionWrapper: reportFullscreenMode on inexistent InputConnection
11-30 22:09:04.401 19033-19033/com.example.rktech.firebasetogettoken W/IInputConnectionWrapper: finishComposingText on inactive InputConnection
11-30 22:09:08.526 19033-28780/com.example.rktech.firebasetogettoken V/FA: Inactivity, disconnecting from the service
11-30 22:09:21.301 19033-28780/com.example.rktech.firebasetogettoken V/FA: Using measurement service
11-30 22:09:21.302 19033-28780/com.example.rktech.firebasetogettoken V/FA: Connecting to remote service
11-30 22:09:21.308 19033-28780/com.example.rktech.firebasetogettoken V/FA: Activity resumed, time: 191762942
11-30 22:09:21.363 19033-28780/com.example.rktech.firebasetogettoken D/FA: Connected to remote service
11-30 22:09:21.364 19033-28780/com.example.rktech.firebasetogettoken V/FA: Processing queued up service tasks: 1
11-30 22:09:23.732 19033-19062/com.example.rktech.firebasetogettoken W/DynamiteModule: Local module descriptor class for com.google.firebase.auth not found.
11-30 22:09:23.734 19033-19062/com.example.rktech.firebasetogettoken W/DynamiteModule: Local module descriptor class for com.google.firebase.auth not found.
11-30 22:09:26.367 19033-28780/com.example.rktech.firebasetogettoken V/FA: Inactivity, disconnecting from the service

Hey @rk215 this repo for for FirebaseUI-web issues. And currently even FirebaseUI-android still doesn't send email verifications. So you are better off reporting this issue to Firebase Support: https://firebase.google.com/support/
They will connect you with a Firebase Auth Android engineer that works on the core SDK.

thanks for suggestion.

On Nov 30, 2017 11:16 PM, "bojeil-google" notifications@github.com wrote:

Hey @rk215 https://github.com/rk215 this repo for for FirebaseUI-web
issues. And currently even FirebaseUI-android still doesn't send email
verifications. So you are better off reporting this issue to Firebase
Support: https://firebase.google.com/support/
They will connect you with a Firebase Auth Android engineer that works on
the core SDK.

—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/firebase/firebaseui-web/issues/21#issuecomment-348265840,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AZYna8F7gKWzsku2fNCppQBBu_2t-V0Rks5s7uoNgaJpZM4I9qVN
.

Is there any update on this issue or any work being done to provide this out of the box?

This is a real bummer. I'm trying to migrate from Google Identity Toolkit to Firebase Auth, and was under the impression that Firebase Auth offers email verification feature out of the box.

Today (with Identity Toolkit) I handle it on my server, but it's not that bad. I can check whether it's a new user, and if it is, automatically send a verification email. I also have a count of the number of times a verification email has been requested. The max. is set at 3 and after that it would stop sending further verification emails to prevent spam/abuse.

But with Firebase, the Admin SDK cannot send verification emails. So it has to be done on the client. But client has no way of knowing whether it's a new user, or how many times the email has been sent. So, it again has to rely on the server and there's more communication required between client and server. The client would have to make a call to the server to check whether to send the verification email or not. If server responds in the positive, client would then send the email, and again call the server to update the information in the database. In other words, it's more complicated and messy with Firebase Auth.

Moreover, the documentation just provides a one line call to send verification email, but doesn't address any implementation patterns around it.

This issue has been open for 2 years. Is there any plan to address it?

Hey @deepfriedbrain, we do return a UserCredential object that determines whether a user is new or not. You can build your own verification flow on top of that. FirebaseUI can handle the landing page for the verification. All this can be completely done through a client flow.

We are definitely committed to an e2e flow for email verification. Some of the blockers were that we want to get the UX flow right and we want to make sure we build this in a way that works for everyone. We also want to support in on the 3 platforms (Android, iOS and web). In addition, we have had many features and requirements in the pipeline that have come up and rank high in priority and urgency.

We are hoping we can get this feature implemented later this year. But for now, you should have all of the tools to build it your own.

@bojeil-google Thanks for your response. It helps to some extent, but there are still missing pieces to the puzzle. I'm trying to understand the complete flow so that it can help me as well as others who come across this issue.

I tried the following approach to determine whether it's a new user, and it seems to work. But I have 2 issues:

  1. How do I determine whether the verification email has already been sent or not using a "client flow"? If the user reloads the page, the lastSignInTime does not change. It changes only on sign in / out.

    let user = firebase.auth().currentUser;
    var creationTime = new Date(user.metadata.creationTime);
    var lastSignInTime = new Date(user.metadata.lastSignInTime);
    if (lastSignInTime <= creationTime) {
        // It's a new user, send verification email
    }
    
  2. With UserCredential, I would use this:

    firebase.auth().signInAndRetrieveDataWithCredential(credential)
        .then(function(userCredential) {
            if (userCredential.additionalUserInfo.isNewUser) {
                // It's a new user, send verification email
            }
    });

But how do I get the credential object? I couldn't find any sample code for it. The closest is this SO thread but I don't have the userPassword.

But even if I get the UserCredential approach working, does the isNewUser flag update when the page is refreshed? I guess no and that brings us back to the same question - how do we keep track of whether a verification email has already been sent or not using a purely "client flow"?

  1. You said "FirebaseUI can handle the landing page for the verification." Can you explain how? I cannot find any information on this. Does it also handle "Send verification email" button?

UPDATE: Another thought - I could probably sign out the user after sending them the verification email. This would force the lastSignInTime to update, but I also read on another thread that the lastSignInTime doesn't update if the user signs back in within 2 mins.

Even if you determine the email verification was previously sent, you should still give the user the option to resend the email as the emails can expire after some time. You always have the option to use something like Firebase Realtime database to track that too.

It's not clear why you care about lastSignInTime. Check the signInSuccessWithAuthResult callback. It provides a UserCredential object which has an isNewUser property in the additionalUserInfo.

Rendering FIrebaseUI on your custom email callback page will have it check the URL for the email verification parameters and then render the UI to handle the verification completion. We will document that at some point.

Thanks again for your help.

Yes, in my current Identity Toolkit implementation, I do have a button to "Resend verification email". I'm trying to figure out how to make it work with Firebase.

But you haven't addressed the point about checking whether an email has been sent or not using the "client flow". Is there a flag that tracks whether a verification email has been sent to a user? Otherwise, how do I know whether an email has been sent already or not before triggering the email automatically? This is the whole sticking point here.

I don't care about lastSignInTime so much. I tried your suggestion to use signInSuccessWithAuthResult callback and it works. But it gives me the same end result that I achieved by checking the datetime manually (sample code in my previous message). So, I'm fine with either approach. So this is not an issue.

Yes, I'm getting the verification confirmation page. Refer to the screenshot below. Is that what you meant?

In summary, I would like to know how to check whether a verification email has already been sent or not. I can take care of handing the "Resend verification email" using a custom page.

image

Yes that is what I meant by the verification confirmation page.

Firebase Auth doesn't track the status of the email verification. You would need to build your own mechanism. You can use Firebase realtime database for that.

As I mentioned, even if you keep track of the email status, these codes will expire after some time.

Thanks for confirming it.

Now you are saying the same thing that I said in the very beginning that verification email "cannot" be built properly using a client only flow. It needs to rely on a server, be it Firebase realtime database or something else.

Verification email is a must-have for email/password based login. This is a huge gap and I'm surprised why no one else is discussing it.

The link expires in Identity Toolkit also, but that's not the main issue here.

In almost every site I've used for registration, when I sign up, I get the first verification email automatically without explicitly requesting it. If without verifying the email I sign into the site, I get a message that my email is pending verification. There's also a button to resend verification email. This is exactly how it works today on my site with Google Identity Toolkit and this is exactly what I'm trying to achieve with Firebase Auth.

But to determine whether to send the first verification email, I need to know whether this is the very first time user is trying to access my site. So today I do it immediately at the point of user creation on my backend. How do I do it with Firebase? The isNewUser doesn't help me as far as I can tell because it returns true as long as the user has not signed out of their first session. I can't be sending verification email automatically (from the client side) if the user happens to simply refresh the site or reopen it.

With Google Identity Toolkit, the server admin SDK sends the verification email and I have full control over this aspect. By moving the verification email feature to the client, Firebase Auth has taken away that control. This is a "serious flaw" of Firebase Auth.

From all the discussions so far, the conclusion is that the admin SDK has to have the feature to send verification email. Otherwise, the Firebase Auth email/password sign in option is crippled and lot of work has to be done to make it work properly.

I checked on their Admin SDK GitHub project and surprisingly there's no issue/request on this topic. I checked with Firebase support earlier in the week and they said they have a request to add verification email feature to the admin SDK but they cannot commit on it.

I'm wondering how others have been using the email/password option. There's no code sample or starter kit that shows a working example of this with a complete flow (including keeping track of whether an email has been sent before or not).

UPDATE 1:

One of the options is the ability to send verification email right at the point of user creation. Either Firebase Auth should do it automatically or provide a callback method at the time of user creation to do it programmatically.

const uiConfig = {
    signInSuccessUrl: '/profile',
    signInOptions: [
        firebase.auth.EmailAuthProvider.PROVIDER_ID
    ],
    credentialHelper: firebaseui.auth.CredentialHelper.NONE,
    callbacks: {
        signInSuccessWithAuthResult: function (authResult) {
            if (authResult.additionalUserInfo.isNewUser) {
                authResult.user.sendEmailVerification();
            }
            return true;
        }
    }
};

// Initialize the FirebaseUI Widget using Firebase.
const ui = new firebaseui.auth.AuthUI(firebase.auth());
ui.start('#firebaseui-auth-container', `uiConfig);

This is a working auto send of verification for anyone curious. It does not include reissuing or anything like that.

FYI you can create a Cloud function that triggers on a user Creation event that will send the email verification email automatically too. Please see: https://firebase.google.com/docs/functions/auth-events#trigger_a_function_on_user_creation

I handled it after successful login, here is the code. I am using Angular, but same applies for native Javascript.
This is not the exact code, but it pretty much cover the idea.

`
successCallback(data: FirebaseUISignInSuccessWithAuthResult) {

//If this is a new user && his provider is password (username/password registeration) && his email is not verified,
if (
  data.authResult.additionalUserInfo.isNewUser &&
  data.authResult.additionalUserInfo.providerId == 'password' &&
  !data.authResult.user.emailVerified
) {
  //Send him the verification email, show him a toastr message, then apply a force logout
  data.authResult.user.sendEmailVerification();
  this.afAuth.auth.signOut();
    alert("Account created successfully. Please verify your email address.");
  }

//If this is not a new user && his provider is password (username/password registeration) && his email is not verified.
//On the other hand, the UI shows the user a button to resend the verification email.
else if (
  !data.authResult.additionalUserInfo.isNewUser &&
  data.authResult.additionalUserInfo.providerId == 'password' &&
  !data.authResult.user.emailVerified
) {
  //Show him a taostr message that his email is not verified, then apply a force logout.
  this.afAuth.auth.signOut();
  const shallSendVerficationEmail = confirm("Your email address is not verified. Would you like to resend verification email?")
  if (shallSendVerficationEmail){
        data.authResult.user.sendEmailVerification();

} 
//Otherwise, either an old user, or other providers such as Facebook or Gmail, then login normally.
else {
    return;
}

}`

this would be useful for other providers as well, for example, some of my users sign in with GitHub and their emails aren't verified so if have to provide a custom solution

Was this page helpful?
0 / 5 - 0 ratings