This version is still in development and is not considered stable yet. For the latest stable version, please use Spring Security 6.5.3!spring-doc.cn

Reactive X.509 Authentication

Similar to Servlet X.509 authentication, the reactive x509 authentication filter allows extracting an authentication token from a certificate provided by a client.spring-doc.cn

The following example shows a reactive x509 security configuration:spring-doc.cn

@Bean
SecurityWebFilterChain springSecurity(ServerHttpSecurity http) {
	http
		.x509(Customizer.withDefaults())
		.authorizeExchange((authorize) -> authorize
			.anyExchange().authenticated()
		);
	return http.build();
}
@Bean
fun securityWebFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
    return http {
        x509 { }
        authorizeExchange {
            authorize(anyExchange, authenticated)
        }
    }
}

In the preceding configuration, when neither principalExtractor nor authenticationManager is provided, defaults are used. The default principal extractor is SubjectX500PrincipalExtractor, which extracts the CN (common name) field from a certificate provided by a client. The default authentication manager is ReactivePreAuthenticatedAuthenticationManager, which performs user account validation, checking that a user account with a name extracted by principalExtractor exists and that it is not locked, disabled, or expired.spring-doc.cn

The following example demonstrates how these defaults can be overridden:spring-doc.cn

@Bean
SecurityWebFilterChain springSecurity(ServerHttpSecurity http) {
	SubjectX500PrincipalExtractor principalExtractor = new SubjectX500PrincipalExtractor();
	principalExtractor.setExtractPrincipalNameFromEmail(true);

	UserDetails user = User
		.withUsername("luke@monkeymachine")
		.password("password")
		.roles("USER")
		.build();

	ReactiveUserDetailsService users = new MapReactiveUserDetailsService(user);
	ReactiveAuthenticationManager authenticationManager = new ReactivePreAuthenticatedAuthenticationManager(users);

	http
		.x509((x509) -> x509
			.principalExtractor(principalExtractor)
			.authenticationManager(authenticationManager)
		)
		.authorizeExchange((authorize) -> authorize
			.anyExchange().authenticated()
		);
	return http.build();
}
@Bean
fun securityWebFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
    val extractor = SubjectX500PrincipalExtractor()
    extractor.setExtractPrincipalNameFromEmail(true)

    val user = User
        .withUsername("luke@monkeymachine")
        .password("password")
        .roles("USER")
        .build()

    val users: ReactiveUserDetailsService = MapReactiveUserDetailsService(user)
    val authentication: ReactiveAuthenticationManager = ReactivePreAuthenticatedAuthenticationManager(users)

    return http {
        x509 {
            principalExtractor = extractor
            authenticationManager = authentication
        }
        authorizeExchange {
            authorize(anyExchange, authenticated)
        }
    }
}

In the previous example, a username is extracted from the emailAddress field of a client certificate instead of CN, and account lookup uses a custom ReactiveAuthenticationManager instance.spring-doc.cn

For an example of configuring Netty and WebClient or curl command-line tool to use mutual TLS and enable X.509 authentication, see github.com/spring-projects/spring-security-samples/tree/main/servlet/java-configuration/authentication/x509.spring-doc.cn