Insufficient Scope error. Token does not contains scopes

In my application each administrator has app_metdata attribute that defines whether or not they have the admin role. I am using a rule (below) to add the admin scope if the user has this metadata.However, any API calls using the token returns an insufficient scope error. I have used jwt.io to verify that NO scopes are returned in my token. What do I have to do to ensure my authorized scopes are included in the JWT?

  function (user, context, callback) {
  var _ = require("lodash");
  
  var req = context.request;
  
  // Get requested scopes
  var scopes = (req.query && req.query.scope) || (req.body && req.body.scope);
  
  // Normalize scopes into an array
  scopes = (scopes && scopes.split(" ")) || '';


  if (user.app_metadata !== undefined && user.app_metadata.roles !== undefined && user.app_metadata.roles.indexOf('admin') >= 0) {
   scopes.push("admin"); 
  }
  // Restrict the access token scopes according to the current user
  //context.accessToken.scope = restrictScopes(user, scopes);
  console.log('scopes',scopes.join(" "));
  context.accessToken.scope = scopes.join(" ");
  callback(null, user, context);

}
1 Like

I am trying to do a similar thing with a similar rule.

One of my applications will have the scopes on the access token, and another does not have it…

Did you end up finding a solution for this?

This was actually answered by @tanver.hasan in StackOverflow but I’ll include it here for you and others in the future:

The rule looks correct. But the problem may be with loadash. I have used Authorized extension to add roles, permission, and group to users. It updates the user app_metadata field. To add the user’s permissions in the scope, I used the following rule.

function (user, context, callback) {
  if (context.request.query.audience === '[api identifier]' && 
      context.clientID === '[client id]') {
  var req = context.request;
  var scopes = (req.query && req.query.scope) || (req.body && req.body.scope);
  var permissions = user.permissions || [];
  var requestedScopes = context.request.body.scope || context.request.query.scope;
  var filteredScopes = requestedScopes.split(' ').filter( function(x) {
    return x.indexOf(':') < 0;
  });
  Array.prototype.push.apply(filteredScopes, permissions);
  console.log(filteredScopes.join(' '));
  context.accessToken.scope = filteredScopes.join(' ');
  }
  callback(null, user, context);
} 

Auth0 Configuration (SPAs + API)

Make sure to restrict the permission to specific API and client. Otherwise, you might provide access to management API in the token mistakenly. If you are not using authorized extension, you can get the correct permission form the user object (user_metadata).

Alternatively, to add any specific API scope in the token for the API access, you can request the scope when you are calling /oauth/token or /authorize endpoint.

The /authorize endpoint is used for implicit grant , authorization code grant flow and authorization code grant with PKCE. The purpose of this call is to obtain consent from the user to invoke the API (specified in the audience field) and do certain things (specified in scope) on behalf of the user. Auth0 will authenticate the user and obtain consent, unless consent has been previously given. If you alter the value in scope, Auth0 will require consent to be given again. It should be executed in the browser

https://YOUR_AUTH0_DOMAIN/authorize?
  audience=API_IDENTIFIER&
  scope=openid%20email%20profile%20read:user&
  response_type=token%20id_token&
  client_id=YOUR_CLIENT_ID&
  redirect_uri=https://YOUR_APP/callback&
  state=123&
  nonce=234

On the other hand, /oauth/token endpoint is used to implement clent credentials grant and resource owner password credentials grants. The following curl command ask for a token. It is using Resouce owner password credentials grant

curl --request POST \
  --url 'https://YOUR_AUTH0_DOMAIN/oauth/token' \
  --header 'content-type: application/json' \
  --data '{"grant_type":"password","username": "user@example.com","password": "pwd","audience": "https://someapi.com/api", "scope": "read:sample", "client_id": "YOUR_CLIENT_ID", "client_secret": "YOUR_CLIENT_SECRET"}'

Note: You have to use Access token for API call.

Additionality, you can try adding admin role or permission as custom claim using rule in the access token or id_token. Based on the claim, you can restrict the access. For example,

function (user, context, callback) {
  const namespace = 'https://myapi.com/';
  context.idToken[namespace + 'user_metadata'] = user.user_metadata;
  context.accessToken[namespace + 'user_metadata'] = user.user_metadata;

  callback(null, user, context);
}

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