Auth0 Home Blog Docs

What's the best practice to handle metadata?

rules
spa
app_metadata
scope
user_metadata

#1

Hi,

I am creating a multi-tenant app based on a SPA (Angular) + Node.js back-end + Auth0.
I would like my app to exchange user info with Auth0. Based on conversation here, I have creating a rule to add metadata to tokens.

function (user, context, callback) {
  var namespace = 'https://mynamespace.com/';
  context.idToken[namespace + 'user_metadata'] = user.user_metadata;
  context.accessToken[namespace + 'app_metadata'] = user.app_metadata;
  callback(null, user, context);
}

I get tokens using the following scope:
SCOPE: ‘openid profile email update:current_user_metadata’
(and I have activated the “Allow Skipping User Consent” of the API)

Then, when the app update some user preferences (like default language), I send a PATCH request:

this.httpClient.patch(
  AUTH_CONFIG.AUDIENCE + 'users/' + this.authService.userProfile.sub,
  {"user_metadata": {"preferences": {"language": lang.id}}},
  {headers: new HttpHeaders().set('Authorization', `Bearer ${localStorage.getItem('token')}`)
}).subscribe(
  (val) => {
      console.log("PATCH call successful value returned in body", val);
      //update local profile (WARNING: doesn't refresh the id token that also contain user_metadata)
      this.authService.user_metadata.preferences.language = lang.id;
      this.authService.userProfile['https://mynamespace.com/user_metadata'] = this.authService.user_metadata;
      localStorage.setItem('profile', JSON.stringify(this.authService.userProfile));
  },
  response => {
      console.log("PATCH call in error", response);
  }
); 

As you can see, I update the user profile in the local storage (so that the app use the new parameter when it restart). However, I can’t update the tokens the same way. It’s working but I don’t like the discrepancy and I believe I may run into problems when I’ll send these tokens to my backend.

Therefore, I am wondering if adding the metadata to the tokens was a good idea in the first place. Should I instead extend the scope and read metadata from Auth0? Is it secure for a SPA to expand the scope access the API in such way? Hence my initial question, what’s the best practice here?


#2

If you wish to update your user’s metadata and have those changes be reflected in their tokens, the best solution is to first update the metadata in Auth0 via the management API as you are doing. You can then request a new token in your SPA via checkSession as described here.

You also should use your own intermediary API that makes the calls to the management API on the user’s behalf, that way the end user can’t use their access token to update other users. When you renew the token via checkSession, your rules will be ran as usual so the new metadata will be included in the new token.


#3

Thanks. Eventually, after the subscribe, I have used the following code which renew the token (based on checkSession) and reschedule the automatic renewal.

    val => {
      //update token and local profile
      this.authService.renewToken();
      //reschedule token renewal
      this.authService.scheduleRenewal();
    },

My understanding is that checkSession is using cookie. However, I didn’t understand the part where you were saying that end user could use their access token to update other users.