getTokenSilently() failing with "ID token is required but missing" error

Hello,

I am building an Angular service (AuthService) like you have in your Quick Start guide. I need to be able to exchange our Auth0 accessToken for a Firebase token whenever the accessToken is updated. To do this I’ve added a refresh timer in my AuthService to manually invoke getTokenSilently() to get the latest accessToken and then call a REST service to mint a new Firebase token.

The problem I’m having is if I set that refresh timer to run prior to the accessToken expiration, I just receive back the same accessToken (that is about to expire). If I set it to run at the same time or slightly after the accessToken expiration, I get an error ID token is required but missing. I have enabled refresh token rotation on the Auth0 application and enabled offline_access on the Auth0 API for the accessToken. The refresh_token grant type is also applied to the Auth0 application. I see the refresh_token stored in localStorage along with the id_token, access_token, etc. so I know I’m getting it. It seems like everything is configured correctly to enable refresh token use.

Perhaps I don’t really understand how the refresh_token is used within the bowels of auth0-spa-js. My assumption was that it would use the refresh token to go get a new access_token from Auth0 either whenever getTokenSilently() was invoked or by tracking the access_token expiration and automatically going to Auth0 to fetch an updated one (using the web worker). What triggers the use of the refresh token by auth0-spa-js and if getTokenSilently() will not force it, is there another method that can be called to force the silent refresh?

Any help, greatly appreciated. Thanks!

Follow up:
I was able to discover that the calls to /oauth/token with the refresh token are occurring but the response is missing the id_token and scope fields. I am getting a new access_token and refresh_token in the response. What could be causing that? I saw a post mentioning that the original token must have included the openid scope and it does. Any other common reasons that the scope and id_token would be missing in the response to /oauth/token during refresh?

1 Like

Not sure why this post was marked as the solution. I’m still wondering why the id_token isn’t being returned automatically as it is described in documentation. Looking at the code, I don’t see a way to force the call to oauth/token to contain the openid scope which would result in it properly sending back the id_token. Is this a bug somewhere either in Auth0 token service or the auth0-spa-js?

For others that run into this problem, here was my solution.

I had a rule that ensured that there weren’t any scopes requested that hadn’t been authorized. It was modeled after the example here.

When a request to refresh the access_token comes in from the auth0-spa-js library, it won’t have any scopes defined. Because my rule sent back an empty string for scope in that scenario, it was causing the id_token to be left off the response. Here is my final code for the rule that includes a workaround to add the proper scopes on when a refresh request comes in:

/**
 * Rule to check permissions to filter user scopes on access token
 *
 * @param {*} user
 * @param {*} context
 * @param {*} callback
 */
function checkScopes(user, context, callback) {
  const permissions = user.permissions || [];
  context.request.body = context.request.body || {};
  context.request.query = context.request.query || {};
  let requestedScopes = context.request.query.scope || context.request.body.scope || '';
  if (context.protocol === 'oauth2-refresh-token') {
    requestedScopes = requestedScopes || 'openid profile email offline_access';
  }
  const filteredScopes = requestedScopes.split(' ').filter( function(x) {
    return x.indexOf(':') < 0;
  });

  Array.prototype.push.apply(filteredScopes, permissions);
  context.accessToken.scope = filteredScopes.join(' ');

  callback(null, user, context);
}

Hope that helps others. Cheers!

1 Like

Glad you have figured it out and thanks for sharing with the rest of community!

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