20

How can I send a verification email after I create a user with firebase admin SDK? I am trying to combine createUser function and sendEmailVerification function could somebody indicate a hint or an answer? thanks

update:

the user creation is being done by an admin user who is already signed in in the app, so the admin user is just creating users on the dashboad. This is completely different from the registeration methods.

update 2:

I tried to follow bojeil's answer, I am still stuck with the step that user signs in with the custom token. It gets into conflict with my current admin user session, the admin users gets kicked out and instead the new user is signed in and even when I sign out the new user, the admin user is still out and needs to sign in to get back into the app.

here is my code inside the app after I get the custom token:

$http.post('/.custom-token', {uid: $scope.data.data.uid})
        .then(function (response) {
            console.log("custom token here:", response.data.token);
            firebase.auth().signInWithCustomToken(response.data.token)
                .then(function (firebaseUser) {
                    firebaseUser.sendEmailVerification();
                    firebase.auth().signOut().then(function() {
                        // Sign-out successful.
                        console.log("signed out success");
                    }, function(error) {
                        // An error happened.
                    });
                })

                .catch(function(error) {
                    // Handle Errors here.
                    var errorCode = error.code;
                    var errorMessage = error.message;
                    // ...
                });

        });

so, I get the token, sign in the new user, send the email verification link, and then, sign out the new user. But my admin user who is doing all of this gets signed out as well. what am I missing here?

Community
  • 1
  • 1
passion
  • 1,000
  • 6
  • 20
  • 47
  • Hi! I am looking into something similar. How did you overcome the admin logging out - problem? – user165242 Sep 28 '17 at 09:37
  • you should call the signOut function in the then function of the sendEmailVerification(). Since sendEmailVerification is async, you should wait until the execution is completed and then call the signOut function. – DerFaizio Feb 19 '18 at 16:07

8 Answers8

22

OK this is what you can do but you may hit quota limitations:

  • Include the firebase-admin module.
  • Include the firebase client module.
  • using admin sdk, create the new user via createUser
  • when that promise resolves, get the uid of the user created.
  • using admin sdk, create custom token for that uid.
  • using client sdk, signInWithCustom token using that custom token.
  • A user is returned in the process, call user.sendEmailVerification()
  • signOut that user from the client SDK.
bojeil
  • 29,642
  • 4
  • 69
  • 76
  • 1
    hmmm, but signing in with the user token, will it be in conflict with my current admin user signed-in session? – passion Jan 27 '17 at 10:28
  • The user sign in will not conflict with your admin session. You cannot rely on currentUser in this case and run your sendEmailVerification on the returned user instance on sign in. – bojeil Jan 27 '17 at 18:48
  • thanks for the hints, i tried to follow your explanation but i still have problem, please see my updated question. thanks. – passion Jan 28 '17 at 10:46
  • 1
    I don't think I understand what you mean by admin user? Here is one thing you can do, you can create a copy of a firebaseApp where you run these temp sign in operations: var tempApp = firebase.initializeApp(clientConfig, 'temp'); You then use tempApp.auth().signInWithCustomToken... This wouldn't conflict with your other instance. – bojeil Jan 28 '17 at 22:01
  • I spent several days on this issue, and found this answer. Thanks for the answer. You made my day :) – Pankaj Parkar Oct 11 '18 at 13:51
  • How do you "sign out that user from the client SDK" without also signing out the admin user? As an admin, I create a new user but then that last line signs out the new user and me (the admin user). – Duderino9000 Dec 16 '20 at 22:28
5

According to firebase, the admin-sdk does not currently support this feature. See their response here: https://stackoverflow.com/a/44557980/8177355

Whenever an email / password authentication user is logged in, and attempts to use a feature that requires authentication, I call onAuthStateChanged() and then check the user's record for email verification.

If the email is not verified, and I have not sent a verification email before, I send it automatically. I return an error, asking the user to verify their email. (I store a variable in a profile setup for the user in firestore, to indicate whether it has been sent previously).

On future attempts to use the app, if the email is still not verified, I return the same error, and also include a button in the error labeled "re-send verification email" that triggers sending of the verification email when pressed. (This way I am not automatically sending tons of verification emails every time the user tries to do something.)

Matthew Rideout
  • 7,330
  • 2
  • 42
  • 61
4

A rather clean solution would be to actually use the REST APIs.

curl 'https://www.googleapis.com/identitytoolkit/v3/relyingparty/getOobConfirmationCode?key=[API_KEY]' \
-H 'Content-Type: application/json' \
--data-binary '{"requestType":"PASSWORD_RESET","email":"[user@example.com]"}'

The [API KEY] is a web client api key that can be retrieved from Project Settings > add an app >> click web and you will get the configuration with a JSON, within the JSON there is an APIKey that is the one that you need to use.

N Jay
  • 1,774
  • 1
  • 17
  • 36
3

You don't even need to use the Firebase Admin SDK for this. You can just use the regular Firebase client-side SDK:

firebase.auth().createUserWithEmailAndPassword(email, password)
  .then(function(user) {
     console.log("User successfully created:", user.uid);
     return user.sendEmailVerification();
  })
  .then(function() {
    console.log("Email verification email successfully sent!");
  })
  .catch(function(error) {
    console.log("Error:", error);
  });
jwngr
  • 4,284
  • 1
  • 24
  • 27
  • 8
    i think you are missing the point: `If the new account was created, the user is signed in automatically. Have a look at the Next steps section below to get the signed in user details.` it is automatically signed in. The user who is creating another userX is already signed in, if this new userX also gets signed in, there will be a conflict in the session tokens. – passion Jan 26 '17 at 23:23
  • I unfortunately don't understand what you are trying to ask for. – jwngr Jan 27 '17 at 01:18
  • That worked for me. I had to adjust slightly the first callback (user)=>user.user.sendEmailVerification() – Lonelydatum Mar 26 '19 at 01:12
2

Here's bojeil's steps in code, which work in a NodeJS Firebase Cloud Function. Assuming that 'admin' is your Firebase Admin SDK instance, and 'firebase' is your Firebase Client SDK instance.

var userId = "YOURUSERIDHERE";
admin.auth()
        .createCustomToken(userId)
        .then((customToken) => {
            return firebase.auth().signInWithCustomToken(customToken)
        })
        .then((data) => {
            return data.user.sendEmailVerification({url: "http://YOURREDIRECTURL"});
        }).then((result) => {
            console.log("success");
        }).catch((error) => {
            console.log("faillure");
        });

Make sure that you've setup the Admin SDK properly, by creating a service account and initialising it in the Admin SDK configuration snippet.

Mdlc
  • 7,128
  • 12
  • 55
  • 98
1

I think we can try the following combinations:

Jemzzzz
  • 129
  • 9
1

What I did is very simple:

  1. Create a user in the server
  2. In the client await the server creation and after that sign-in using the client SDK,
  3. in the background listening to firebase auth user change event and than use the user and call sendEmailVerification

This is my React code:

 await Api('signupUser', data) // server call

 await firebase
        .auth()
        .signInWithEmailAndPassword(email, password); //client login

 // send email on login
 useEffect(() => {
      return firebase.auth().onIdTokenChanged((user) => 
      user?.sendEmailVerification());
  }, []);
cheziHoyzer
  • 4,803
  • 12
  • 54
  • 81
0

2023

The accepted answer and some other ones are already old now. There is now a function generateEmailVerificationLink that can generate the verification link for any persisted user.

Generate the verification link and send it, for example, using Nodemailer (I recommed this way, it's simple) or some 3rd party mail API.

Michal Moravik
  • 1,213
  • 1
  • 12
  • 23