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:
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 = '/'});
Listening to authentication state The module provides a method called onAuthStateChanged which allows you to subscribe to the users current authentication state, and receive an event whenever that state changes.
onAuthStateChanged. Adds an observer for changes to the user's sign-in state. Prior to 4.0. 0, this triggered the observer when users were signed in, signed out, or when the user's ID token changed in situations such as token expiry or password change.
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;
}));
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With