Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can't reauthenticate with email link in Firebase

I have email link sign-in setup in my web app and it works fine. However, I need to reauthenticate a user before performing a certain action.

I am using the following code to reauthenticate:

let credential = firebase.auth.EmailAuthProvider.credentialWithLink(userEmail, window.location.href);

firebase.auth().currentUser.reauthenticateWithCredential(credential).then(function (usercred: any) {
     console.log('Reauthentication test successful.');
}).catch(function (error: any) {
     console.log('Reauthentication test failed.');
});

However, the credential throws an error every time:

code: "auth/argument-error"
message: "Invalid email link!"

This is even if I try changing the URL. The url is authorized in the console, and is https (I was testing on localhost at first and thought maybe that was the issue).

Any ideas?

like image 399
TheRyan722 Avatar asked Nov 17 '22 02:11

TheRyan722


1 Answers

I had the same issue and the documentation is kind of vague in the process. I did not want to use already existing UI solutions (đŸ˜…) so I had to figure it out.

Here is the documentation snippet:

import { getAuth, linkWithCredential, EmailAuthProvider } from "firebase/auth";

// Construct the email link credential from the current URL.
const credential = EmailAuthProvider.credentialWithLink(
  email, window.location.href);

// Link the credential to the current user.
const auth = getAuth();
linkWithCredential(auth.currentUser, credential)
  .then((usercred) => {
    // The provider is now successfully linked.
    // The phone user can now sign in with their phone number or email.
  })
  .catch((error) => {
    // Some error occurred.
  });

The code window.location.href supposes that you are opening a link from an email link sign in

  • Server side / Function
  • or Sent from the client
  • also a good read for a good flow Passing State in Email Actions

It's not too different from the others, email link process, where you have to trigger an email being sent either from the client side or a server.

I would have the page to handle the other modes (password reset, ...) and also this specific logic to handle new authentication or just re-authentication on page load.

here is an exemple on Angular (Typescript) based on the documentation

// app.component.ts

ngAfterViewInit() {
  const currentUrl = window.location.href;
  if (isSignInWithEmailLink(this.authService.auth, currentUrl)) {
    const isLoggedIn = !!this.user?.uid;
    let email = isLoggedIn
      ? this.user?.email
      : window.localStorage.getItem("emailForSignIn");
    if (!email) {
      email = window.prompt("Please provide your email for confirmation");
    }
    if (email && validateEmail(email)) {
      try {
        // --> important !

        if (isLoggedIn) {
           const credential = EmailAuthProvider.credentialWithLink(email,currentUrl);
            await reauthenticateWithCredential(this.user, credential)
        } else {
             await signInWithEmailLink(
            this.authService.auth,
            email,
            currentUrl
          );
        }
        window.localStorage.removeItem("emailForSignIn");
        this.router.navigateByUrl("/login");
        // console.log(userCredential);
      } catch (e) {
        console.log(e);
        // Some error occurred, you can inspect the code: error.code
        // Common errors could be invalid email and invalid or expired OTPs.
        this.toastr.error(getTranslation(e.code), "Error");
      }
    } else {
      this.toastr.error("Please enter a valid email", "Error");
    }
  }
}
like image 90
Jeffrey Nicholson Carré Avatar answered May 25 '23 01:05

Jeffrey Nicholson Carré