Search code examples
spring-securityauth0

Add 'ROLE' to spring security / Auth0 authorization


In my Spring Boot application i'm working with Auth0 to manage access to my rest api.
In addition to Auth0's scope i would like to add a ROLE to each user which in turn will provide an additional layer of access control where specific API's won't be accessible to low privileged users.

I've been reading about custom rules and authorization extensions but couldn't quite understand what is the right implementation for me.

Here's my WebSecurityConfigurerAdapter code snippet:
So basically i want only 'ADMIN' for example to be able to access /test/**

@Override
    protected void configure(HttpSecurity http) throws Exception {
        JwtWebSecurityConfigurer
                .forRS256(configBean.getAuth0ApiAudience(), configBean.getAuth0Issuer())
                .configure(http)
                .authorizeRequests()
                .antMatchers(HttpMethod.GET, "/test/**").hasAuthority("read:test")
                .anyRequest().authenticated();
    }

Any help would be much appreciated!


Solution

  • You have a few options here (at least..).

    1). You could conceivably use a Rule to do handle the decision logic on which "ROLES" are assigned to given user - and rather than tag this onto scope (which you could do too..), you may decide they belong instead as a custom claim on that access token. Body of Rule may contain something like

    // lookup the permissions for given user somehow (secured webhook, static map etc) - here lets imagine we want ROLE_USER assigned
    
    context.accessToken.scope = "ROLE_USER" 
     // or
    context.accessToken['https://mydomain/roles'] = "ROLE_USER"
    

    2). Simply use the fact that you have the auth0 userid available in the JWT Access token from Auth0 that you send to the API - you could use this knowledge to look up the finer grained permissions for that use "out of bands" of Auth0 (using your own database storage for permissions keyed on user Id etc or some other customer claim tagged on the access token - or by using auth0 if for example you tagged the ROLE information as metadata onto the Auth0 User profile. You could then do an Auth0 user profile lookup (management api) by user id and get details that way. See example here for an illustration in Java on getting the userId claim from the JWT access token if you like this approach.

    3). Take a look at the Auth0 authorization extension which provides support for user authorization via Groups, Roles, and Permissions. You can define the expected behavior during the login process, and your configuration settings will be captured in a rule that's executed during runtime.

    There is no hard and fast answer here, each of the above merits consideration, and what you need for your project. If you really want to leverage the existing declarative authorization as per your code above, then Option 1, and pegging the ROLES information to the scope is the easiest approach.

    However, I would actually advocate option 2). above myself, for most "pragmatic" small to medium sized ventures. Here, you would require a little programmatic code inside your Controller endpoint to lookup the ROLES and then make a security decision that way. You could also push out the lookup code into a common Custom Filter that executes before the Controller code is reached, and does the necessary Spring Security manipulation that way - more of an advanced developer option - (I have written libraries in the past that supported this approach for Spring Boot / Security - and can therefore vouch it is a reasonable approach. See here for demonstration but again, sure you would prefer to get on with building your business logic and not detour into building a library, right?).

    Option 3). is definitely worth exploring if you are building out a serious enterprise app, and need all the integrations - especially where integration with enterprise connections such as Active Directory are in play.

    Leave me comments if you are still confused, but hopefully the above offers sufficient insights to explore further.

    Quick update

    Further to our discussions, here is a little Rule that gives you the idea you were asking about:

    function addRoleScopesToAccessToken(user, context, callback) {
      console.log("add-role-scopes-to-access-token rule");
      user.app_metadata = user.app_metadata || {};
      var roles = user.app_metadata.roles;
      if (roles && roles.length > 0) {
        context.accessToken.scope = roles.join(' ');
      }
      callback(null, user, context);
    }
    

    And this is how your "app_metadata" might look like:

    {
      "roles": [
        "role1",
        "role2"
      ]
    }
    

    You should end up with a JWT access token with the roles added to the scope. eg.

    enter image description here