Firebase getRedirectResult is being called after logout

I'm a little confused by some behaviour I'm seeing with Firebase. I never used the old version, but I believe getRedirectResult is new since they joined forces with Google.

I have a SPA that I am using Vue.js with vue-router, and Firebase for. There is a landing page, and then another view for which users can be logged in, or not. Login is done by redirect. When this second view is loaded, I check getRedirectResult in the vue-router 'activate' hook, and if there is a user, do some other stuff with the user information.

The problem proceeds thusly:
1. We are on second page. User logs in. getRedirectResult is called and finds a user. Yay.
2. User logs out. We are back on landing page.
3. We click a button that leads us to second page. getRedirectResult is called and finds the previous user. What?! No!

I can't find anything on whether I am missing something and need some kind of extra check in place, or to somehow forcibly refresh the page after logout so it forgets that the last user logged in, or if this would be considered a bug. Any assistance would be greatly appreciated!

getRedirectResult call on second page in vue component router 'activate' hook:

    firebase.auth().getRedirectResult()
        .then((result) => {
          return result.user;
        }).then((user) => {
          // Do stuff.
        });
    

Update: Solved by doing a hard page refresh in the logout callback, as follows:

    firebase.auth().signOut()
        .then(() => {window.location.href = '/'});
    

Answers:

Answer

Use a flag to detect if getRedirectResult() has been processed. i.e.

firebase.auth().getRedirectResult()
  .then((result) => {
    return result.user;
  }).then((user) => {
    if (this.authRedirected)
      return; // Skip

    // Do stuff.

    this.authRedirected = true; // Mark redirected
  });
Answer

This drove me crazy. As you'll see here (https://github.com/firebase/firebase-js-sdk/issues/133), this is unfortunately intended behavior.

My approach was to avoid using getRedirectResult() entirely and achieve the same functionality by testing for the presence of an authenticated Firebase user (rather than waiting for the redirect callback). In Angular, you use AngularFire's authState observable. With this approach, when you signOut(), there's no issue with that lingering user in your client memory because it wasn't stored in getRedirectResult().

The concept is that you place a Route Guard on the login page. The Route Guard only lets you on to the login page if an authenticated user isn't present. At that point, you log in, and once that succeeds (signInWithRedirect() always takes a few seconds), the firebase user data is loaded into the client, which triggers the Route Guard to block you from the login page and instead redirect you to the location of your choice.

For bonus points, if you want to preserve the returnUrl, store that string in local storage before firing signInWithRedirect(), and then retrieve it in the Route Guard when the redirect happens (and delete it from local storage).

Inspiration from this Firebase blog post: https://firebase.googleblog.com/2018/03/cleanse-your-angular-components.html. Hopefully this can be applied conceptually to what you are doing in Vue.js.

If you're curious, here's what that Route Guard looks like in Angular 2:

import { Injectable } from '@angular/core';
import { AuthService } from './auth.service';
import { Router, CanActivate } from '@angular/router';
import { map } from 'rxjs/operators';

@Injectable({
  providedIn: 'root'
})
export class LoginGuardService implements CanActivate {

  constructor(
    private auth: AuthService,
    private router: Router
  ) { }

  canActivate() {
    return this.auth.firebaseUser$.
      pipe(map(user => {
        // The firebaseuser determines if user is logged in
        // If logged in, block the route with a redirect
        if (user) {
          console.log('User detected', user);
          const returnUrl = localStorage.getItem('returnUrl');
          // Route user to returnUrl, if none, go to profile
          if (returnUrl && returnUrl !== '/') {
            this.router.navigate([returnUrl]);
          } else {
            this.router.navigate(['profile']);
          }
          return false;
        }
        return true;
      }));
  }
}

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us

©2020 All rights reserved.