No app_metadata in resource owner password flow

  • Which SDK this is regarding: auth0-PHP
  • SDK Version: ^8.0
  • Platform Version: PHP 7.4 (WordPress)
  • Code Snippets/Error Messages/Supporting Details/Screenshots:

We have a flow that happens entirely on the server; needed, as we need to keep long-lived (refreshed) tokens without user intervention.

It goes something like:

    $this->httpClient = new \GuzzleHttp\Client();

    $config = new SdkConfiguration([
      'httpClient'     => $this->httpClient,
      'strategy'      => 'management',
      'clientId'      => $clientId,
      'clientSecret'  => $clientSecret,
      'domain'        => $this->domain,

    $this->authentication_client = new Authentication($config);


    return $this->_run_op(function ($arg) {
      return $this->authentication_client->login(
        ['scope' => 'offline_access'],
    }, ['username' => $email, 'password' => $password]);

We use a rule which augments our access_tokens with some information, that we then use with our internal system.

And this works with passwordless accounts.

However, the access tokens we obtain when performing the login above, or later, when requesting a new access_token using the refresh_token, are naked. In fact: worse than naked.

I am still able to use them as bearer tokens to query endpoints like /userinfo but they are short, and they don’t appear to include app_metadata.

Is this expected?

Hi @argo , it looks like you are getting an opaque token because you are not specifying an audience. When no audience is provided, it will default to an opaque token for calling /userinfo

I would recommend setting up a custom API in Auth0 so you can use its identifier as an audience, this will give you a JWT token instead of the opaque token. This behaviour is documented here:

You can then use Actions to add app_metadata to the tokens issued, e.g. if I wanted to add a user’s favourite_colour which is stored in their app_metadata to the access token, the action would look something like:

exports.onExecutePostLogin = async (event, api) => {
  const namespace = '';
  const favourite_colour = event.user.app_metadata.favourite_colour || "none"
  api.accessToken.setCustomClaim(`${namespace}/favourite_colour`, favourite_colour)

Note the namespace, it is important to provide a namespace which does not collide with reserved names - Create Namespaced Custom Claims

Please see these links for more information on Actions:

1 Like

Hi @sgo .

Thanks a lot for this prompt and complete explanation.

Yes, we are adding custom claims using rules right now, according to the old flow. I think rules are now part of actions.

I have configured an API, although our access control is simply based on roles in our custom claims.

Unfortunately, even when adding the audience:

$config = new SdkConfiguration([
      'httpClient'      => $this->httpClient,
      'strategy'        => 'management',
      'clientId'        => $clientId,
      'clientSecret'    => $clientSecret,
      'domain'          => $this->domain,
      'audience'        => $this->audience,

    $this->authentication_client = new Authentication($config);

I still seem to only get an opaque token.

The application, defined by the clientId / clientSecret, is authorized against the API, and audience is an array of URLs with just a single entry.

Thank you for your help.

Solved. I was able to get a fully formed access_token by adding the audience parameter to the API call, not the initialization.

    return $this->_run_op(function ($arg) {
      return $this->authentication_client->login(
        ['scope' => 'offline_access', 'audience' => $this->audience],
    }, ['username' => $email, 'password' => $password]);


1 Like

Wooohooo! Perfect! Glad to hear that!

Thanks @konrad.sopala .

I do have mixed news, and additional info:

  • Access tokens issued with passwordless authentication have two audiences associated with them; https://<tenant-default-domain>/api/v2 (management api), and https://<tenant-default-domain>/userinfo
  • Opaque access tokens only have https://<tenant-default-domain>/userinfo

When using the PHP SDK, although I presume that this is not specific to the PHP SDK, if I set the audience to https://<tenant-default-domain>, I get an opaque access token, in my case (because I have enabled it), a refresh token, and a fully fledged id token with all additional claims set.

If I set the audience to https://<custom-api-uri>, I get the access token and refresh token, and this time the access token is fully fledged. But in that case, of course, the access token is not valid against /userinfo.

Because my custom api doesn’t have an endpoint like that.

In my case, I am going to have to go with option A, since I need both the custom claims and the userinfo. I imagine that this behavior could be confusing to some, hence I wanted to leave some notes.

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