Web App not working with new Auth0 Tenant

I have a web app served with Node/Express which presently works fine.

I’m trying to set up a separate tenant for my dev/test environment so I don’t have to pollute the login database with test users.

But I’m guessing the existing tenancy had a bunch of legacy options enabled which are no longer available for new signups, as my app no longer receives all the relevant information.

I’m using passport-auth0 which calls the /userinfo endpoint as far as I’m aware.
Using the existing tenant I get something back like this:

  { auth0Id: 'auth0|59a1....',
   auth0:
   { accessToken: 'Azy2W6Y5....',
     profile:
      { provider: 'auth0',
        displayName: 'al@twohill.nz',
        id: 'auth0|59a1....',
        user_id: 'auth0|59a1....',
        name: [Object],
        emails: [Array],
        picture:
         'https://s.gravatar.com/avatar/...',
        nickname: 'al',
        identities: [Array],
        _json: [Object],
        _raw:
         '{"email":"al@twohill.nz","user_metadata":{"title":"Monsieur","given_name":"Al","family_name":"Twohill","lang":"fr"},"name":"al@twohill.nz","picture":"https://s.gravatar.com/avatar/...","nickname":"al","app_metadata":{"role":"client"},"role":"client","email_verified":false,"clientID":"68BHX6LhcnFq....","updated_at":"2018-10-23T08:27:19.643Z","user_id":"auth0|59a1....","identities":[{"user_id":"59a1....","provider":"auth0","connection":"Username-Password-Authentication","isSocial":false}],"created_at":"2017-08-26T21:39:29.871Z","sub":"auth0|59a1...."}' 
      } 
    }
  }

Which as you can see includes all the information such as app_metadata etc.

With the new tenancy I get a different response

 { auth0Id: 'auth0|5bce966f9a...',
  auth0:
   { profile:
      Profile {
        displayName: '....client1@gmail.com',
        id: 'auth0|5bce966f9a...',
        user_id: 'auth0|5bce966f9a...',
        name: [Object],
        picture:
         'https://s.gravatar.com/avatar/...',
        nickname: '....client1',
        _json: [Object],
        _raw:
         '{"sub":"auth0|5bce966f9a...","nickname":"....client1","name":"....client1@gmail.com","picture":"https://s.gravatar.com/avatar/...","updated_at":"2018-10-23T08:16:55.756Z"}' },
     accessToken: 'W4fnoDB_0ja8C_...',
     refreshToken: undefined }
   }

This doesn’t have any of the app_metadata in it!

I’ve read the docs here User Profile Structure and here Understand How Metadata Works in User Profiles but I’ve become thoroughly confused. There is mention of having to create a rule to expose metadata (which I tried but it seems really hard!) or I have to “utilize one of the User endpoints of the Management API”.

Am I missing something or has this gotten unbearably hard? I’m nearly ready to throw in the towel and write my own authentication!

Can anyone help me with this?

Hey there @alt, I wouldn’t throw in the towel just yet.

In the metadata documentation it states:

Beginning 1 September 2017 , new tenants cannot search any of the app_metadata fields.

Only tenants associated with paid subscriptions that were created on/before 31 August 2017 can search the app_metadata fields.

Which means all new tenants won’t have access to app_metadata.

However you still have access to user_ metadata as described.

If you don’t mind sharing, please tell us the goal you are trying to achieve and we may be able to help you accomplish your desired result with the current constraints. Thanks!

Hi James,

There’s two parts to it. In app_metadata we’ve been storing the role which decides what sort of access the user gets to the application.

We also try and collect as much information as we require for billing directly from the users profile (eg name, email, etc). With social signups this works fine enough, but with username/password signups it doesn’t seem to be possible to populate the person’s name field, so we’ve been storing that in user_metadata as a workaround.

It’s a shame that the new tenants don’t “just work” - this was a key selling point for Auth0 for me. I can engineer around the constraints of the new tenants, but it’s probably just as easy at that point to use passport.js to authenticate directly against Google, Facebook etc and drop Auth0.

Hi @alt.

Let me try to explain the behavior you are now seeing, the reasoning behind it, and the suggested workaround.
In the old days, when the OIDC specification was finalized, Auth0 would return the full user profile (what you describe in the first JSON) to applications requesting an authentication with the openid profile scope. This included the identities array, the full app_metadata and user_metadata objects, and every other property provided by the upstream identity provider. This is what we call the “Legacy User Profile”.

This is a potential security issue. While it might not look like so when you use just one first party web server application with “full powers”, the OIDC/OAuth2 model provides a model where you could have many different applications authenticating with your Auth0 domain, some with more access than other (including potentially third party applications not developed by you). Also, some applications could consume user information directly from the browser (where the information is less secure). For all these reasons, we want to limit the amount of information returned to applications by default, and that’s why we moved to full OIDC conformance.

The OIDC spec defines a series of scopes (profile, email and others) that let applications specify exactly what information they require from the user. Each scope represent a series of well defined properties (claims) that will be returned (see here for more information on the standard OIDC scopes and claims).

If you want to return additional claims as part of the authentication response (be it in the ID Token or from the /userinfo endpoint) you can still do so, but you’ll need to be very explicit about it and write a rule that looks like this:

function(user, context, callback) {
  // better to be explicit and 
  // only add custom claims for the specific application that requires them
  // you can use context.clientID if it makes more sense to you
  if (context.clientName !== "the_name_of_the_app") { 
    return callback(null, user, context);
  ]
  
  // you will need to *namespace** the claims
  // the URL doesn't have to be real, but can't be an Auth0 domain
  const namespace = 'https://myapp.example.com/';
  context.idToken[namespace + 'role'] = user.app_metadata.role;
  context.idToken[namespace + 'preferred_contact'] = user.user_metadata.preferred_contact;
  callback(null, user, context);
}

In the resulting user information payload, you’ll see the two claims added (with the respective namespace) that you can use directly in your application.

This is described in detail here: JSON Web Token Claims.

We understand that we are adding a little more friction with this, but the reasoning behind the decision is to avoid spilling out too much information by default and require developers to be more explicit when sending potentially sensitive information to applications. Hopefully this works out for you.

3 Likes

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.