It’s just plain hard to get true, real-time visibility into a running auth flow.

Parts of the process can be completely hidden from us; if the complete authorization process requires a redirect from a remote OAuth production server, then every debugging effort must go through the production server.

It’s practically unfeasible to debug this locally. There’s no way to reproduce the exact state and no way to inspect what is actually happening under the hood. Not ideal.

Knowing these types of challenges, we built Lightrun - a real-time production debugging tool - to allow you to understand complicated flows with code-level information. Add logs, take snapshots (virtual breakpoints), and instrument metrics without a remote debugger, without stopping the running service, and, most importantly - in real-time and without side effects.

Learn more with this 5-minute tutorial focused on debugging these kinds of scenarios using Lightrun:

>> Debugging Authentication and Authorization Using Lightrun

1. Overview

In this quick article, we'll explain the subtle but significant difference between a Role and a GrantedAuthority in Spring Security. For more detailed information on roles and authorities, see the article here.

Further reading:

Spring Security Basic Authentication

Set up Basic Authentication in Spring - the XML Configuration, the Error Messages, and example of consuming the secured URLs with curl.

2. GrantedAuthority

In Spring Security, we can think of each GrantedAuthority as an individual privilege. Examples could include READ_AUTHORITY, WRITE_PRIVILEGE, or even CAN_EXECUTE_AS_ROOT. The important thing to understand is that the name is arbitrary.

When using a GrantedAuthority directly, such as through the use of an expression like hasAuthority(‘READ_AUTHORITY'), we are restricting access in a fine-grained manner.

As you can probably gather, we can refer to the concept of authority by using privilege as well.

3. Role as Authority

Similarly, in Spring Security, we can think of each Role as a coarse-grained GrantedAuthority that is represented as a String and prefixed with “ROLE. When using a Role directly, such as through an expression like hasRole(“ADMIN”), we are restricting access in a coarse-grained manner.

It is worth noting that the default “ROLE” prefix is configurable, but explaining how to do that is beyond the scope of this article.

The core difference between these two is the semantics we attach to how we use the feature. For the framework, the difference is minimal – and it basically deals with these in exactly the same way.

4. Role as Container

Now that we've seen how the framework uses the role concept, let's also quickly discuss an alternative – and that is using roles as containers of authorities/privileges.

This is a higher level approach to roles – making them a more business-facing concept rather than an implementation-centric one.

The Spring Security framework doesn't give any guidance in terms of how we should use the concept, so the choice is entirely implementation specific.

5. Spring Security Configuration

We can demonstrate a fine-grained authorization requirement by restricting access to /protectedbyauthority to users with READ_AUTHORITY.

We can demonstrate a coarse-grained authorization requirement by restricting access to /protectedbyrole to users with ROLE_USER.

Let's configure such a scenario in our security configuration:

protected void configure(HttpSecurity http) throws Exception {
    // ...
    // ...

6. Simple Data Init

Now that we understand the core concepts better, let's talk about creating some setup data when the application starts up.

This is, of course, a very simple way of doing that, to hit the ground running with some preliminary test users during development – not the way you should handle data in production.

We're going to be listening for the context refresh event:

public void onApplicationEvent(ContextRefreshedEvent event) {
    MyPrivilege readPrivilege
      = createPrivilegeIfNotFound("READ_PRIVILEGE");
    MyPrivilege writePrivilege
      = createPrivilegeIfNotFound("WRITE_PRIVILEGE"); 

The actual implementation here doesn't really matter – and generally, depends on the persistence solution you're using. The main point is – we're persisting the authorities we're using in the code.

7. UserDetailsService

Our implementation of UserDetailsService is where the authority mapping takes place. Once the user has authenticated, our getAuthorities() method populates and returns a UserDetails object:

private Collection<? extends GrantedAuthority> getAuthorities(
  Collection<Role> roles) {
    List<GrantedAuthority> authorities
      = new ArrayList<>();
    for (Role role: roles) {
        authorities.add(new SimpleGrantedAuthority(role.getName()));
         .map(p -> new SimpleGrantedAuthority(p.getName()))
    return authorities;

8. Running and Testing the Example

We can execute the example RolesAuthoritiesApplication Java application, found in the GitHub project.

To see the role-based authorization in action, we need to:

  • Access http://localhost:8082/protectedbyrole
  • Authenticate as [email protected] (password is “user”)
  • Note successful authorization
  • Access http://localhost:8082/protectedbyauthority
  • Note unsuccessful authorization

To see authority-based authorization in action, we need to log out of the application and then:

  • Access http://localhost:8082/protectedbyauthority
  • Authenticate as [email protected] / admin
  • Note successful authorization
  • Access http://localhsot:8082/protectedbyrole
  • Note unsuccessful authorization

9. Conclusion

In this quick tutorial, we looked at the subtle but significant difference between a Role and a GrantedAuthority in Spring Security.

Security bottom

I just announced the new Learn Spring Security course, including the full material focused on the new OAuth2 stack in Spring Security 5:

Security footer banner
Comments are closed on this article!