Spring Security - Reload Authorities on Every Request

I recently ran in an issue at work:

Using a role-based access control with Spring Security, how can I refresh user B’s authorities when user A modifies user B’s roles?

You’d think that this would be done automatically, but unfortunately, it isn’t. The authorities are decided upon authentication, meaning that until the user re-authenticates, his authorities won’t necessarily reflect the current access he should be having.

I searched quite a bit for an easy answer, and there were many posts who were left unanswered, or even worse, answers from XML-based Spring configuration.

Ugh, XML.

Anyhow, I ended up having to figure it out on my own: just force each users to re-authenticate every time they make a request. By using an interceptor, we can do just that! The downside is that well, obviously, if you use a database to get the roles of your users, you’ll have to query your database every time there’s a request.

Luckily for me (and unluckily for you, probably), performance was not a concern, so I could ignore the performance impact.

First, create an interceptor:

@Component
public class VerifyAccessInterceptor implements HandlerInterceptor {

    // ...

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        Authentication auth = SecurityContextHolder.getContext().getAuthentication();
        Set<GrantedAuthority> authorities = new HashSet<>();
        if (auth.isAuthenticated()) {
            authorities.add(new SimpleGrantedAuthority("ROLE_USER"));
        }

        User userFromDatabase = getUserFromDatabase(auth.getName());
        if (userFromDatabase != null) {
            // add whatever authorities you want here
            authorities.add(new SimpleGrantedAuthority("...")); 
        }

        Authentication newAuth = null;

        if (auth.getClass() == OAuth2AuthenticationToken.class) {
            OAuth2User principal = ((OAuth2AuthenticationToken)auth).getPrincipal();
            if (principal != null) {
                newAuth = new OAuth2AuthenticationToken(principal, authorities,(((OAuth2AuthenticationToken)auth).getAuthorizedClientRegistrationId()));
            }
        }

        SecurityContextHolder.getContext().setAuthentication(newAuth);
        return true;
    }

}

My specific implementation uses OAuth2 (OAuth2AuthenticationToken), but you can use UsernamePasswordAuthenticationToken instead.

And now, to add your interceptor to the configuration:

@Configuration
public class WebConfiguration extends WebMvcConfigurationSupport {

    @Autowired
    private VerifyAccessInterceptor verifyAccessInterceptor;


    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(verifyAccessInterceptor).addPathPatterns("/**");
    }

}

Obviously, this is just a very rough implementation. It works as-is, but that it shouldn’t be given a bit more love. A few enhancements can be made, such as:

  • Checking if the authorities changed before updating the Authentication object
  • Applying the filter to only specific paths rather than all paths