Lock: [v10] Login redirect happens before authenticated event

Created on 27 Jul 2016  路  18Comments  路  Source: auth0/lock

I'm using auth0 lock v10: http://cdn.auth0.com/js/lock/10.0.0/lock.min.js

I'm creating, showing and hooking the authenticated event like this:

this.lock = new Auth0Lock('foo', 'bar.eu.auth0.com', { auth: { params: { scope: 'openid given_name family_name email' } } });
this.lock.show();
this.lock.on('authenticated', (authResult) => {
localStorage.setItem('id_token', authResult.idToken);
console.log('logged in!');
});

I am calling login from http://localhost:9000/#/login and the redirect is taking me to http://localhost:9000/. On that page I have a check if localStorage contains id_token but it does not so an error is generated. Immediately after that the authenticated event is triggered, thus setting the id_token.

I am redirected before the authenticated event is triggered, thus the localStorage does not contain id_token.
Why is the redirect happening before the authenticated event, am I missing something?

Most helpful comment

@gnandretta thanks for the answer but I still don't understand the flow. I don't know if it matters but I'm using Aurelia as my JavaScript client framework and I'm not using push state so the URLs includes a hash (#).

I'm using auth0-lock version 10.0 and I show the lock as a modal.

When I login I guess I'm redirected to auth0 some where but the URLs I can see and act upon are these:
Starting: http://localhost:9000/#/login
After login I get redirected to http://localhost:9000/#access_token=xyz&id_token=xyz&token_type=Bearer&state=xyz
After that I get redirected to http://localhost:9000/#

I'm not entirely sure why I get that second redirect and why I get the access_token + id_token + token_type + state added to the query string. It also looks a bit odd that the first parameter (access_token) isn't prefixed with a question mark (?).

When I Get redirected to the last step (http://localhost:9000/#) my app manages to fire an event to my API (http://localhost:9000/api/test/secure) before the lock.on('authenticated', ...) event fires. My API rejects this call as unauthorized.

I managed to circumvent this issue by actually parsing the query string and extracting the id_token in the first redirect step. I don't think this is how I am supposed to handle it.

Also, if I add a redirectUrl in my lock settings then the responseType is automatically changed to "code" and instead of the id_token a code + state is added to the query string. If I set the redirectUrl and also set the responseType to "token", then no parameters are sent to the redirectUrl (!?). This must be a bug.

Any help on this issue is greatly appreciated.

All 18 comments

Hi, you are using lock in redirect mode, which is the default. After you enter the username and password you are redirected to auth0 and then back to your application. Only at this point the authentication is complete and the authenticated event is emitted.

@gnandretta thanks for the answer but I still don't understand the flow. I don't know if it matters but I'm using Aurelia as my JavaScript client framework and I'm not using push state so the URLs includes a hash (#).

I'm using auth0-lock version 10.0 and I show the lock as a modal.

When I login I guess I'm redirected to auth0 some where but the URLs I can see and act upon are these:
Starting: http://localhost:9000/#/login
After login I get redirected to http://localhost:9000/#access_token=xyz&id_token=xyz&token_type=Bearer&state=xyz
After that I get redirected to http://localhost:9000/#

I'm not entirely sure why I get that second redirect and why I get the access_token + id_token + token_type + state added to the query string. It also looks a bit odd that the first parameter (access_token) isn't prefixed with a question mark (?).

When I Get redirected to the last step (http://localhost:9000/#) my app manages to fire an event to my API (http://localhost:9000/api/test/secure) before the lock.on('authenticated', ...) event fires. My API rejects this call as unauthorized.

I managed to circumvent this issue by actually parsing the query string and extracting the id_token in the first redirect step. I don't think this is how I am supposed to handle it.

Also, if I add a redirectUrl in my lock settings then the responseType is automatically changed to "code" and instead of the id_token a code + state is added to the query string. If I set the redirectUrl and also set the responseType to "token", then no parameters are sent to the redirectUrl (!?). This must be a bug.

Any help on this issue is greatly appreciated.

@mikeesouth can you provide a sample with the issue?

@gnandretta Yes, I will try to provide a minimal example to reproduce the error but it will not be before next week at the earliest.

@mikeesouth, @gnandretta Hello guys, I have the same problem and I was thinking that was a problem of implementation but when I did it with the version 9 from the CDN it works as expected. I was following this example: https://github.com/auth0-blog/redux-auth0.

I have the example here: https://zendify.herokuapp.com/.
This is the repository: https://github.com/Garethderioth/zendify.

You can try to log in and see the redirect issue. Then, you have to refresh the page for see that the logging was successful.

The user email is: [email protected] and the password is foobar.

@Garethderioth the example you took as a reference uses Lock 9 in popup mode (which is discouraged) and your application uses lock 10 in redirect mode (which is the default). In redirect mode the authenticated event happens once you are redirected back to your application.

This seems to be done intentionally.. ? https://github.com/auth0/lock/blob/f3f7e4ac308809036aac45d33d5fcda8481d25d0/src/core/index.js#L180

The reason I even need to set a redirectURL at all seems to be a single page app issue. I initialize lock on page load, which takes current url, but then doesn't update based on history pushstate.

@gnandretta You are right. I just use the following configuration, for what I need:

const options = { auth: { redirect: false }, autoclose: true };

Regards!

Is there still an issue with the latest Lock version?

im using same options and hide callback is happening before authenticated.
Which is not what i expected for example in case of routing authGuard since i cannot detect if user was was authenticated and closed the lock or just closed the lock.

@olaf89 can you provide a sample project to see what you are doing?

login action:

public login() {
            var loggedIn$ = Observable.fromEvent(this.lock, "authenticated");
            var closed$ = Observable.fromEvent(this.lock, "hide").map(x => null);

            this.lock.show();

            return loggedIn$.merge(closed$).first().do(x => {if (!x) throw ""})
    }

authGuard: (can authorize user to see the page)

        return this.authEffects.loginSuccess$.map(_ => true)
            .merge(this.authEffects.loginFailed$.map(_ => false))
            .take(1)

@olaf89 any chance of getting a full working sample project to debug?

I have the same issue. Here's a minimal example:

<!-- login.html -->
<script src="https://cdn.auth0.com/js/lock/10.2.2/lock.min.js"></script>
<script src="login.js"></script>

// login.js:
window.onload = function() {
  var lock = new Auth0Lock(CLIENT_ID, DOMAIN);
  lock.on("authenticated", function(authResult) {
    localStorage.setItem('idToken', authResult.idToken);
  });
  if (localStorage.getItem('idToken')) {
    console.log('success');
  } else {
    lock.show();
  }
}

After a successful login, lock reloads itself and only then the "authenticated" event is fired and localStorage is set. So it takes 2 times instead of just 1 to log in successfully.

Is there any way to fix this behavior without requiring the user to manually press a "Login" button? I.e. I'd like to show Lock automatically on page load, but only if the user has not logged in before.

Turns out, this is kind of an "advanced" scenario in which, according to the README, we have to use another event - hash_parsed:

window.onload = function() {
  var lock = new Auth0Lock(CLIENT_ID, DOMAIN);
  lock.on("hash_parsed", function(authResult) {
    if (authResult == null && localStorage.getItem('idToken') == null) {
      lock.show();
    } else {
      localStorage.setItem('idToken', authResult.idToken);
      console.log('success');
    }
  });
}

Now it appears to work correctly, since it handles both cases: a "cold" page load and a redirect from successful authentication with idToken passed over query string.

Closing this one per https://github.com/auth0/lock/issues/514#issuecomment-247817368. Please reopen if the hash_parsed event is not enough

hash_parsed is the answer :)

  onHashParsed() {
    this.lock.on('hash_parsed', (authResult) => {
      this.log('hash parsed', {
        authResult
      });
      if (authResult == null) {
        if (this.getAuth0Token() == null) {
          this.showLock();
        }
      } else {
        this.log('setting auth token', {
          authResult
        });
        if (authResult.idToken) {
          this.setAuth0Token(authResult.idToken)
          this.log('success', authResult);
        } else {
          this.error('authResult missing idToken')
        }
      }
    })
    return this
  }
Was this page helpful?
0 / 5 - 0 ratings

Related issues

sandrinodimattia picture sandrinodimattia  路  6Comments

benmadany picture benmadany  路  4Comments

DavidWells picture DavidWells  路  5Comments

dharness picture dharness  路  6Comments

virgil-av picture virgil-av  路  5Comments