0
votes

I'm currently building an app in Polymer which uses Firebase Authentication to login with your Google+ account or Email. When you run the app it will first check if the user already has a session. If not then the user is being routed to the login page which will display a login form and will handle the login by using <firebase-auth> by Polymerfire. The login page will notify the user property upwards to the my-app (app shell). If the user has been successfully authenticated we send them to the homepage my-app. This will fire the routePageChanged observer in my-app.

_routePageChanged(page) {
    if(this.user && this.user.email && this.user.refreshToken) {
       this.set("noUser", false);
       this.page = page
    } else {
       this.set("noUser", true);
       this.page = 'login';
    }
}

Okay, so far so good. If we route a user to the login form and let them authenticate, all is working fine. However, if the user already has a session the routePageChanged observer in my-app will fire and won't have a user object yet.

Problem 1

The problem in the example above is that it'll always show the login page for a few miliseconds. We can fix this by adding a timeout (?) on the initial route and show a spinner and wait for the firebase authentication. This seems a little bit hacky as I don't know how long it will take for the user to automatically authenticate? What is the best way to wait for the authentication and then do a route?

Problem 2

In the app-login page I'm handling the login. I've chosen to use a singInWithRedirect as I want the login to be available on mobile (popups are being blocked sometimes). The problem with singInWithRedirect is that it'll also re-render/initialise the whole app after authentication. This means that after creating a valid auth session the routePageChanged observer in my-app will be fired and there won't be a user object for a few miliseconds, which will make the app route to /login.

The _userChanged function in app-login will then route back to the overview on its turn. This will also show the login page for a few miliseconds.

<firebase-auth id="auth" user="{{user}}" provider="{{provider}}" on-error="handleError" on-user-changed="_userChanged"></firebase-auth>

_userChanged(event) {
    if (event.detail.value.uid) {
       this.set("waitingForAuthChanged", false);
       this.set("user", event.detail.value);
       window.history.pushState({}, null, "/overview");
       window.dispatchEvent(new CustomEvent('location-changed'));
    }
}

What's the best way to properly handle all these states? I used to use the signInWithPopup function, this won't initialise the app after authentication. I'm trying to achieve the same with the redirect.

1

1 Answers

0
votes

You use routePageChanged observer instead of user object observer. So try to manage all with observer of user:

<firebase-auth id="auth" user="{{user}}" provider="{{provider}}" on-error="handleError" on-user-changed="_userChanged"></firebase-auth>
...
<iron-pages role="main" selected="[[page]]" attr-for-selected="name" selected-attribute="visible" fallback-selection="404" > 
<div name="home"><my-home>Home Page</my-home></div>
<div name="signin"><signin-page>Signing page</signin-page></div>
<div name="404"></div>
</iron-pages>
...
<script>
...
static get observers() {
        return ['_isUserLoggedIn(user)']

... 
_isUserLoggedIn(u) {
    if (u) { this.set('signedIn', true);
             this.set('page', 'home'); // user signed in, then go home
            } else {
            this.set('signedIn', false);
            this.set('page', 'signin'); // user not signed in, so go sign in page
            }
}
</script>

Demo