I am confused at what is causing this error, I first started noticing this when I migrated from version 1.2 to 1.4 of the spring oauth2 authorization server. Below you will find relevant files to help debug the issue.
Error output when trying to run ./gradlw bootRun. It fails to build
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'authorizationServerSecurityFilterChain' defined in class path resource [com/something/auth_service/configuration/OAuth2SecurityConfig.class]: Failed to instantiate [org.springframework.security.web.SecurityFilterChain]: Factory method 'authorizationServerSecurityFilterChain' threw exception with message: org/springframework/security/web/authentication/DelegatingAuthenticationConverter
When I tried using the spring-boot-starter-oauth2-authorization-server it used an older dependency spring-security-oauth2-authorization-server:1.2.1 instead of 1.4.1. Not sure why that was happening but just decided to explicitly specify the dependencies.
Build.Gradle
plugins {
id 'java'
id 'org.springframework.boot' version '3.2.0'
id 'io.spring.dependency-management' version '1.1.4'
id 'application'
}
group = 'com.something'
version = '0.0.1-SNAPSHOT'
application {
mainClass = 'com.something.auth_service.AuthApplication'
}
java {
sourceCompatibility = '17'
}
configurations {
compileOnly {
extendsFrom annotationProcessor
}
all {
exclude group: 'commons-logging', module: 'commons-logging'
}
}
repositories {
mavenCentral()
}
bootRun {
args = ["--spring.profiles.active=dev"]
}
bootTestRun {
args = ["--spring.profiles.active=dev"]
}
dependencies {
implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.18.0'
implementation 'software.amazon.awssdk:ses:2.28.20'
implementation 'software.amazon.awssdk:sdk-core:2.28.20'
implementation 'software.amazon.awssdk:auth:2.28.20'
implementation 'software.amazon.awssdk:s3:2.28.20'
implementation 'software.amazon.awssdk:regions:2.28.20'
implementation 'software.amazon.awssdk:utils:2.28.20'
implementation 'software.amazon.awssdk:services:2.28.20'
implementation 'software.amazon.awssdk:aws-core:2.28.20'
implementation 'jakarta.mail:jakarta.mail-api:2.1.3'
implementation 'software.amazon.awssdk:sesv2:2.28.20'
implementation 'software.amazon.awssdk:auth:2.28.20'
implementation 'org.springframework.boot:spring-boot-starter-data-mongodb'
implementation 'org.springframework.boot:spring-boot-starter-security:3.4.1'
implementation 'org.springframework.boot:spring-boot-starter-web:3.4.1'
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
implementation 'redis.clients:jedis:5.1.2'
implementation 'com.sun.mail:javax.mail:1.6.0'
implementation 'javax.mail:javax.mail-api:1.6.2'
implementation 'org.hibernate.validator:hibernate-validator'
implementation 'io.jsonwebtoken:jjwt-api:0.12.3'
implementation 'org.springframework.security:spring-security-oauth2-authorization-server:1.4.1'
runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.12.3'
runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.12.3'
implementation 'javax.servlet:servlet-api:2.5'
implementation 'jakarta.annotation:jakarta.annotation-api:2.1.1'
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.springframework.security:spring-security-test'
}
tasks.named('test') {
useJUnitPlatform()
}
This is my Spring Authorization Server configuration, which includes login settings. I successfully got the login routes working and tested the client registration. However, everything started breaking after upgrading to the latest version of Spring Authorization Server.
OAuth2 Security Config
package com.something.auth_service.configuration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.DelegatingPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
import org.springframework.security.oauth2.server.authorization.config.annotation.web.configuration.OAuth2AuthorizationServerConfiguration;
import org.springframework.security.oauth2.server.authorization.config.annotation.web.configurers.OAuth2AuthorizationServerConfigurer;
import org.springframework.security.oauth2.server.authorization.settings.AuthorizationServerSettings;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
import org.springframework.security.web.util.matcher.MediaTypeRequestMatcher;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.security.interfaces.RSAPublicKey;
import java.security.interfaces.RSAPrivateKey;
import java.security.KeyPairGenerator;
import com.something.auth_service.configuration.user.CustomUserDetailsService;
import com.something.auth_service.configuration.user.UsernamePasswordAuthenticationProvider;
import com.something.auth_service.repository.UserRepository;
import com.nimbusds.jose.jwk.JWKSet;
import com.nimbusds.jose.jwk.RSAKey;
import com.nimbusds.jose.jwk.source.ImmutableJWKSet;
import com.nimbusds.jose.jwk.source.JWKSource;
import org.springframework.security.oauth2.jwt.JwtDecoder;
import com.nimbusds.jose.proc.SecurityContext;
import jakarta.servlet.http.HttpServletResponse;
import java.security.KeyPair;
@Order(Ordered.HIGHEST_PRECEDENCE)
@Configuration
public class OAuth2SecurityConfig {
@Bean
CustomUserDetailsService userDetailsService(UserRepository userRepository) {
return new CustomUserDetailsService(userRepository);
}
@Bean
public PasswordEncoder customPasswordEncoder() {
String idForEncode = "bcrypt";
Map<String,PasswordEncoder> encoders = new HashMap<>();
encoders.put(idForEncode, new BCryptPasswordEncoder());
return new DelegatingPasswordEncoder("bcrypt", encoders);
}
@Bean
public AuthenticationManager authenticationManager(
CustomUserDetailsService userDetailsService, PasswordEncoder sharedPasswordEncoder) {
UsernamePasswordAuthenticationProvider authenticationProvider = new UsernamePasswordAuthenticationProvider(userDetailsService, sharedPasswordEncoder);
return new ProviderManager(authenticationProvider);
}
@Bean
SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http,RegisteredClientRepository registeredClientRepository,
AuthorizationServerSettings authorizationServerSettings) throws Exception {
OAuth2AuthorizationServerConfigurer authorizationServerConfigurer =
OAuth2AuthorizationServerConfigurer.authorizationServer();
// Failed below here.
http
.securityMatcher(authorizationServerConfigurer.getEndpointsMatcher())
.with(authorizationServerConfigurer, (authorizationServer) ->
authorizationServer
.oidc((oidc) ->
oidc.clientRegistrationEndpoint((clientRegistrationEndpoint) -> oidc.clientRegistrationEndpoint(Customizer.withDefaults())
)
)
)
.cors(cors -> cors.disable())
.csrf(csrf -> csrf.disable())
.authorizeHttpRequests((authorize) ->
authorize
.requestMatchers(HttpMethod.OPTIONS, "/**").permitAll()
.requestMatchers("/create-account").permitAll()
.requestMatchers("/error").permitAll()
.requestMatchers("/oauth2/authorize").permitAll()
.requestMatchers("/login").permitAll()
.anyRequest().authenticated()
)
.formLogin(formLogin -> {
formLogin.loginPage("/login");
formLogin.usernameParameter("emailOrUsername");
formLogin.passwordParameter("password");
formLogin.successHandler((request, response, authentication) -> {
System.out.println("Login Succeeded.");
response.setStatus(HttpServletResponse.SC_OK);
response.getWriter().write("Login successful!");
response.getWriter().flush();
});
})
.logout(logout -> {
logout.logoutUrl("http://localhost:8082/logout");
logout.logoutSuccessUrl("http://localhost:8082/login");
logout.invalidateHttpSession(true);
logout.clearAuthentication(true);
logout.deleteCookies("JSESSIONID");
logout.logoutSuccessHandler((request, response, authentication) -> {
System.out.println("Logout Succeeded.");
response.setStatus(HttpServletResponse.SC_OK);
response.getWriter().write("Logout successful for "+request.getSession().getId());
response.getWriter().flush();
});
})
.oauth2ResourceServer(oauth2ResourceServer -> oauth2ResourceServer.jwt(Customizer.withDefaults()))
.exceptionHandling((exceptions) -> {
exceptions.accessDeniedHandler((request, response, accessDeniedException) -> {
request.getSession().invalidate();
System.out.println("Login Failed, Access Denied.");
response.setStatus(HttpServletResponse.SC_OK);
response.getWriter().write("Login Failed, Access Denied.");
response.getWriter().flush();
});
exceptions.defaultAuthenticationEntryPointFor(
new LoginUrlAuthenticationEntryPoint("http://localhost:8082"),
new MediaTypeRequestMatcher(MediaType.TEXT_HTML)
);
}
);
return http.build();
}
private static KeyPair generateRsaKey() {
KeyPair keyPair;
try {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(2048);
keyPair = keyPairGenerator.generateKeyPair();
} catch (Exception ex) {
throw new IllegalStateException(ex);
}
return keyPair;
}
@Bean
JWKSource<SecurityContext> jwkSource() {
KeyPair keyPair = generateRsaKey();
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
RSAKey rsaKey = new RSAKey.Builder(publicKey)
.privateKey(privateKey)
.keyID(UUID.randomUUID().toString())
.build();
JWKSet jwkSet = new JWKSet(rsaKey);
return new ImmutableJWKSet<>(jwkSet);
}
@Bean
JwtDecoder jwtDecoder(JWKSource<SecurityContext> jwkSource) {
return OAuth2AuthorizationServerConfiguration.jwtDecoder(jwkSource);
}
@Bean
AuthorizationServerSettings authorizationServerSettings() {
return AuthorizationServerSettings.builder().build();
}
}
It seems like you're mixing Spring Boot 3.2.0 and 3.4.1. After bumping Spring Boot plugin to 3.4.1, you may let deps follow versions in plugin by removing :3.4.1.
You might consider using org.springframework.boot:spring-boot-starter-oauth2-authorization-server
instead of spring-security-oauth2-authorization-server
.