I am using Firebase to authenticate users in our app using GoogleAuthProvider
. But I don't want a new user to sign in if they are not already an authenticated user.
If the user exists then sign them in and console.log('user ' + user.email + ' does exist!');
.
However, if the user does not exist. Then do not allow authentication and console.log('user ' + user.email + ' does not exist!')
var googleProvider = new firebase.auth.GoogleAuthProvider();
export const doSignInWithGoogle = () => auth.signInWithPopup(googleProvider);
googleLogin = () => {
auth
.doSignInWithGoogle()
.then(result => {
var user = result.user;
const userRef = db.collection('users').doc(user.uid);
userRef.get().then(docSnapshot => {
if (docSnapshot.exists) {
userRef.onSnapshot(() => {
console.log('user ' + user.email + ' does exist!');
});
} else {
console.log('user ' + user.email + ' does not exist!');
}
});
})
.catch(error => {
this.setState(updateByPropertyName('error', error));
});
};
I thought referencing the user records in Firestore would be a simple approach to this. However, perhaps Firebase Auth already have a way to do this. I cannot find documentation or any example.
In the above code, nothing gets logged and the user is either created or logged in.
How can I stop new users from signing up, whilst still allowing current users to sign in?
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 fromfirebase.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.
The object you receive from firebase after login has additionalUserInfo
where you have the property isNewUser
.
You can find the reference here: https://firebase.google.com/docs/reference/js/firebase.auth.html#.AdditionalUserInfo
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)
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With