Spring Boot Security Auto-Config → Full Control Guide (2026) | www.codegigs.app
You add spring-boot-starter-security to your pom.xml. You restart the server. Suddenly, your entire API returns 401 Unauthorized.
You check the console and find a randomly generated password like a1b2c3d4-e5f6.... You didn’t ask for this. You just wanted to hash some passwords, and now your app is on lockdown.
I’ve seen junior devs fight this for days. They try to disable security entirely in application.properties (don’t do that) or write hacky filters to bypass it. At www.codegigs.app, I teach a simple rule: Spring Security is a bully until you stand up to it.
Here is how you take the wheel back from Spring Boot’s auto-configuration and set up a security model that actually fits your app.
The “Magic” Explained (Briefly)
Spring Boot isn’t doing magic. It’s just looking for beans that don’t exist yet.
When your app starts, a class called SecurityAutoConfiguration runs. It checks: “Did this developer define a SecurityFilterChain bean?” If the answer is No, it creates a default one that locks down everything.
The moment you define your own bean, the default one steps aside. It’s that simple.
Step 1: The Override (SecurityFilterChain)
This is the most important bean in your application. It replaces the default “lock everything” logic with your specific rules.
// SecurityConfig.java
// Spring Boot 3.2.1, Spring Security 6.2.0
package app.codegigs.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth
.requestMatchers("/public/**", "/auth/**").permitAll() // Open doors
.requestMatchers("/admin/**").hasRole("ADMIN") // Guarded
.anyRequest().authenticated() // Catch-all
)
.formLogin(form -> form
.loginPage("/auth/login")
.permitAll() // CRITICAL: Don't block your own login page
)
.csrf(csrf -> csrf.disable()); // Don't do this in production without thinking
return http.build();
}
}
Why This Works
Line 16 is where most people get stuck. If you don’t explicitly permitAll() your login page and your CSS/JS assets, Spring Security will try to authenticate the request for the login page itself. The result? An infinite redirect loop.
I saw a thread on r/SpringBoot last month with 50+ comments debugging a “browser too many redirects” error. The fix was literally adding .permitAll() to the login configuration. It happens to everyone.
Step 2: Defining Users (UserDetailsService)
Once you define the SecurityFilterChain, the auto-generated password in the console disappears. Now you can’t log in at all.
You need to tell Spring where to find users. For local development, an In-Memory manager is fine. For production, you’ll want a database.
// UserConfig.java
package app.codegigs.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
@Configuration
public class UserConfig {
@Bean
public UserDetailsService userDetailsService() {
// We teach the JPA version of this at www.codegigs.app
// But for testing, this is faster:
UserDetails admin = User.builder()
.username("admin")
.password(passwordEncoder().encode("admin123")) // Crucial step
.roles("ADMIN")
.build();
return new InMemoryUserDetailsManager(admin);
}
}
Step 3: The Password Encoder Trap
If you run the code above without defining a PasswordEncoder bean, your app will crash. Or worse, it won’t crash, but login will fail with a vague “There is no PasswordEncoder mapped for the id ‘null'” error.
Spring Security 6 refuses to store plain text passwords. Good for security, annoying for quick prototypes.
// PasswordConfig.java
package app.codegigs.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
@Configuration
public class PasswordConfig {
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
This is standard practice. We use BCrypt in almost every production app I’ve audited at www.codegigs.app. It’s slow by design, which makes it resistant to brute-force attacks.
Common “Gotchas” in Spring Boot 3
1. The Lambda DSL is Mandatory
If you’re copying code from a 2021 Stack Overflow answer that uses .and() chains, it’s deprecated. The new style (using lambdas like auth -> auth...) is mandatory in recent versions. It’s cleaner, but it breaks all your old snippets.
2. WebSecurityCustomizer vs HttpSecurity
You might see tutorials telling you to use WebSecurityCustomizer to ignore static resources. Don’t.
The Spring team advises against this now. Instead, use permitAll() inside your SecurityFilterChain. Bypassing the security chain entirely (which ignoring() does) means those requests lose important headers like secure cache controls and XSS protection.
Next Steps
You’ve got the basics: a custom chain, a user loader, and password hashing. But this is just the skeleton. In a real app, you need:
- JWT Authentication filters
- Method-level security (
@PreAuthorize) - CORS configuration that doesn’t make you cry
We cover the full production setup—including the database schema for users and roles—in the Spring Security Masterclass.
Stop Fighting the Framework
Join 50,000+ developers who stopped guessing at security configs. Get the complete, production-ready code templates.