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);
}