[[kotlin-config]] = Kotlin Configuration Spring Security Kotlin configuration has been available since Spring Security 5.3. It lets users configure Spring Security by using a native Kotlin DSL. [NOTE] ==== Spring Security provides https://github.com/spring-projects/spring-security-samples/tree/main/servlet/spring-boot/kotlin/hello-security[a sample application] to demonstrate the use of Spring Security Kotlin Configuration. ==== [[kotlin-config-httpsecurity]] == HttpSecurity 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? There is a configuration class (called `WebSecurityConfigurerAdapter`) that is being invoked behind the scenes. It has a method called `configure` with the following default implementation: ==== [source,kotlin] ---- fun configure(http: HttpSecurity) { http { authorizeRequests { authorize(anyRequest, authenticated) } formLogin { } httpBasic { } } } ---- ==== The default configuration (shown in the preceding listing): * Ensures that any request to our application requires the user to be authenticated * Lets users authenticate with form-based login * Lets users authenticate with HTTP Basic authentication Note that this configuration is parallels the XML namespace configuration: ==== [source,xml] ---- ---- ==== == Multiple HttpSecurity Instances We can configure multiple HttpSecurity instances, just as we can have multiple `` blocks. The key is to extend the `WebSecurityConfigurerAdapter` multiple times. The following example has a different configuration for URL's that start with `/api/`: ==== [source,kotlin] ---- @EnableWebSecurity class MultiHttpSecurityConfig { @Bean <1> public fun userDetailsService(): UserDetailsService { val users: User.UserBuilder = User.withDefaultPasswordEncoder() val manager = InMemoryUserDetailsManager() manager.createUser(users.username("user").password("password").roles("USER").build()) manager.createUser(users.username("admin").password("password").roles("USER","ADMIN").build()) return manager } @Configuration @Order(1) <2> class ApiWebSecurityConfigurationAdapter: WebSecurityConfigurerAdapter() { override fun configure(http: HttpSecurity) { http { securityMatcher("/api/**") <3> authorizeRequests { authorize(anyRequest, hasRole("ADMIN")) } httpBasic { } } } } @Configuration <4> class FormLoginWebSecurityConfigurerAdapter: WebSecurityConfigurerAdapter() { override fun configure(http: HttpSecurity) { http { authorizeRequests { authorize(anyRequest, authenticated) } formLogin { } } } } } ---- <1> Configure Authentication as usual. <2> Create an instance of `WebSecurityConfigurerAdapter` that contains `@Order` to specify which `WebSecurityConfigurerAdapter` should be considered first. <3> The `http.antMatcher` states that this `HttpSecurity` is applicable only to URLs that start with `/api/` <4> Create another instance of `WebSecurityConfigurerAdapter`. If the URL does not start with `/api/`, this configuration is used. This configuration is considered after `ApiWebSecurityConfigurationAdapter`, since it has an `@Order` value after `1` (no `@Order` defaults to last). ====