Only let pre-verified users log into Firebase - javascript

Right now, I only want users who have already registered and been verified with our software to login, and I have saved the list of emails of users (stripped of special characters) inside Firebase. Currently, when the user logs in, I use the following function to check if their email is in this list:
function isEmailValid(userEmail, trueCallback, falseCallback) {
var emailHash = userEmail.replace(/[^a-zA-Z0-9]/g, "");
firebase
.database()
.ref("validEmails/" + emailHash)
.on("value", snapshot => {
if (snapshot.val()) {
trueCallback(snapshot.val());
} else {
falseCallback();
}
});
}
Although this method works, it is quite unwieldy, as the user is still able to log in initially before the function callback is called, and their email is still shown in the "Authentication" tab in Firebase.
Is there a better way to only allowed pre-verified users to log into Firebase?

I'm pretty sure this has been covered before: there currently is no way to prevent users from signing in with Firebase Authentication. But if you want to prevent them from accessing backend resources, you can check whether their email address is verified either in the server-side security rules (for Realtime Database, Storage, or Firestore), or in your own server-side code.
At I/O a demo was given of upcoming functionality in Cloud Function that would allow you to prevent signing in users without a verified email address. But I don't know when this functionality will available in a public API.
Also see:
Firebase Prevent Creating Account Before Email Verification
How to prevent user authentication in Firebase/Vue.js BEFORE email is verified
How do I lock down Firebase Database to any user from a specific (email) domain?

Related

Why Firebase (onAuthStateChanged) does not see a Google signup user (with signInWithCredential)?

