3

I'm trying to impliment auth with persistance in angularfire with this code:

constructor(private auth: Auth, private router: Router) {
    if (auth.currentUser) this.router.navigate(this.redirect);
  }

  async loginWithGoogle() {
    const provider = new GoogleAuthProvider();

    try {
      await setPersistence(this.auth, browserLocalPersistence);
      await signInWithPopup(this.auth, provider);
      this.message = 'Sign in successful';
      await this.router.navigate(this.redirect);
    } catch (error: any) {
      console.error(error);
      if (error.code) {
        this.message = `${error.code}: ${error.message}`;
      } else {
        this.message = 'There was a problem signing in. Please try again.';
      }
    }
  }

However, i always get this error, no matter the placement of the setPersistence method:

Class constructor BrowserLocalPersistence cannot be invoked without 'new'

I followed the docs (https://firebase.google.com/docs/auth/web/auth-state-persistence) to the T; what am i doing wrong?

I am using Angular 13, Angularfire 7 and Firebase 9.

Harry Allen
  • 385
  • 4
  • 13
  • I strongly recommend only calling `setPersistence` if you *know* you have a specific use-case that requires it. On most browser Firebase will already persist the auth state between reloads, without calling `setPersistence`. – Frank van Puffelen Sep 23 '21 at 01:28
  • I didn't see that... I guess I just don't even need to set the persistence; thanks! – Harry Allen Sep 23 '21 at 01:31
  • I am also getting this error. For me in google chrome user getting logged out on reload. I am trying to imeplement `await setPersistence(this.auth, browserLocalPersistence);` but getting error `Class constructor BrowserLocalPersistence cannot be invoked without 'new' ` – MaxySpark Sep 01 '22 at 19:35

2 Answers2

0

From the documentation on persisting auth state persistence in the JavaScript/web SDK:

For a web application, the default behavior is to persist a user's session even after the user closes the browser.

I strongly recommend only calling setPersistence if you know you have a specific use-case that requires it. On most browser Firebase will already persist the auth state between reloads, without calling setPersistence.

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
  • 3
    Simply calling signInWithEmailAndPassword(auth, email, password); does NOT persist login between reloads. – Kevin192291 Jan 07 '22 at 08:43
  • As said: on most browser Firebase will already persist the auth state between reloads. I clarified my answer with a link to the documentation just now. If that doesn't work for you, please open a new question with a minimal reproduction of that problem. – Frank van Puffelen Jan 07 '22 at 15:21
  • If what I said in my answer doesn't work for you, please open a new question with a minimal reproduction of that problem. – Frank van Puffelen Sep 02 '22 at 07:03
0

I have left my implementation of login with provider below.

Although I have not migrated to the Modular Firebase V9 in this project yet, the auth persistence still works the same- users who have logged in once don't need to re-login each time they come back.

I have found it to be good practice to leave auth logic in services that can be injected into your components or modules.

In the constructor you can find a nice way to determine if your users' are logged in and have a profile associated with their auth ID in Cloud Firestore.


export class AuthService {

  analytics = firebase.analytics(); // this declaration works better than constructor init from import
  userCredential; // to store the promise returned when signing up/ in with email & password
  // type: User from the model
  user$: Observable<User>; // defined as observable as it can change when user signs in/out

  constructor(
    // inject imports for fire store auth service in constructor
    private afAuth: AngularFireAuth,
    private afs: AngularFirestore,
    private router: Router
  ) {

    // Get the auth state, then fetch the Firestore user document or return null
    this.user$ = this.afAuth.authState.pipe(  // define the observable state
      switchMap(user => {
        // Logged in
        if (user) { // if user is defined
          // point to document with matching ID
          return this.afs.doc<User>(`users/${user.uid}`).valueChanges();
        } else {
          // Logged out
          return of(null); // allows us to tell when user is not logged in
        }
      })
    );
  }

  /**
   * Authenticate users with Google O-Auth provider
   * @param {boolean=} [registration = false] - whether this is the first sign in or not
   */
  async googleSignIn(registration: boolean = false) {

    // reference google auth provider
    const provider = new auth.GoogleAuthProvider();
    // pass provider to sign in with popup functionality
    this.userCredential = await this.afAuth.signInWithPopup(provider);

    if (registration) { // if the request is coming from the registration page

      try {
        await this.insertNewUser(this.userCredential.user, this.userCredential.user.displayName);
        await this.verifyEmail(); // send a verification email to the user when registering
        await this.router.navigate(['/user-profile']);
      } catch (err) {
        console.log(`Error: ${err.errorMessage}`);
        M.toast({html: `Error: ${err.errorMessage}`, classes: 'rounded materialize-red'});
      }

    } else {  //  user is logging in again

      try {
        await this.router.navigate(['/user-profile']);
        M.toast({html: `Signed in as ${this.userCredential.user.displayName}`, classes: 'rounded blue'});

        // let user know that they haven't been verified
        if (!this.userCredential.emailVerified) {
          console.log(`user's email has not been verified`);
          M.toast({
            html: `Your email has not yet been verified. Please check your inbox.`,
            classes: 'rounded orange darken-2'
          });
        }

      } catch (err) {
        console.log(`Error: ${err.errorMessage}`);
        M.toast({html: `Error: ${err.errorMessage}`, classes: 'rounded materialize-red'});
      }

    }

    // track the login event with analytics
    this.analytics.logEvent('login', {serviceName: 'Google Login'});

  } // end of sign in function

} // end of auth service 
Dharman
  • 30,962
  • 25
  • 85
  • 135
Rafael Zasas
  • 891
  • 8
  • 27