Refreshed access_token with custom audience results in 401 Unauthorized on the /userinfo endpoint

I am trying to get user info from the /userinfo endpoint using an access token with a custom audience (the custom audience is necessary for my application). This works with the initial access token, but after getting a new token with the refresh_token, I can no longer send requests to /userinfo.

I get the initial token using an authorization_code request to /oauth/token. In the initial login request, I included the custom audience in the parameters, like &audience=https://myapi.com. The access_token that is returned then has two audiences:

  "aud": [
    "https://myapi.com",
    "https://mytenant.auth0.com/userinfo"
  ],

This token works fine with the /userinfo endpoint, since it includes that userinfo audience.

The issue arises when I try to get a new access token using the refresh_token. I do this by sending a refresh_token request to /oauth/token. The access_token returned in this response only has a single audience:

  "aud": [
    "https://myapi.com"
  ],

As you can see, it no longer has the userinfo audience. When I try to use this new access token on the /userinfo endpoint, I get a “401 Unauthorized” error.

Is this intended behaviour? How am I supposed to use the /userinfo endpoint after refreshing my token?

One interesting thing to note is that if I do not use a custom audience in the initial login request, then I get back an opaque token that works with /userinfo even after being refreshed. Unfortunately, I need the custom audience for the API that I am using, so this isn’t a viable workaround.

Hi @morgan.zolob,

Welcome back to the Auth0 Community.

This is actually the expected behavior when refreshing the access token. Usually the aud claim is meant to be populated with a single API identifier ( for general security measures when requesting an access token ), the intended resource server receiver of the token, while the /userinfo endpoint presents the only exception. It is the single case where 2 different audiences can be specified for requesting a token.

You can check out this github page for more information.

The solution would be making the first request for your custom API set as the audience, then either make a separate call using a function such as getTokenSilently ( this depends on the SDK that is being used ) to the /userinfo endpoint with the API identifier set such as https://{CanonicalDomain}/userinfo. This is also mentioned in our Get User Info documentation:

To access the most up-to-date values for the email or custom claims, you must get new tokens. You can log in using silent authentication (where the prompt parameter for your call to the authorize endpoint equals none ).

You can also simply rely on the ID token issued from the initial request ( if you only need basic information about the user ).

I hope this helps!
Best regards,
Remus

Thanks @remus.ivan for the response. Unfortunately due to my site being on a different domain than my tenant, I can’t rely on getTokenSilently (at least not the iframe method that calls /authorize) since many browsers block third party cookies. This is why I was using refresh tokens in the first place. Unfortunate that there’s no way to make this work.

I guess I will look into updating my apps so that I can use something like the id_token instead and not rely on /userinfo.