General support for Java configuration was added to Spring Framework in Spring 3.1. Spring Security 3.2 introduced Java configuration to let users configure Spring Security without the use of any XML.

If you are familiar with the Security Namespace Configuration , you should find quite a few similarities between it and Spring Security Java configuration.

The first step is to create our Spring Security Java Configuration. The configuration creates a Servlet Filter known as the springSecurityFilterChain , which is responsible for all the security (protecting the application URLs, validating submitted username and passwords, redirecting to the log in form, and so on) within your application. The following example shows the most basic example of a Spring Security Java Configuration:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.*;
import org.springframework.security.config.annotation.authentication.builders.*;
import org.springframework.security.config.annotation.web.configuration.*;
@Configuration
@EnableWebSecurity
public class WebSecurityConfig {
	@Bean
	public UserDetailsService userDetailsService() {
		InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
		manager.createUser(User.withDefaultPasswordEncoder().username("user").password("password").roles("USER").build());
		return manager;

This configuration is not complex or extensive, but it does a lot:

Let the user with a Username of user and a Password of password authenticate with form based authentication

Let the user logout

CSRF attack prevention

Session Fixation protection

Security Header integration:

HTTP Strict Transport Security for secure requests

X-Content-Type-Options integration

Cache Control (which you can override later in your application to allow caching of your static resources)

X-XSS-Protection integration

X-Frame-Options integration to help prevent Clickjacking

AbstractSecurityWebApplicationInitializer

The next step is to register the springSecurityFilterChain with the WAR file. You can do so in Java configuration with Spring’s WebApplicationInitializer support in a Servlet 3.0+ environment. Not surprisingly, Spring Security provides a base class (AbstractSecurityWebApplicationInitializer) to ensure that the springSecurityFilterChain gets registered for you. The way in which we use AbstractSecurityWebApplicationInitializer differs depending on if we are already using Spring or if Spring Security is the only Spring component in our application.

AbstractSecurityWebApplicationInitializer without Existing Spring - Use these instructions if you are not already using Spring

AbstractSecurityWebApplicationInitializer with Spring MVC - Use these instructions if you are already using Spring

import org.springframework.security.web.context.*;
public class SecurityWebApplicationInitializer
	extends AbstractSecurityWebApplicationInitializer {
	public SecurityWebApplicationInitializer() {
		super(WebSecurityConfig.class);

The SecurityWebApplicationInitializer:

Automatically registers the springSecurityFilterChain Filter for every URL in your application.

Add a ContextLoaderListener that loads the WebSecurityConfig.

AbstractSecurityWebApplicationInitializer with Spring MVC

If we use Spring elsewhere in our application, we probably already have a WebApplicationInitializer that is loading our Spring Configuration. If we use the previous configuration, we would get an error. Instead, we should register Spring Security with the existing ApplicationContext. For example, if we use Spring MVC, our SecurityWebApplicationInitializer could look something like the following:

import org.springframework.security.web.context.*;
public class SecurityWebApplicationInitializer
	extends AbstractSecurityWebApplicationInitializer {

This onlys register the springSecurityFilterChain for every URL in your application. After that, we need to ensure that WebSecurityConfig was loaded in our existing ApplicationInitializer. For example, if we use Spring MVC it is added in the getServletConfigClasses():

public class MvcWebApplicationInitializer extends
		AbstractAnnotationConfigDispatcherServletInitializer {
	@Override
	protected Class<?>[] getServletConfigClasses() {
		return new Class[] { WebSecurityConfig.class, WebMvcConfig.class };
	// ... other overrides ...

The reason for this is that Spring Security needs to be able to inspect some Spring MVC configuration in order to appropriately configure underlying request matchers, so they need to be in the same application context. Placing Spring Security in getRootConfigClasses places it into a parent application context that may not be able to find Spring MVC’s HandlerMappingIntrospector.

Configuring for Multiple Spring MVC Dispatchers

If desired, any Spring Security configuration that is unrelated to Spring MVC may be placed in a different configuration class like so:

public class MvcWebApplicationInitializer extends
		AbstractAnnotationConfigDispatcherServletInitializer {
	@Override
    protected Class<?>[] getRootConfigClasses() {
		return new Class[] { NonWebSecurityConfig.class };
	@Override
	protected Class<?>[] getServletConfigClasses() {
		return new Class[] { WebSecurityConfig.class, WebMvcConfig.class };
	// ... other overrides ...

This can be helpful if you have multiple instances of AbstractAnnotationConfigDispatcherServletInitializer and don’t want to duplicate the general security configuration across both of them.

Thus far, our WebSecurityConfig contains only information about how to authenticate our users. How does Spring Security know that we want to require all users to be authenticated? How does Spring Security know we want to support form-based authentication? Actually, there is a configuration class (called SecurityFilterChain) that is being invoked behind the scenes. It is configured with the following default implementation:

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
		.authorizeRequests(authorize -> authorize
			.anyRequest().authenticated()
		.formLogin(withDefaults())
		.httpBasic(withDefaults());
	return http.build();

The default configuration (shown in the preceding example):

We can configure multiple HttpSecurity instances just as we can have multiple <http> blocks in XML. The key is to register multiple SecurityFilterChain @Beans. The following example has a different configuration for URL’s that start with /api/.

@Configuration
@EnableWebSecurity
public class MultiHttpSecurityConfig {
	@Bean                                                             (1)
	public UserDetailsService userDetailsService() throws Exception {
		// ensure the passwords are encoded properly
		UserBuilder users = User.withDefaultPasswordEncoder();
		InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
		manager.createUser(users.username("user").password("password").roles("USER").build());
		manager.createUser(users.username("admin").password("password").roles("USER","ADMIN").build());
		return manager;
	@Bean
	@Order(1)                                                        (2)
	public SecurityFilterChain apiFilterChain(HttpSecurity http) throws Exception {
			.securityMatcher("/api/**")                                   (3)
			.authorizeHttpRequests(authorize -> authorize
				.anyRequest().hasRole("ADMIN")
			.httpBasic(withDefaults());
		return http.build();
	@Bean                                                            (4)
	public SecurityFilterChain formLoginFilterChain(HttpSecurity http) throws Exception {
			.authorizeHttpRequests(authorize -> authorize
				.anyRequest().authenticated()
			.formLogin(withDefaults());
		return http.build();
Create an instance of SecurityFilterChain that contains @Order to specify which SecurityFilterChain should be considered first.
The http.securityMatcher states that this HttpSecurity is applicable only to URLs that start with /api/.
Create another instance of SecurityFilterChain.
If the URL does not start with /api/, this configuration is used.
This configuration is considered after apiFilterChain, since it has an @Order value after 1 (no @Order defaults to last).
public class MyCustomDsl extends AbstractHttpConfigurer<MyCustomDsl, HttpSecurity> {
	private boolean flag;
	@Override
	public void init(HttpSecurity http) throws Exception {
		// any method that adds another configurer
		// must be done in the init method
		http.csrf().disable();
	@Override
	public void configure(HttpSecurity http) throws Exception {
		ApplicationContext context = http.getSharedObject(ApplicationContext.class);
		// here we lookup from the ApplicationContext. You can also just create a new instance.
		MyFilter myFilter = context.getBean(MyFilter.class);
		myFilter.setFlag(flag);
		http.addFilterBefore(myFilter, UsernamePasswordAuthenticationFilter.class);
	public MyCustomDsl flag(boolean value) {
		this.flag = value;
		return this;
	public static MyCustomDsl customDsl() {
		return new MyCustomDsl();
class MyCustomDsl : AbstractHttpConfigurer<MyCustomDsl, HttpSecurity>() {
    var flag: Boolean = false
    override fun init(http: HttpSecurity) {
        // any method that adds another configurer
        // must be done in the init method
        http.csrf().disable()
    override fun configure(http: HttpSecurity) {
        val context: ApplicationContext = http.getSharedObject(ApplicationContext::class.java)
        // here we lookup from the ApplicationContext. You can also just create a new instance.
        val myFilter: MyFilter = context.getBean(MyFilter::class.java)
        myFilter.setFlag(flag)
        http.addFilterBefore(myFilter, UsernamePasswordAuthenticationFilter::class.java)
    companion object {
        @JvmStatic
        fun customDsl(): MyCustomDsl {
            return MyCustomDsl()
public class Config {
	@Bean
	public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
			.with(MyCustomDsl.customDsl(), (dsl) -> dsl
				.flag(true)
			// ...
		return http.build();
    fun filterChain(http: HttpSecurity): SecurityFilterChain {
            .with(MyCustomDsl.customDsl()) {
                flag = true
            // ...
        return http.build()

If you want, you can have HttpSecurity add MyCustomDsl by default by using SpringFactories. For example, you can create a resource on the classpath named META-INF/spring.factories with the following contents:

META-INF/spring.factories
org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer = sample.MyCustomDsl

You can also explicit disable the default:

public class Config { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { .with(MyCustomDsl.customDsl(), (dsl) -> dsl .disable() return http.build(); fun filterChain(http: HttpSecurity): SecurityFilterChain { .with(MyCustomDsl.customDsl()) { disable() // ... return http.build()

Spring Security’s Java configuration does not expose every property of every object that it configures. This simplifies the configuration for a majority of users. After all, if every property were exposed, users could use standard bean configuration.

While there are good reasons to not directly expose every property, users may still need more advanced configuration options. To address this issue, Spring Security introduces the concept of an ObjectPostProcessor, which can be used to modify or replace many of the Object instances created by the Java Configuration. For example, to configure the filterSecurityPublishAuthorizationSuccess property on FilterSecurityInterceptor, you can use the following:

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
		.authorizeRequests(authorize -> authorize
			.anyRequest().authenticated()
			.withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>() {
				public <O extends FilterSecurityInterceptor> O postProcess(
						O fsi) {
					fsi.setPublishAuthorizationSuccess(true);
					return fsi;
	return http.build();
        

© VMware, Inc. or its affiliates. Terms of UsePrivacyTrademark Guidelines Thank youYour California Privacy RightsCookie Settings

Apache®, Apache Tomcat®, Apache Kafka®, Apache Cassandra™, and Apache Geode™ are trademarks or registered trademarks of the Apache Software Foundation in the United States and/or other countries. Java™, Java™ SE, Java™ EE, and OpenJDK™ are trademarks of Oracle and/or its affiliates. Kubernetes® is a registered trademark of the Linux Foundation in the United States and other countries. Linux® is the registered trademark of Linus Torvalds in the United States and other countries. Windows® and Microsoft® Azure are registered trademarks of Microsoft Corporation. “AWS” and “Amazon Web Services” are trademarks or registered trademarks of Amazon.com Inc. or its affiliates. All other trademarks and copyrights are property of their respective owners and are only mentioned for informative purposes. Other names may be trademarks of their respective owners.