Auth0.js: cannot impersonate (sign in as)

Created on 1 Mar 2018  路  17Comments  路  Source: auth0/auth0.js

when "sign in as" is used from user management, it triggers the application configured callback:
http://localhost:9000/auth0-callback#access_token=some-access-token&id_token=some-id-token&scope=openid&expires_in=86400&token_type=Bearer
notice, there is no state.

but in auth0.js v9 we have:
https://github.com/auth0/auth0.js/blob/2ca7ccf3ba8e736f859b1024a8327ab0f5f8b110/src/web-auth/index.js#L180-L191

it always trips "state does not match"

All 17 comments

I have the same problem. The only solution I've found so far is to use v9.2.3. after this version parseHash method will always check state and if it does not exist return this error.

It is still unclear on how to do impersonation in a new version. I have a suspicion they are going to deprecate this feature.

Found it @jimmyn https://github.com/auth0/auth0.js/compare/v9.2.3...v9.3.1#diff-2f11667c8f671044416e38e4ceb9d7c8R186

You could argue this breaks semver, but you could argue they fixed a bug

Hi folks! We're aware of the issue and working in a solution. Thanks for the patience 馃帀

We're adding a new option so you can enable impersonation again: https://github.com/auth0/auth0.js/pull/689

Yes. We're sorry about that. But we're closing an attack vector which is way more important. There will be docs about the trade-offs of using __enableImpersonation and what kind of attacks it leaves your users vulnerable to.

hey @Pyrolistical, do you want to test the new version with the flag so we make sure this works in your scenario? I already tested locally, but it'd be good to have an extra pair of hands working on this one! If you want to test it, here's the build file from this PR: https://770-13125982-gh.circle-artifacts.com/0/home/ubuntu/auth0.js/build/auth0.js

you'll need to add the __enableImpersonation flag to your parseHash method, like this:

webAuth.parseHash({__enableImpersonation: true}, function(err, authResult){

});

@luisrudge You are fixing this with an __enableImpersonation flag, but I have a way to fix this that doesn't break semver.

  1. When making an impersonation call, add a bypass-state parameter in the hash
  2. the bypass-state value is a timestamp on when the impersonation call was made + RS256 signature
  3. when auth0.js parseHash see bypass-state, it downloads the well known RS256 public key. it then verifies the RS256 signature of bypass-state and checks the timestamp is within the last 60 seconds

this allows impersonation to just work. the RS256 signature ensures only auth0 can ever set a valid bypass-state parameter. the timestamp in bypass-state prevents CSRF after 60 seconds

This is a great idea but, unfortunately, a product decision that I cannot make. You can ask reach out to our support team in https://support.auth0.com and add your suggestion there. I'll personally send this to the appropriate team and we'll see how it goes 馃帀

@luisrudge @Pyrolistical On my end, what I've done is to call checkSession when parseHash (and hence validateAuthenticationResponse) returns error. I'm not sure if that is the original design intent of checkSession but using checkSession negates the need for the additional __enableImpersonation flag. As an example,

        this.auth0.parseHash(function (err, authResult) {
          if (authResult && authResult.accessToken && authResult.idToken) {
            //handle success 
            return
          } else {
            this.auth0.checkSession({
              scope: this.options.auth.scope
            }, function (err, result) {
              if (err || !result || !result.idToken || !result.accessToken) {
                // regular login
                return
              } else {
                //handle success
              }
            }

Would this then nullify the CSRF attack vector associated with __enableImpersonation?

checkSession returns the current session in the authorization server (auth0). If impersonation sets a session in the server, then it works.

@luisrudge Yes it works on my end and so it seems that impersonation does indeed set a session in the server. Thus moving forward, shouldn't that be the default method to use for impersonation rather than setting the __enableImpersonation which then exposes the client to CSRF attacks?

I'm not sure we want to recommend people calling checkSession if the parseHash fails. I'll talk with the team internally and see what they think. Thanks for pinging me with this info!

@luisrudge One point to note that is that in the checkSession() method that I pointed out above, the impersonated & impersonator properties will never be set in the userInfo object.

@johnlim After reviewing your specific workaround which uses checkSession when the hash fails to be parsed, both our product and security teams are advising against it because this behavior will certainly change in the future.

Moving forward, we want developers to think about the implications of enabling the __enableIdPInitiatedLogin flag and issues they might face if they chose to do so.

@luisrudge Thanks! Will Auth0 provide more information on the implications and how we can mitigate them in the near future? At the moment, when I read the documentation, it seems to be flashing a big red flag that says "Use at your own risk!".

This is in our docs: https://auth0.com/docs/user-profile/user-impersonation#enable-impersonation, it's not a flashing warning, but a warning anyway 馃槤
image

Was this page helpful?
0 / 5 - 0 ratings