Only authenticate with Google Auth Provider if user exists

If you really want to use signInWithPopup method, you have this option, but it's not the best way. when you are signing in with google, signInWithPopup method returns a promise. you can access the isNewUser property in additionalUserInfo from resulting object. then delete the user you just created.

firebase.auth().signInWithPopup(provider).then(
     function (result) {
          var token = result.credential.accessToken;
          var user = result.user;

          //this is what you need
          var isNewUser = result.additionalUserInfo.isNewUser;
          if (isNewUser) {
               //delete the created user
               result.user.delete();
          } else {
               // your sign in flow
               console.log('user ' + user.email + ' does exist!');
          }
     }).catch(function (error) {
     // Handle Errors here.

});

This is the easy way but deleting after creating is not the best practice. There is another option,

you can use, signInAndRetrieveDataWithCredential method for this. according to the docs,

auth/user-not-found will be Thrown if signing in with a credential from firebase.auth.EmailAuthProvider.credential and there is no user corresponding to the given email.

function googleSignInWithCredentials(id_token) {
     // Build Firebase credential with the Google ID token.
     var credential = firebase.auth.GoogleAuthProvider.credential(id_token);

     // Sign in with credential from the Google user.

     firebase.auth().signInAndRetrieveDataWithCredential(credential)
          .then(function (userCredential) {
               //sign in
               console.log(userCredential.additionalUserInfo.username);
          }).catch(function (error) {
               // Handle Errors here.
               var errorCode = error.code;
               if (errorCode === 'auth/user-not-found') {
                    //handle this
               } else {
                    console.error(error);
               }
          });
}

here is an example from firebase github repo.


with Firebase security rules, can only check if keys exist - therefore searching in the users table is not an option:

"emails": {
    "[email protected]": true,
    "[email protected]": true
}

and then one can check with security rules, if the auth.token.email exists as a key:

{
    "rules": {
        ".read": "root.child('emails').child(auth.token.email).exists(),
        ".write": false,
    }
}

in the client, this should throw an "The read failed: Permission denied error" error then, to be handled accordingly. hooking into the Firebase sign-up isn't possible - but while they cannot log-in, this has the same effort (except that on has to clean up the user-database from time to time); eg. with a Cloud Function, which deletes users, which do not have their email as key in the emails "table".

in Firestore security rules, one can check with:

  • request.auth.token.email & request.auth.token.email_verified

for example, with a collection called emails and a collection called content:

match /databases/{database}/documents {

    function userMatchesId(userId) {
        return request.auth != null && request.auth.uid == userId
    }
    function readAllowed(email) {
        return if get(/databases/$(database)/documents/emails/$(request.auth.token.email)).data != null
    }

    match /users/{userId} {
        allow get: if userMatchesId(userId)
    }
    match /content {
        allow get: if readAllowed(request.auth.token.email)
    }
}