Summary

i am having a problem with a circular dependency error. it is thrown when i define a UserDetailsService bean in my securityConfig class, however if i define that same bean in my authenticationConfig class,the error is gone and i dont get why.

Actual Behavior

this is the log: Exception: org.springframework.beans.factory.UnsatisfiedDependencyException. Message: Error creating bean with name 'securityConfig': Unsatisfied dependency expressed through field 'initialAuthenticationFilter': Error creating bean with name 'initialAuthenticationFilter': Unsatisfied dependency expressed through field 'manager': Error creating bean with name 'authManager' defined in class path resource [root/AuthenticationConfig.class]: Unsatisfied dependency expressed through method 'authManager' parameter 0: Error creating bean with name 'org.springframework.security.config.annotation.web.configuration.HttpSecurityConfiguration.httpSecurity' defined in class path resource [org/springframework/security/config/annotation/web/configuration/HttpSecurityConfiguration.class]: Failed to instantiate [org.springframework.security.config.annotation.web.builders.HttpSecurity]: Factory method 'httpSecurity' threw exception with message: Error creating bean with name 'securityConfig': Requested bean is currently in creation: Is there an unresolvable circular reference? and then this diagram:

The dependencies of some of the beans in the application context form a cycle: ┌─────┐ | securityConfig (field private root.filters.InitialAuthenticationFilter root.SecurityConfig.initialAuthenticationFilter) ↑ ↓ | initialAuthenticationFilter (field private org.springframework.security.authentication.AuthenticationManager root.filters.InitialAuthenticationFilter.manager) ↑ ↓ | authManager defined in class path resource [root/AuthenticationConfig.class] ↑ ↓ | org.springframework.security.config.annotation.web.configuration.HttpSecurityConfiguration.httpSecurity defined in class path resource [org/springframework/security/config/annotation/web/configuration/HttpSecurityConfiguration.class] └─────┘

Expected Behavior

If i move the bean definition to any other class, it works, but when defined in securityConfig it doesnt, and i cannot find the circular dependency that spring is telling me about

Configuration

Version

Spring boot version 3.0.5 Spring security core 6.0.2

Sample

https://github.com/santinozanone/SpringHttpSecurityCircularDependency.git

Comment From: rwinch

The issue you are experiencing is because SecurityConfig relies on InitialAuthenticationFilter and InitialAuthenticationFilter needs an AuthenticationManager which in turn needs the UserDetailsService defined in the SecurityConfig.

You can fix this a number of ways, but the easiest is by removing the member variables for SecurityConfig and instead passing them as parameters to the Bean that needs them.

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http, 
           JwtAuthenticationFilter jwtAuthenticationFilter, 
           InitialAuthenticationFilter initialAuthenticationFilter) throws Exception {

    return http.csrf().disable().httpBasic().and()
            .addFilterBefore(initialAuthenticationFilter, BasicAuthenticationFilter.class)
            .addFilterAfter(jwtAuthenticationFilter, BasicAuthenticationFilter.class).authorizeHttpRequests()
            .requestMatchers("/actuator/**").permitAll().
            and().authorizeHttpRequests().anyRequest().authenticated()
            .and().build();
}

This makes the object graph a lot cleaner. When the SecurityConfig uses member variables, any non-static method might use the member variable during initialization and thus the member variables must be initialized before any non-static method (bean declaration) is invoked. If the dependency is injected via the method, then Spring knows precisely which beans depend on what.

As an aside, the InitialAuthenticationFilter and JwtAuthenticationFilter are registered twice. The first is directly into HttpSecurity and the second is because Spring Boot registers all Filters automatically. Either make it so that your security Filters are not Beans or explicitly disable them in Spring Boot

Comment From: santinozanone

thank you for taking the time to answer, i fixed the filters being registered twice, but could you explain why the AuthenticationManager needs the UserDetailsService?, is it because the InitializeUserDetailsManagerConfigurer tries to get an UserDetailsService bean?. and where could i read more about the member variables initialization. again, thank you.

Comment From: rwinch

If you do not create an AuthenticationManager Spring Security will look for a UserDetailsService and create an AuthenticationManager from the UserDetailsService.

I haven't found any good documentation around member variable documentation, so I created https://github.com/spring-projects/spring-framework/issues/30333 to add some documentation. The takeaway is that you should prefer using arguments to methods defining the bean over using constructor or member variables of the Configuration itself.

Comment From: santinozanone

thanks you, i will check it out .