Why is my aurelia spa reset upon return from Auth0 lock

Please be aware that this is my attempt to get a second opinion on Ryan Chenkie’s answer to the issue I posted a week ago as Lock based authentication setup - Auth0 Community.

Since that time, I did manage to learn a lot more about Lock API and have deployed the application that in my opinion still misbehaves (click here to run it) and check this document for more details on the app structure and behavior.

In summary, click on the “GitHub Users” menu item, results with the Auth0 lock prompt, and if you just click on the provided ID (auth0test@aureliatools.com), you will see the application that is already running, to reload itself.

I saw many statements about this behavior being unavoidable for SPA apps - but I would really like to understand why. Giving me the complete definition of the Auth0 response to the authentication request, so I can simulate Auth0 Lock using Postman tool would be ideal.

@pat.trivedy
@ryanchenkie


Since this is the place that expects precise questions in order to get useful answers, let me add the following:

Initial setup

        let options = {
            rememberLastLogin: true,
            auth: {
                redirectUrl: 'http://localhost:9000/#/auth0-service',
                responseType: 'token',
                sso: true
            },
            theme: {
                labeledSubmitButton: true
            },
            allowForgotPassword: true,
            allowSignUp: false,
            allowedConnections: 'Username-Password-Authentication'],
            prefill: {
                email: "auth0test@aureliatools.com",
                username: "auth0test"
            },
            hashCleanup: false,
            autoParseHash: false
        };
        //
        // Auth0Lock is created here - when the Auth0Service gets added to the DI container
        // executing 'import { Auth0Service } from './services/auth0-service';' statement in app.js
        //
        try {
            this.lock = new Auth0Lock(client_ID, domain, options);
        } catch (e) {
            console.log(e.message);
        }

My choice of options can be inconsistent for what I want to achieve, so this is clearly an area where I expect to be found at fault.

I am also unsure on how to use the resumeAuth API, so my current implementation of the “authenticated” event handler is:

registerAuth0EventHandler(router, lock) {
        // Lock event handler - at the moment used only to set the state of being authenticated
        // and gather user profile / JWT bearer token
        //
        this.lock.on("authenticated", (authResult) => {
            this.lock.getProfile(authResult.idToken, (error, profile) => {
                if (error) {
                    console.log("getProfile failed.")
                    return;
                }
                this.showUserCredentials(authResult, profile);
                this.isAuthenticated = true;
                lock.hide();
                let returnRoute = localStorage.getItem('returnRoute');
                router.navigate(returnRoute);
             });
        });
    }
    showUserCredentials(authResult, profile) {
        let _profile = JSON.stringify(profile);
        let _id_token = authResult.idToken;
        console.log('EventHandler in the Auth0Service module reporting:');
        console.log('token:   ' + _id_token);
        console.log('profile: ' + _profile);
    }

Related to this specific issue, my questions are:

  1. Does resumeAuth API follow the
    lock.on(“authenticated”,
    function(authResult) - or it is used
    instead?
  2. In my implementation I use
    Aurelia’s DI, with the
    consequence that the Lock is
    instantiated only once (when fetched
    from the Dependency Container for
    the first time). Based on my reading
    of the Auth0 documentation, is seems
    that this might be wrong as the Lock
    behaves as a singleton (for a
    specific client, that is), so I
    might be in trouble by optimizing my
    code :slight_smile:

Update (in reaction to @jmangelo answer)

Your paragraph

In a process like this the (HTTP) redirect happening at the fourth step implies that for a SPA the application will have to reload because the browser is moving from one web application (identity provider) to another (the SPA). Since this is mandated by OAuth2/OIDC you’ll find references to the unavoidable situation in SPA’s which is mostly correct.

is the answer I am looking for more than a month. Not having sufficient Auth0 experience (do not take this as stating that I do not have sufficient identity management experience, though :-)) I was suspicious of everything and wanted one firm anchor to start from. Thank you for providing it now.

