Exploring Spring Security's Authentication Mechanism in Web Applications


In this blog post, we’ll take a deep dive into Spring Security’s authentication mechanism and how it integrates with Spring Web MVC. Using a JWT as an example, we will explore the main classes in the Spring Security authentication mechanism and how they work together.

Spring Security and Spring Web MVC - General Architecture

Spring Security is an authentication and authorization framework for securing Spring-based applications. Because of its integration with Spring Web MVC, this is also true for web applications.
In this section, I want to describe how these two Spring projects are integrated with each other. This picture shows the integration of Spring Web MVC and Spring Security

The first component we are interested in right now is the DelegatingFilterProxy of Spring Web MVC. It is a servlet filter as described in the Jakarta servlet specification. In general, these filters are responsible for performing filtering tasks on either the request, the response, or both. In a Spring web application, they are called by the servlet container (Catalina) inside the web server (Tomcat). In particular, the DelegatingFilterProxy is responsible for delegating requests to the FilterChainProxy - a Spring bean, a servlet filter, and part of Spring Security. This means that DelegatingFilterProxy acts as a bridge between the servlet and the Spring world.
The FilterChainProxy itself has a list of SecurityFilterChains, to which it delegates its requests. The SecurityFilterChain is a Spring bean that is typically provided by our application. For example:

@Configuration
public class SecurityConfiguration {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        return http
            .authorizeHttpRequests(authorize -> {
                authorize.requestMatchers("/admin/**").authenticated();
                authorize.anyRequest().permitAll();
            })
            .oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt)
            .build();
    }
}

The SecurityFilterChain has a list of servlet filters, that handle security-related concerns. In this example, it will contain a BearerTokenAuthenticationFilter because of the ::oauth2ResourceServer() method.

Authentication in the Context of Spring Web MVC

With the general architecture explained, we can now take a deeper look at the authentication mechanism of Spring Security. Again, we will start with an overview of the classes involved. Diagram of the classes involved in authentication and how they are connected to each other.

This diagram shows the classes involved in authentication using a JWT as the authentication token. Before we have a look at how they work together, let us first discuss the responsibilities of these classes.

  • FilterChainProxy
    The entry point to Spring Security from Spring Web MVC. The instance of this class is managed by Spring’s Inversion of Control (IoC) container. It contains a list of SecurityFilterChains to which it delegates its requests.
  • SecurityFilterChain
    Contains a RequestMatcher and a list of Jakarta Servlet filters. The RequestMatcher is used by the FilterChainProxy to determine whether a SecurityFilterChain is responsible for a request or not. If it is, its filters are invoked.
  • BearerTokenAuthenticationFilter
    Extracts an Authentication object (in this particular case, a BearerTokenAuthenticationToken) from the information given in a request, passes it to its AuthenticationManager, and handles the result by setting a SecurityContext.
  • BearerTokenAuthenticationToken
    Contains the bearer token from the request that was extracted by the BearerTokenAuthenticationFilter.
  • Authentication
    Holds the information used to authenticate a user. If the authentication was successful, an Authentication object is stored in the SecurityContext.
  • AuthenticationManager
    Handles the actual authentication request.
  • ProviderManager
    Is the default implementation of the AuthenticationManager. It holds a list of AuthenticationProviders.
  • AuthenticationProvider
    Handles the actual authentication.
  • JwtAuthenticationProvider
    A possible implementation of an AuthenticationProvider that supports BearerTokenAuthenticationTokens for authentication.

Now that we know the main classes and their responsibilities, let us take a closer look at their interactions with each other. Note that I left out details in this diagram to make it easier to understand. It mainly shows one path through the authentication mechanism, ignoring all loops, most logical branches, and many classes.

Diagram of the classes involved in authentication and how they interact.

As discussed earlier, the FilterChainProxy is the starting point of the authentication mechanism. It checks if a SecurityFilterChain is responsible for the current request and asks for all of its filters. After receiving the filters, it invokes each of them. The BearerTokenAuthenticationFilter in our example then extracts the JWT Bearer token from the request and passes it as a BearerTokenAuthenticationToken to the ProviderManager. The ProviderManager checks to see if any of its AuthenticationProviders can perform authentication with this information, and invokes them. In our case, the JwtAuthenticationProvider can handle the given BearerTokenAuthenticationToken and tries to decode the JWT. This object is the component, that does the actual authentication. If it is successful, it creates an AbstractAuthenticationToken and returns it all the way back to the BearerTokenAuthenticationFilter. This filter uses the Authentication object to create a new SecurityContext. If the authentication fails, an exception is thrown by the JwtAuthenticationProvider and caught and handled by the BearerTokenAuthenticationFilter.

Conclusion

As I worked my way through the code to understand Spring’s authentication mechanism, I first thought it was horribly complicated. But by abstracting away some of the details, I was finally able to understand the intent of the code. The official documentation describes Spring Security as follows:

Spring Security is a powerful and highly customizable authentication and access-control framework.

One of the main goals of Spring Security is to be highly customizable to support a wide range of different authorization processes. The JWT handling classes we used in this example are part of spring-security-oauth2-resource-server - an additional module within Spring Security. By extending a few classes, the authors were able to plug this functionality directly into the framework. All thanks to the seemingly complicated architecture of the project.