So I followed this tutorial on how to sign in a user with rnfirebase and google signup. And it works fine. Here is the code:
const googleSignUp = async () => {
// Get the users ID token
const { idToken } = await GoogleSignin.signIn();
// Create a Google credential with the token
const googleCredential = auth.GoogleAuthProvider.credential(idToken);
// Sign-in the user with the credential
const user = auth().signInWithCredential(googleCredential);
return { idToken, user };
};
(Let me note here, that the app has already a sign in with email and password way, with Firebase).
Then I realized that the user cannot change his name, email or delete his account.
Looking deeper, I found out that the onAuthStateChanged(firebase.auth, async (user) => ... returns null for the user.
I've seen in some older answers that if you use Google sign up, you need to sign up the user with signInWithCredential, which I use, so this in not the issue.
Could it be a problem that for email/password sign in, I use code from Firebase web and not from rnfirebase? Although I already had a combination of those, using the push notifications from rnfirebase.
Can someone explain why I get this behavior, and how to fix it?
Thanks!
If I understand correctly, you use both the react-native-firebase library (which wraps the native iOS and Android SDKs) and the JavaScript Web SDK for Firebase in your app.
If that is the case, both indeed have a separate sign-in state, and signing into one won't fire onAuthStateChanged listeners on the other.
You'll have to pick one SDK to authenticate with Firebase, and then use that for both providers.

How to check if email is verified in Firebase using a parameter?

My plan is to ONLY sign in a user if the email has been verified. I am using a if-statement to check if the email is verified using the built in "emailVerified" function but it is crashing.
function login(email, password) {
if (email.emailVerified) {
console.log("trying to log user");
return auth.signInWithEmailAndPassword(email, password);
} else {
console.log("failed to log user");
alert("Please verify your email");
return false;
}
}
There is no way to determine whether a profile's emailVerified property is set in the client-side SDK without signing in. So with only the client-side SDK, you won't be able to do what your pseudo-code does.
What you can do is create a custom API in a trusted environment (for example on Cloud Functions) where you use the Admin SDK to get a user profile by its email address and then check if its emailVerified property is set to true. You can then call this custom API from within your application code. But this still won't prevent a malicious user from calling the signInWithEmailAndPassword method themselves
Alternatively, and much simpler, is to sign in first, then check if the email is verified, and only allow the user to continue using the app (and accessing data) if the email is verified.
Note that this topic comes up quite regularly, so I recommend also reading:
Only let pre-verified users log into Firebase
Firebase - Auth - discover users who signed up but not verified email
Firebase Auth - createUserWithEmailAndPassword() - prevent login until email is verified
Can I get updated emailVerified without logging out?
and more from these search results

Password protect a page with Firebase

I'm building a CMS with Firebase, but struggling to assess whether what I require is possible, or if I'm missing something.
What I require is the ability to password-protect a page only, and remember that browser as having access. A full user account (using the in built auth) is required to edit the content of the page, but only a password is required to view it.
I know I can use the auth flow with email, but am looking for the editor to be able to create a password for viewing only.
Is this possible, or should I look elsewhere?
The way I commonly do this is a bit like Jeremy's answer, but simpler.
You ask the user for a password when they enter the page, and store that password locally (for reloads).
Then you store data in your database under a path that includes the password. So say that your password is geheim, you could store the data under:
data: {
geheim: {
value: "This is the secret value"
}
}
Now you secure your database with rules like these:
{
"rules": {
".read": false,
"data": {
"geheim": {
".read": true
}
}
}
}
Now somebody can only read the data at /data/geheim if they know the entire path. So you'll enter the data part in your code, but require them to enter geheim as the password. Then you attach a listener with:
firebase.database().ref("data").child(password).once("value", function(snapshot) {
console.log(snapshot.val());
});
And if the user entered the correct value for password, this will read the value.
Firebase Authentication only deals with authenticated user accounts. It doesn't deal with simple password protection of content.
It's definitely possible, but as Doug's answer indicated, you'll have to do it outside normal means. Off the top of my head, the way I would accomplish this is...
When a user enters a password, it stores the password in their local storage.
On page load, or on password entry... pull the password from local storage
Make a request to a Firebase cloud function, makes sure to include the password it just retrieved from local storage, and which page it is requesting content for
Firebase cloud function validates password
Firebase cloud function retrieves data for specific page
Firebase cloud function returns said data
Load data on front-end like normal
As you already identified, you should stick with the built-in Firebase auth for content editing.
I definitely suggest Frank's answer because it's simple and it works. Btw the moral of the story is that you use the firebase Database to store you view-only password but, if you want to complicate your life because you need a strong view-only password system, the Authentication product provides the custom authentication method that you can integrate with your existing auth system (for example fb login). It obviously needs a server-side implementation that is a code that takes the password, check if it's valid and sends the token back to the Auth system.
Here more details: https://firebase.google.com/docs/auth/web/custom-auth

How to confirm user in Cognito User Pools without verifying email or phone?

I am using Amazon Cognito Identity SDK for JavaScript (deprecated).
I created new pool without verifying email and phone_number.
By default, users aren't confirmed in Cognito User Pools, so I need to do this manually.
How to confirm user in Cognito User Pools without verifying email or phone?
I hope this will help someone else.
To do this you can add this Lambda function:
exports.handler = (event, context, callback) => {
event.response.autoConfirmUser = true;
event.response.autoVerifyEmail = true; // this is NOT needed if e-mail is not in attributeList
event.response.autoVerifyPhone = true; // this is NOT needed if phone # is not in attributeList
context.done(null, event);
};
Then navigate to AWS Cognito's General settings >> Triggers and add this Lambda function to 'Pre sign-up' - click the drop down list and select Lambda function with above code.
If you only use 'preferred_username' (if no e-mail or phone # is used) setting event.response.autoConfirmUser to true is sufficient.
Actually, AWS has recently added the ability to verify email and verify phone number in the pre-signup lambda as well. You basically need to set autoVerifyEmail and autoVerifyPhone in the lambda and they will get verified.
More info in the official documentation.
"response": {
"autoConfirmUser": boolean
"autoVerifyEmail": boolean
"autoVerifyPhone": boolean
}
I think the accepted answer is problematic. OP's question is how to confirm a user without verifying their email. But the solution will verify the user's email.
If you want to confirm a user with an unverified email (or phone), you can use AdminConfirmSignUpCommand. It is the intended way to confirm a user without having them do it, as per official docs:
Unlike ConfirmSignUpCommand, AdminConfirmSignUpCommand doesn't need a code. You can implement this command after signup in your API or as a Custom Message Trigger (effectively confirming the user when the email is sent).
Now, the user can log in, but the email must be confirmed still.

How to delete any other user besides the currentUser with Firebase?

In their docs: https://firebase.google.com/docs/auth/web/manage-users#delete_a_user
And their code example:
var user = firebase.auth().currentUser;
user.delete().then(function() {
// User deleted.
}).catch(function(error) {
// An error happened.
});
This only deletes my user, the one logged in. How would I look up a different user to delete based on email with Firebase?
You can't delete a different user from a client web app, but you could do so from a server using the Admin SDK, as shown here.
You can limit other users using any user by implementing a code+db.
Later, using google cloud services/functions, you might be able to setup one that looks for specific values in db to delete those users for you, as it will be running as Admin.

Categories

Resources