
Baeldung Pro comes with both absolutely No-Ads as well as finally with Dark Mode, for a clean learning experience:
Once the early-adopter seats are all used, the price will go up and stay at $33/year.
Last updated: March 26, 2025
In this tutorial, we introduce AuthenticationManagerResolver and then show how to use it for Basic and OAuth2 authentication flows.
Simply put, the AuthenticationManager is the main strategy interface for authentication.
If the principal of the input authentication is valid and verified, AuthenticationManager#authenticate returns an Authentication instance with the authenticated flag set to true. Otherwise, if the principal is not valid, it will throw an AuthenticationException. For the last case, it returns null if it can’t decide.
ProviderManager is the default implementation of AuthenticationManager. It delegates the authentication process to a list of AuthenticationProvider instances.
We can set up global or local AuthenticationManager if we create a SecurityFilterChain bean. For a local AuthenticationManager, we could create an AuthenticationManager bean, accessing AuthenticationManagerBuilder through HttpSecurity.
AuthenticationManagerBuilder is a helper class that eases the set up of UserDetailService, AuthenticationProvider, and other dependencies to build an AuthenticationManager.
For a global AuthenticationManager, we should define an AuthenticationManager as a bean.
AuthenticationManagerResolver lets Spring select an AuthenticationManager per context. It’s a new feature added to Spring Security in version 5.2.0:
public interface AuthenticationManagerResolver<C> {
AuthenticationManager resolve(C context);
}
AuthenticationManagerResolver#resolve can return an instance of AuthenticationManager based on a generic context. In other words, we can set a class as the context if we want to resolve the AuthenticationManager according to it.
Spring Security has integrated the AuthenticationManagerResolver in the authentication flow with HttpServletRequest and ServerWebExchange as the context.
Let’s see how to use AuthenticationManagerResolver in practice.
For example, assume a system that has two groups of users: employees and customers. These two groups have specific authentication logic and have separate datastores. Moreover, users in either of these groups are only allowed to call their related URLs.
We can use AuthenticationManagerResolver wherever we need to choose an AuthenticationManager dynamically, but in this tutorial, we’re interested in using it in built-in authentication flows.
First, let’s set up an AuthenticationManagerResolver, then use it for Basic and OAuth2 authentications.
Let’s start by creating a class for security configuration.
@Configuration
public class CustomWebSecurityConfigurer {
// ...
}
Then, let’s add a method that returns the AuthenticationManager for customers:
AuthenticationManager customersAuthenticationManager() {
return authentication -> {
if (isCustomer(authentication)) {
return new UsernamePasswordAuthenticationToken(/*credentials*/);
}
throw new UsernameNotFoundException(/*principal name*/);
};
}
The AuthenticationManager for employees is logically the same, only we replace isCustomer with isEmployee:
public AuthenticationManager employeesAuthenticationManager() {
return authentication -> {
if (isEmployee(authentication)) {
return new UsernamePasswordAuthenticationToken(/*credentials*/);
}
throw new UsernameNotFoundException(/*principal name*/);
};
}
Finally, let’s add an AuthenticationManagerResolver that resolves according to the URL of request:
AuthenticationManagerResolver<HttpServletRequest> resolver() {
return request -> {
if (request.getPathInfo().startsWith("/employee")) {
return employeesAuthenticationManager();
}
return customersAuthenticationManager();
};
}
We can use AuthenticationFilter to dynamically resolve the AuthenticationManager per request. AuthenticationFilter was added to Spring Security in version 5.2.
If we add it to our security filter chain, then for every matched request, it first checks if it can extract any authentication object or not. If yes, then it asks the AuthenticationManagerResolver for a suitable AuthenticationManager and continues the flow.
First, let’s add a method in our CustomWebSecurityConfigurer to create an AuthenticationFilter:
private AuthenticationFilter authenticationFilter() {
AuthenticationFilter filter = new AuthenticationFilter(
resolver(), authenticationConverter());
filter.setSuccessHandler((request, response, auth) -> {});
return filter;
}
The reason for setting the AuthenticationFilter#successHandler with a no-op SuccessHandler is to prevent the default behavior of redirection after successful authentication.
Then, we can add this filter to our security filter chain by creating a SecurityFilterChain bean in our CustomWebSecurityConfigurer:
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.addFilterBefore(authenticationFilter(), BasicAuthenticationFilter.class);
return http.build();
}
BearerTokenAuthenticationFilter is responsible for OAuth2 authentication. The BearerTokenAuthenticationFilter#doFilterInternal method checks for a BearerTokenAuthenticationToken in the request, and if it’s available, then it resolves the appropriate AuthenticationManager to authenticate the token.
OAuth2ResourceServerConfigurer is used to set up BearerTokenAuthenticationFilter.
So, we can set up AuthenticationManagerResolver for our resource server in our CustomWebSecurityConfigurer by creating a SecurityFilterChain bean:
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.oauth2ResourceServer()
.authenticationManagerResolver(resolver());
return http.build();
}
For a reactive web application, we still can benefit from the concept of resolving AuthenticationManager according to the context. But here we have ReactiveAuthenticationManagerResolver instead:
@FunctionalInterface
public interface ReactiveAuthenticationManagerResolver<C> {
Mono<ReactiveAuthenticationManager> resolve(C context);
}
It returns a Mono of ReactiveAuthenticationManager. ReactiveAuthenticationManager is the reactive equivalent to AuthenticationManager, hence its authenticate method returns Mono.
Let’s start by creating a class for security configuration:
@EnableWebFluxSecurity
@EnableReactiveMethodSecurity
public class CustomWebSecurityConfig {
// ...
}
Next, let’s define ReactiveAuthenticationManager for customers in this class:
ReactiveAuthenticationManager customersAuthenticationManager() {
return authentication -> customer(authentication)
.switchIfEmpty(Mono.error(new UsernameNotFoundException(/*principal name*/)))
.map(b -> new UsernamePasswordAuthenticationToken(/*credentials*/));
}
And after that, we’ll define ReactiveAuthenticationManager for employees:
public ReactiveAuthenticationManager employeesAuthenticationManager() {
return authentication -> employee(authentication)
.switchIfEmpty(Mono.error(new UsernameNotFoundException(/*principal name*/)))
.map(b -> new UsernamePasswordAuthenticationToken(/*credentials*/));
}
Lastly, we set up a ReactiveAuthenticationManagerResolver based on our scenario:
ReactiveAuthenticationManagerResolver<ServerWebExchange> resolver() {
return exchange -> {
if (match(exchange.getRequest(), "/employee")) {
return Mono.just(employeesAuthenticationManager());
}
return Mono.just(customersAuthenticationManager());
};
}
In a reactive web application, we can use AuthenticationWebFilter for authentication. It authenticates the request and fills the security context.
AuthenticationWebFilter first checks if the request matches. After that, if there’s an authentication object in the request, it gets the suitable ReactiveAuthenticationManager for the request from ReactiveAuthenticationManagerResolver and continues the authentication flow.
Hence, we can set up our customized AuthenticationWebFilter in our security configuration:
@Bean
public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
return http
.csrf(csrfSpec -> csrfSpec.disable())
.authorizeExchange(auth -> auth.pathMatchers(HttpMethod.GET,"/**")
.authenticated())
.httpBasic(httpBasicSpec -> httpBasicSpec.disable())
.addFilterAfter(authenticationWebFilter(), SecurityWebFiltersOrder.REACTOR_CONTEXT)
.build();
}
First, we disable ServerHttpSecurity#httpBasic to prevent the normal authentication flow, then manually replace it with an AuthenticationWebFilter, passing in our custom resolver.
We can configure the ReactiveAuthenticationManagerResolver with ServerHttpSecurity#oauth2ResourceServer. ServerHttpSecurity#build adds an instance of AuthenticationWebFilter with our resolver to the chain of security filters.
So, let’s set our AuthenticationManagerResolver for OAuth2 authentication filter in our security configuration:
@Bean
public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
return http
// ...
.and()
.oauth2ResourceServer()
.authenticationManagerResolver(resolver())
.and()
// ...;
}
In this article, we’ve used AuthenticationManagerResolver for Basic and OAuth2 authentications within a simple scenario.
And, we’ve also explored the usage of ReactiveAuthenticationManagerResolver in reactive Spring web applications for both Basic and OAuth2 authentications.