You can use updateEmail with the following workflow:
await user.updateEmail(newEmail)
await user.getIdToken()
await user.sendEmailVerification()
and there's also a function verifyBeforeUpdateEmail.
These two workflows seems identical to me, but is there any difference?
The documentation lacks examples and explanations of the difference.
Reference: https://firebase.google.com/docs/reference/js/firebase.User#verifybeforeupdateemail
The User.verifyBeforeUpdateEmail method is documented as:
Sends a verification email to a new email address. The user's email will be updated to the new one after being verified.
So the process here sends a verification email to the new email address. Only once the user clicks the link in that email will their email address be updated and the emailVerified property of their account set to true.
The user.updateEmail method is documented as:
Updates the user's email address.
So when you use updateEmail, the user's email address ends up being unverified. If you care about email verification, you'll need to call sendEmailVerification again to verify the updates email address. But even if you call sendEmailVerification right after updating the email address, the user account will have its emailVerified property set fo false for a while.
Related
I have an issue I've been unable to resolve. I'm using AWS Cognito User Pools with a user migration lambda function to import users on the fly. After successfully validating a user's password, I'd like to check if this password meets the requirements Cognito enforces. As per the docs, this should be done in code:
Amazon Cognito doesn't enforce the password strength policy that you configured for the user pool during migration using Lambda trigger. If the password doesn't meet the password policy that you configured, Amazon Cognito still accepts the password so that it can continue to migrate the user. To enforce password strength policy and reject passwords that don't meet the policy, validate the password strength in your code. Then, if the password doesn't meet the policy, set finalUserStatus to RESET_REQUIRED.
However, when I set finalUserStatus to RESET_REQUIRED, I see behavior I don't understand. When logging in for the first time, I see the following, which seems correct:
At this time, I also receive an email with Subject: "Your temporary password" and body: "Your username is ...#gmail.com and temporary password is l6*NWOEp.". I thought this was odd because I hadn't submitted the above form yet. When I enter my email in the above form, I receive:
I don't receive any additional emails. When I fill out this form, I receive the same error.
When I go back to the sign in page and use the temporary password I received in the email, I am forwarded to the first form above: the one with the "Password reset required for user due to security reasons".
Below is the code, I've removed unrelated config and error handling:
export const lambdaHandler = async (event: any, context: any): Promise<any> => {
if (event.triggerSource == "UserMigration_Authentication") {
const userName = event.userName;
const password = event.request.password;
const user = await authenticateUser(userName, password);
event.response.userAttributes = {
"email": user.email,
"username": user.email,
"email_verified": "true",
};
if (passwordIsWeak(password) { // always true for testing purposes
event.response.finalUserStatus = "RESET_REQUIRED";
}
context.succeed(event);
}
};
The user in my Cognito User Pool has a Confirmation Status of "Reset required".
I've tried many combinations of finalUserStatus (RESET_REQUIRED, CONFIRMED, FORCE_CHANGE_PASSWORD) and messageAction (SUPPRESS, RESEND) returned in event.response. Anyway, thanks for any help provided!
I have a lot of kind of users, some users is log up with google account, others with google account and password, i only want to send the reset mail sendPasswordResetEmail if the email belong to user have a password, not to every kind of account, this each user have to do when the user is not login.
i used this function sendPasswordResetEmail but that function sent mail to everybody, i had a google account without password, that is wrong to me
You can check user's auth providers and check if that includes Email-Password:
const user = firebase.auth().currentUser;
if (user !== null) {
if (user.providerData.find(p => p.providerId === "password")) {
// user had email-password account
// send email
}
}
Action:
- signInWithPhoneNumber(NUMBER NOT IN DB, recaptchaVerifier)
Expected Behavior:
- Since number not in DB, it should not log me in.
Current Behavior:
- If the number does not exist in DB, it CREATES a new user after going through recaptcha + sms verification. WHY?
Code:
function loginWithSMS(phoneNumber) {
firebase.auth().useDeviceLanguage();
//#ts-ignore
window.recaptchaVerifier = new firebase.auth.RecaptchaVerifier("recaptcha-container");
//#ts-ignore
window.recaptchaVerifier.render().then(function (widgetId) {
//#ts-ignore
window.recaptchaWidgetId = widgetId;
});
// #ts-ignore
firebase
.signInWithPhoneNumber(phoneNumber, window.recaptchaVerifier)
.then((confirmationResult) => {
console.log("Login success", confirmationResult);
window.recaptchaVerifier.clear();
// SMS sent. Prompt user to type the code from the message, then sign the
// user in with confirmationResult.confirm(code).
const verificationCode = window.prompt(
"Please enter the verification " + "code that was sent to your mobile device."
);
return confirmationResult.confirm(verificationCode);
})
.catch((error) => {
console.error(error);
// Error; SMS not sent
// Handle Errors Here
window.recaptchaVerifier.clear();
return Promise.reject(error);
});
}
This is just how the API is defined: by sending a text to the number, Firebase allows the user to verify that they have access to that phone number. If they do, they're allowed to sign in.
This is the same for the email+password provider in Firebase Authentication. Calling firebase.auth().createUserWithEmailAndPassword(email, password) creates the user, even if they didn't exist yet. And while your code may not call this API, any developer can take the Firebase configuration data from your app and call the API themselves.
Most often when developers are asking about this they're confusing authentication with authorization.
When you authenticate, you are proving that you are you. So in the examples above, that you have access to a certain phone number, or that you know the email+password combination of the account.
Based on knowing who the user is, the application then authorizes that user to perform certain actions or to access certain data.
For example, if you're using Realtime Database, Cloud Storage, or Cloud Firestore, you can control access with Firebase's server-side security rules.
If you have a different back-end, you'd control it there by checking the information in the ID token of the user (which you get from Firebase Authentication) against some set of authorization rules for your application.
Also see:
Prevent user account creation with sign in by email in firestore (similar question, but then for passwordless email signin)
How to disable Signup in Firebase 3.x
How does the firebase authentication and realtime application database secure itself?
I tried to login in Meteor with username instead of email but it is not working.
Meteor.loginWithPassword(username, password, error => {
// error ==> user not found
});
According to docs it says user can be either username, email or id
I have saved username in profile of User
Fixed, I saved my username in profile sections. Username should be saved as separate key just like email, then it will work
Why does the Email.send() function from the email package contain a 'from' argument if every email will be sent from the email defined in your process.env.MAIL_URL environmental variable?
Server-side code:
process.env.MAIL_URL = 'smtp://my_email%40gmail.com:my_password#smtp.gmail.com:465/'
Meteor.methods({
sendEmail: function (to, from, subject, text) {
check([to, from, subject, text], [String]);
// Let other method calls from the same client start running,
// without waiting for the email sending to complete.
this.unblock();
Email.send({
to: to,
from: from,
subject: subject,
text: text
});
}
});
Client-side Code:
Meteor.call('sendEmail',
my_email#email.com,
email,
name,
message);
where email, name, and message are variables that are read from form elements.
In your case, when sending through a Gmail account, you are correct. The from email address must match the email address associated with the login information. However, when sending through an SMTP relay service, like Amazons SES or MailChimp, it is possible to set the from address to any verified email address or domain, so you can send from multiple email addresses.