Learn how to implement SpringBoot roles and privileges with Granted Authorities, design secure REST API routes, and restrict access using hasAuthority().
TL;DR
-
Granted Authorities represent the privileges or permissions a user has in Spring Security.
-
hasRole()andhasAuthority()are similar, but roles use theROLE_prefix while authorities do not. -
A clear REST API route hierarchy makes it easier to apply authorization at a granular level.
-
UserPrincipalcan return a user’s privileges asSimpleGrantedAuthorityobjects throughgetAuthorities(). -
hasAuthority()can then protect specific API endpoints based on privileges such asVIEW_PRODUCTandCREATE_PRODUCT.
This is Part 3 of our implementation of SpringBoot roles and Privileges for our Inventory Management System (InventoryMS). In this part we would discuss and implement granted authorities in Spring Boot.
Parts 1 and 2 can be gotten from the links:
- SpringBoot Roles and Privileges – Standard Roles/Privileges in an Inventory Management System
- SpringBoot Roles and Privileges – The Data Model and API
- SpringBoot Roles and Privileges – Access Restriction Using Granted Authorities
1. What are Granted Authorities?
In Spring Security, we have the concept of Granted Authority. This represents a privilege or a permission granted to a user to perform a certain action.
What is difference between Role and Authority?
This two represent the same concept and are basically the same. The difference is how Spring Boot handle the prefixing. A role is expected to be prefixed with “ROLE_” but an authority is not.
For example, the authority “ADMIN” is the same as the role “ROLE_ADMIN”.
hasRole() vs hasAuthority()
This is also the same in concept. When you use hasRole(“ADMIN”), Spring Boot would expect that your role is named “ROLE_ADMIN”. However, if you use hasAuthority(“ADMIN”), Spring Boot would check if you have to role “ADMIN”
In our InventoryMS project, we would be using hasAuthority().
2. Design the REST API Endpoint Pattern
To be able to achieve and efficient way to protect your API, you will have to design the routing pattern. What does this mean? It means you need some hierarchy for the API route. For example:
- top level: version number would (/v1)
- next level: modules for example, /orders, /products and /suppliers
- from here you can have methods GET, POST, PUT and DELETE
With this we would be able provide authorization at a granular level
3. Retrieving the User’s GrantedAuthorities
To be able to protect our REST API based on user roles, we would have to do the following:
return the users authorities (privileges) from UserPrincipal
Here, we would need to update the getAuthorities method of the UserPrincipal class so that it returns a lit of SimpleGrantedAuthorities.
@Override public Collection<? extends GrantedAuthority> getAuthorities() { return userPrivilegeAssignmentService.getUserPrivileges(user.getId()) .stream() .map(privilege -> new SimpleGrantedAuthority(privilege.getDescription())) // Use SimpleGrantedAuthority .collect(Collectors.toList()); }
4. Configure Authorization Rules
At this point we would have to configure the permission on the routes. So we would have to check if the user has the required authority before the request is permitted.
The following changes would need to be made:
... ... .authorizeHttpRequests(auth -> auth .requestMatchers("/register").permitAll() .requestMatchers("/login").permitAll() //Configuration for the product module .requestMatchers(HttpMethod.GET, "/api/v1/products").hasAuthority("VIEW_PRODUCT") .requestMatchers(HttpMethod.POST, "/api/v1/products").hasAuthority("CREATE_PRODUCT") .requestMatchers(HttpMethod.DELETE, "api/vi/product").hasAuthority("DELETE_PRODUCT") //Configuration for the order module .requestMatchers(HttpMethod.GET, "/api/v1/products").hasAuthority("VIEW_PRODUCT") .requestMatchers(HttpMethod.POST, "/api/v1/products").hasAuthority("CREATE_PRODUCT") .anyRequest().authenticated() ) ... ...
Then we would have to repeat this for all other roles we identified.
You could also create an enum type to hold these roles instead of using just strings. But I see no added benefits for taking this extra step.
Note that in our application, we use Roles only as grouping for privileges.
Frequently Asked Questions
What is a Granted Authority in Spring Security?
A Granted Authority represents a permission or privilege that allows a user to perform a specific action within an application.
What is the difference between a role and an authority?
They represent similar concepts, but Spring Security handles their naming differently. Roles are typically prefixed with ROLE_, while authorities do not require that prefix.
What is the difference between hasRole() and hasAuthority()?
hasRole("ADMIN") checks for ROLE_ADMIN, while hasAuthority("ADMIN") checks for the authority named ADMIN.
Why does InventoryMS use hasAuthority()?
InventoryMS uses privileges as the actual permissions for API access, with roles serving primarily as groups for those privileges. hasAuthority() therefore fits the application’s fine-grained authorization model.
How does UserPrincipal provide authorities?
The getAuthorities() method retrieves the user’s privileges and converts each one into a SimpleGrantedAuthority, which Spring Security can use when evaluating authorization rules.
Why is API route design important for authorization?
A consistent hierarchy such as version → module → HTTP method makes it easier to apply specific permissions to individual API operations.
Final Thoughts
Granted Authorities provide the connection between the privileges defined in InventoryMS and the actual security rules protecting its API. Once a user’s privileges are exposed through UserPrincipal, Spring Security can use those authorities to decide which operations the user is allowed to perform.
Using hasAuthority() also supports the fine-grained approach established in the earlier parts of this series. Instead of treating roles as the final permission, InventoryMS uses roles to group privileges while individual authorities control access to specific API operations.
With a consistent REST API structure and clearly defined privileges such as VIEW_PRODUCT, CREATE_PRODUCT, and DELETE_PRODUCT, you have a flexible foundation for controlling access across the application’s modules.