Firebase how to verify an email address - javascript

I am using Ionic 2 and Firebase to Authenticate my users.
I want to make use of Firebase to Verify a users Email. Much the same way as resetting a password works here:
resetPassword(email: string, fireAuth: firebase.auth.Auth): any {
return fireAuth.sendPasswordResetEmail(email);
}
This emails a link to a user, which allows them to rest their password.
Once a user registers:
fireAuth.createUserWithEmailAndPassword(email, password).then((newUser) => {
this.userProfile.child(newUser.uid).set({ email: email });
});
The new user has the following as expected:
emailVerified:false
I would like to call a Firebase function to email a verification link to the user, once they are verified, I can then allow them to login.
Any help appreciated.

Related

How to add email verification into my Vue firebase app? [duplicate]

I wish to create a user account in Firebase Auth using createUserWithEmailAndPassword() - without logging in the user. I wish for the user to verify the email address first. Signing in the user directly causes a lot of unwanted side effects.
The /signup page has the following code - I wish for the user to stay on the /signup page after registration to be able to see the registration message.
firebase.auth().createUserWithEmailAndPassword(data.email, data.password)
.then((user)=> {
//Send email verification link
user.sendEmailVerification()
//Show message - "Your account was created - please verify using link in email"
handleStatusMessage(AUTH_SUCCESS)
})
.catch((error)=>{...})
The app.js has the following login and redirect handler
//handle login and redirect
firebase.auth().onAuthStateChanged((user) => {
if (user) {
if(!user.emailVerified){
//Exit if email is not verified
console.log('auth.js exit')
//Line 7
}
store.dispatch(setInitialStore()).then(() => {
renderApp()
//Brings user to start page
if (history.location.pathname === '/login') {
history.push('/start')
}
})
} else {
renderApp()
//Brings user to /login or /verifyEmail page when logged out
if(!history.location.pathname.includes('/verifyEmail')){
history.push('/login')
}
}
My problems are:
The user gets redirected after successful signup unless I cancel execution on line 7
If I cancel execution on line 7, the user gets stuck when moving away from /signup
Logging out the user causes the onAuthStateChanged() to trigger twice - redirecting the user
How can I keep the user on the /signup page after successful account creation while still allowing the user to navigate to the /login /verifyEmail location? Preferably in logged out state.
What I ended up doing was adding checks for when the user was logged in and logged out during signup.
signupPage.js
firebase.auth().createUserWithEmailAndPassword(data.email, data.password)
.then((user)=> {
//Login is triggered --> line 4 in app.js
user.sendEmailVerification() //Send email verification
handleStatusMessage(AUTH_SUCCESS) //Show success message
firebase.auth().signOut() //Logout is triggered --> line 16 in app.js
})
.catch((error)=>{ ... }
app.js
//handle login and redirect
firebase.auth().onAuthStateChanged((user) => {
if (user) {
//** line 4 ** EXIT if logged in from /signup
if(!isEmailVerified && history.location.pathname.includes('/signup')){
return
}
store.dispatch(setInitialStore()).then(() => {
renderApp()
//Brings user to start page
if (history.location.pathname === '/login') {
history.push('/start')
}
})
} else {
//** line 16 ** EXIT if logged out from /signup
if(history.location.pathname.includes('/signup')){
return
}
renderApp()
//Brings user to /login or /verifyEmail page when logged out
if(!history.location.pathname.includes('/verifyEmail')){
history.push('/login')
}
}
I really wish there was a option for createUserWithEmailAndPassword() to be able to automatically send the email verification email and not logging in the user to avoid this kind of cat-and-mouse game code. :)
A separate method along the lines of createUserWithEmailAndPasswordEmailVerificationRequired() that automatically sends the email link and does not sign in the user would also work ;)
The Firebase Auth function createUserWithEmailAndPassword automatically signs in users upon successful account creation (which does not require email verification).
If you need to verify email addresses for new user sign-ups without automatic sign-in, then an alternative is Email Link Authentication.
You can use Firebase Authentication to sign in a user by sending them an email containing a link, which they can click to sign in. In the process, the user's email address is also verified.
There are numerous benefits to signing in by email:
Low friction sign-up and sign-in.
Lower risk of password reuse across applications, which can undermine security of even well-selected passwords.
The ability to authenticate a user while also verifying that the user is the legitimate owner of an email address.
A user only needs an accessible email account to sign in. No ownership of a phone number or social media account is required.
A user can sign in securely without the need to provide (or remember) a password, which can be cumbersome on a mobile device.
An existing user who previously signed in with an email identifier (password or federated) can be upgraded to sign in with just the email. For example, a user who has forgotten their password can still sign in without needing to reset their password.
After users successfully created accounts via email link authentication, you could provide the option to create a password and link to the existing account.

Firebase auth: Update (not signed in user) password without use 'sendPasswordResetEmail'

I know how to update the password of signed in user in firebase auth:
var user = firebase.auth().currentUser; //get current connected user
return user.updatePassword(newPass)
.then(
() => //success
)
.catch(error => this.handleError(error))
}
But I don't know how to do the same with a not signed in user. Perhaps retrieve user auth persistance only with his email with kind like that (but there is no way to do that):
var user = firebase.auth().getUserByEmail(email); //not implmented in auth firebase
PS: I don't want to use the method sendPasswordResetEmail()
var auth = firebase.auth();
return auth.sendPasswordResetEmail(email);
Greatly appreciated help,
Thanks !
The client-side Firebase SDKs only allow sending password reset (and other messages) to the currently signed in user, as any other calls would be major abuse vectors. So there is no way to send a password reset message to a user based on their email address alone.
If you want this functionality, you will have to implement it yourself. At the end of the process, you can then use the Firebase Admin SDK to update the password in the user's profile.
Also see:
Firebase : How to send a password reset email backend with NodeJs
Send Firebase Reset Password Email After Account Created On Server/Admin

Cognito user pool "username" appears as id not email, how to fix it?

I'm using Amazon Cognito user pools, and i choose to have users signup/In with their emails. According to online guides, when choosing so, the user pool should list users with "username" value as their email, but this is not the case, i'm seeing the "id" which is also referred to as "sub" as the "username" field!
it has the UUID format.
Any ideas how to get username shows the email?
** Note: I'm talking about showing users from AWS cognito console.
Attached is a screenshot
That seems to happen when you chose to signup with either email or phone.
Apparently in that configuration Cognito generates 'username' using the sub...
I would suggest configuring Congito to use 'username' and then on signup set up the 'username' to email, you can also pass email (and phone) as additional attributes.
I hope that helps
#Luke is correct, this only happens when you select the "Email address or phone number" option in the "How do you want your end users to sign in" section of the wizard.
It's a bit confusing because the SignUp API expects an email-formatted username during signup, but then ends up creating a user with a GUID as a username, and assigns the submitted username to the email attribute. This is described in the docs:
Call the SignUp API and pass an email address or phone number in the username parameter of the API. This API does the following:
If the username string is in valid email format, the user pool automatically populates the email attribute of the user with the username value.
If the username string format is not in email or phone number format, the SignUp API throws an exception.
The SignUp API generates a persistent UUID for your user, and uses it as the immutable username attribute internally. This UUID has the same value as the sub claim in the user identity token.
If the username string contains an email address or phone number that is already in use, the SignUp API throws an exception.
This is in fact probably what you want though, as it allows users to change their emails down the line (as actual usernames cannot be changed). And furthermore, the docs state that "You can use an email address or phone number as an alias in place of the username in all APIs except the ListUsers API", so the fact that the username is a GUID in the backend doesn't have much effect on how you interact with the API.
As for listing the email in the console, it looks like they've added an email column in the user list, so that shouldn't be a problem anymore.
Here you have an example.
auth.service.ts
you have to do the login method for Cognito in your authentication service. Something like this:
login(username: string, password: string): Promise<CognitoUser|any> {
return new Promise((resolve,reject) => {
Auth.signIn(username,password)
.then((user: CognitoUser|any) => {
this.currentUserSubject.next(user);
localStorage.setItem("currentUser", JSON.stringify(user));
localStorage.setItem("token", user.signInUserSession.idToken.jwtToken);
localStorage.setItem("userGroup", user.signInUserSession.idToken.payload['cognito:groups']);
localStorage.setItem("userEmail", user.attributes.email);
this.loggedIn = true;
resolve(user);
}).catch((error: any) => reject(error));
});
}
and then in the .ts of your component you have to do the call of that method in the constructor and store in a variable the userEmail argument that you get in the localStorage from Cognito:
constructor(
private authService: AuthService,
) {
this.authService.currentUser.subscribe(response => {
this.currentUser = response;
});
this.userSessionName = localStorage.getItem('userEmail');
}
Finally, you have to display the userSessionName variable in you .html component:
<p>{{ userSessionName }}</p>

Check if an email already exists in firestore auth on signup (Angular)

As a user signs up to our app, I want them to know whether the email they are trying to sign up with already exists, without having to submit the form (A.K.A on blur of the email field). As it stands, the user has to enter their details and click signup before it let's them know whether the email is taken or not.
The required behaviour can be observed with spotify signup where you enter the email, and as soon as you click away you see the following:
So far, I have written a cloud function (http) that is triggered on blur that calls the getUserByEmail function from firestore admin auth. The function is as follows:
export const checkUserEmail = https.onRequest((req, res) => {
corsHandler(req, res, async () => {
try {
const email = req.body.email;
await admin.auth().getUserByEmail(email);
res.send({status: 200});
return;
} catch(e) {
return Helpers._handleError(res, 400, e.message);
}
})
});
This does work as I can now check at this moment whether or not an email exists, however the problem is it takes anywhere between 3-10 seconds to validate (long enough for the user to get deeper into the signup process).
Is there a way to either:
Speed up the cloud function or
Validate whether a user has already authenticated with the email provided directly on the client side with firestore?
Thanks in advance
You can use a users collection, which you may be doing already. This can store user information and often proves to be really handle since the auth user can't be updated with fields it doesn't how out of the box.
You can store users' emails here and check the collection for the user's input compared to the email field of the users collection here.

Firebase-how to use a username along with google sign in?

I recently added google sign in with firebase to my website which already uses sign in with email and password. My website already has a lot of stuff involving their username (I have a separate database with email id and username, so I log them in using their email even if they give their username). So now, when a person signs in with google for the first time, it should save their google username and email in that database. How do I do this?
You can use the promisse return.
let provider = new firebase.auth.GoogleAuthProvider();
provider.addScope('https://www.googleapis.com/auth/plus.login');
this.afAuth.auth.signInWithPopup(provider).then(user => console.log(user.email));
Or
this.afAuth.authState.take(1).subscribe(user => { console.log(user.email));

Categories