Populate authorities in Auth0 Spring Security API from Auth0 assigned user permissions

I’m currently integrating my Angular front app + Spring Boot REST backend with Auth0. Everything works pretty well so far, I’m using Implicit Flow with accessToken for API authorization in the OIDC-conformant flow. However, one thing that is missing is the permission resolution.

In my Spring Security config I’ve used GitHub - auth0/auth0-spring-security-api: Spring Security integration with Auth0 to secure your API with JWTs library (version 1.2.3), which works fine when it comes to JWT decoding and endpoint protection as such. However, when I want in addition to use granted authorities for more fine-grained endpoint access restriction, e.g.:

.antMatchers(HttpMethod.GET,"/api/private-scoped").hasAuthority("entity:read");

the authority doesn’t get resolved. I’ve set this entity:read permission on a user in Auth0 using OOTB functionality (no Authorization Extension installed): Mgmt Console → User → Permissions → Assign Permissions. Unfortunately, the assigned permission doesn’t get populated onto Spring Security granted authority. And I do know why: in line 42 of the Auth0 Spring Security API library auth0-spring-security-api/AuthenticationJsonWebToken.java at master · auth0/auth0-spring-security-api · GitHub the authority gets resolved from only the scope claim. On the other hand, when I decode the JWT manually I see the permissions are correctly attached to JWT (without any running rule!), but they are placed under permissions claim, like this:

"scope": "openid profile email",
  "permissions": [
    "entity:read",
    "entity:write"
  ]

The Auth0 Spring Security API indeed captures openid, profile and email as granted authorities, but nothing else. This is an open issue with the library and there even is an open Pull Request for that (Support additional OIDC Conformant scope claims by ryan-barker-zefr · Pull Request #12 · auth0/auth0-spring-security-api · GitHub), which seems to be dangling for quite a while.

So until the library gets fixed, I’ve tried a workaround to manually copy over the permissions into scope claim. Unfortunately it seems I can’t access Auth0 permissions assigned to a user from either context or user object in a rule, I’ve searched all over using the debug code:

function (user, context, callback) {
  console.log(user);
  console.log(context);
}

My last resort was to implement a hook, which apparently has even a ready example for augmenting scope claim with additional roles:

module.exports = function(client, scope, audience, context, cb) {
  var access_token = {};
  access_token.scope = scope;
  // Modify scopes or add extra claims
  // access_token['https://example.com/claim'] = 'bar';
  access_token.scope.push('customRole');
  console.log("hook OK");
  cb(null, access_token);
};

But even with this hook being active I don’t see anything changed in the scope claim, in fact I don’t even see any log message in the Realtime Web-task log viewer so I’m not sure if the hook is running.

Please kindly advise what could be other steps to take. Just to recap: I simply want to have my Spring Security Auth0 library properly recognising Auth0 user permissions and placing them as granted authorities.

You can put the permissions that are needed as scope in the authorize request in your Angular app, such as:
openid profile email entity:read entity:write
Then they would appear right in the scope claim in the JWT. And of course the scopes that a user is not allowed to get would not be included and dropped by the Authorization Server / Auth0.

Regarding your workarounds:

I’m myself not too familiar with the Auth0 Spring Security API in detail, but wanted to mention in regards to the hook you mention at the bottom: where did you register this hook? I assume you put this under Dashboard > Hooks > Client Credentials Exchange, where it says:

The client-credentials-exchange hook allows custom code to modify the scopes and add custom claims to the tokens issued from the POST /oauth/token Auth0 API.

Note that this only works for the Client Credentials Exchange, not for the Implicit or any other grant type.

Regarding the rule:

You can set access token scopes in a rule, however, you can only set the complete scope set. Meaning you can neither read the existing/requested scopes within a rule itself, nor can you append scopes, only completely assign a new set. (We have received this question/feedback before and noted it down in a product backlog for consideration review, but at the moment it’s not possible.)

So, to assign a complete set of scopes to a token, it would be via (which is not suitable for your case):

function (user, context, callback) {
  context.accessToken.scope = 'scope1 scope2 somethingelse';
  callback(null, user, context);
}

Thank you for your prompt answer. Your clarification explains well why both my hook and rule didn’t work properly.

I have eventually come up with a workaround that satisfied our requirements. It turned out that although permissions are (for some reason) not visible in the user or context object on a Rule level, but the Roles are listed on the context object:

...
authorization: {roles:["MyCustomRoles]},
...

So after I introduced the following rule:

function (user, context, callback) {
  let roles = context.authorization.roles;
  let customRoles = "";
  if (roles !== undefined) {
    for (let i = 0; i < roles.length; i++) {
    customRoles += " " + roles[i];
    }
  } else {
    console.log("roles is null");
  }
  context.accessToken.scope = "openid profile email" + customRoles;
  callback(null, user, context);
}

The roles have become visible on the Spring Security side and the hasAuthority checks started to work. It’s not a perfect solution as I had to directly specify the OIDC scopes, but hopefully the Auth0 Spring Security API library will get fixed soon and the whole issue will not be there anymore.

1 Like

Yes, this is correct, same as scopes already requested (TBH I don’t know the reason behind this myself), which is why you cannot simply append but need to assign them completely new, like you do in your rule as well. Glad you found a solution.

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