Let me also argue your point the application will have to reload because the browser is moving from one web application (identity provider) to another (the SPA). My application has a very special relationship with Auth0 - as defined on the Dashboard, so I could envision a solution where the redirect to my app’s Allowed Callback URL (with proper definition of Allowed Origins) can perceived by my app as a simple navigation request to a different route, invoking the module where the data returned by Auth0 are processed, without any app reload taking place. This behavior after all is precisely the reason SPA was “invented”, just like AJAX was created to prevent full page refresh.

Now, I am not asking you to implement this behavior - my whole point is to ensure that I am not doing something really silly, while representing Auth0 to the Aurelia Community, where everybody understands HTTP protocol and very few know how to use Auth0. To say it differently, I am constantly seeking for best Auth0 development practices, just like am doing the same on the Aurelia side.

Finally, my original aim is to illustrate the concept of “late authentication” (do it if and when needed) - and at the time there could be a lot of “application” state that I would have to persist across authentication. This in itself is not an unsolvable problem by any means - it would just seem unnecessary if people do not understand your just provided explanation of the "necessary application reload*.

I understand that my idea to “improve” the communications between the Auth0 and my SPA app is not compliant with OAuth2/OIDC, so let’s see if they will enhance the current protocol at some later time.

Starting by answering your specific questions regarding Lock:

1. (use of resumeAuth)

The use of this method is strictly associated with the autoParseHash toggle. By default Lock will try to automatically parse the authentication response and trigger the respective events. If you disable this behavior by using autoParseHash: false then you’re responsible for triggering the hash parsing yourself. Have in mind, that events (like authenticated) will be triggered independently if the hash parsing was triggered manually or automatically. Also note that according to the documentation the autoParseHash toggle is configured within the auth parent object and not at the root.

2. (Lock instantiation)

If Lock is always used with the same configuration then you may get away with creating only once, but it would probably depend on the exact scenarios. Also of interest is that a successful use of Lock will generally mean the use of a redirect-based flow which ends up reloading everything; this behavior seems to be the crux of your question so lets focus on that instead.


(redirect/reload/reset situation)

The underlying authentication protocols being used (OAuth2/OIDC) imply that, in general, for a web application the authentication should depend on the use of HTTP redirects. The high-level steps can be described like this:

  1. The user (still not authenticated) access the application and triggers a login.
  2. The application redirects the user to the associated identity provider (in this case, your Auth0 account).
  3. The user performs authentication at the identity provider.
  4. The identity provider redirects back to the client application with an assertion that proves the identity of the user.

In a process like this the (HTTP) redirect happening at the fourth step implies that for a SPA the application will have to reload because the browser is moving from one web application (identity provider) to another (the SPA). Since this is mandated by OAuth2/OIDC you’ll find references to the unavoidable situation in SPA’s which is mostly correct.

Due to the nature of SPA’s the only option to not reload the application would be for the user to authenticate in a way that the original browser window is never navigated from the SPA to the identity provider. This is not impossible and you could trigger the authentication to happen in a popup window; however, most of the times using popups is a problem on his own so you may also not see many references to this.

In addition, even though the application needs to reload you can implement it in a way that is transparent for the user. The user won’t care that behind the scenes your applications is reloaded as long as the user sees a consistent experience, more specifically, if the user was at screen A before login they will likely assume that after authentication screen A will be shown to them and this can be implemented after your application reloads (the big issue is if your application takes really long to initialize itself, but this is an issue that would already exists; the login just increases the number of times the user experience it).

It also seems that you reply The redirect url failed to handle SPA url with hash - Auth0 Community indicates a solid alternative to the application reload. Is this correct?

It also seems that you reply The redirect url failed to handle SPA url with hash - Auth0 Community indicates a solid alternative to the application reload. Is this correct?

The form_post response mode although being an alternative method to deliver the response still implies that the navigation to the identity provider has happened so for this scenario is not really any different.