Spring Boot Security Auto-Configuration: Defaults and Customization
Learn Spring Boot Security auto-configuration defaults, customization, and real-world pitfalls.
20+ years shipping production Java in banking & fintech. Drawn from code that ran under real load.
- ✓Java 17+ installed
- ✓Spring Boot 3.2+ project with spring-boot-starter-security dependency
- ✓Basic understanding of Spring Boot auto-configuration (see /java/spring-boot-auto-configuration/)
• Spring Boot Security auto-configures a default security chain with HTTP Basic auth, form login, and a random password logged at startup. • You can customize security by defining a SecurityFilterChain bean or overriding properties like spring.security.user.name. • Defaults are production-hostile: no CSRF protection for APIs, no password encoding, and no proper session management. • Customization requires understanding the auto-configuration order and conditional beans like UserDetailsService and AuthenticationProvider. • Use @EnableWebSecurity to take full control and disable problematic defaults like CSRF for REST APIs.
Think of Spring Boot Security as a bouncer at a club. By default, the bouncer checks ID (HTTP Basic), lets you in, and gives you a stamp (session). But the default bouncer is lazy: he stamps everyone, doesn't check ID strength, and leaves the back door open (no CSRF for APIs). You can replace him with a strict bouncer who uses fingerprint (JWT), checks a VIP list (database), and locks the back door (custom security filter chain).
| Chrome | Firefox | Safari | Edge |
|---|---|---|---|
| ✓ | ✓ | ✓ | ✓ |
Spring Boot Security auto-configuration is a double-edged sword. It gets you started in seconds, but it's also the source of countless production incidents. I've seen teams deploy to production with the default random password because they didn't realize Spring Boot generates one at startup. I've debugged sessions that leaked because CSRF was enabled for a REST API. And I've spent hours chasing NullPointerExceptions because a custom UserDetailsService wasn't picked up due to bean ordering.
In this tutorial, we'll tear down the auto-configuration layer by layer. You'll learn what defaults Spring Boot 3.2 applies, why they exist, and when they'll burn you. We'll cover how to customize authentication, authorization, and filter chains using SecurityFilterChain beans, @EnableWebSecurity, and application.properties. We'll also dig into the Spring Security 6.2 changes: the new lambda DSL, the removal of WebSecurityConfigurerAdapter, and the default password encoder switch to DelegatingPasswordEncoder.
By the end, you'll be able to diagnose security issues in under 5 minutes, customize security for REST APIs, JWT, and OAuth2, and avoid the top 5 mistakes that lead to security vulnerabilities in production. This isn't just theory—it's battle-tested advice from running payment processing systems handling millions of requests per day.
What Auto-Configuration Provides Out of the Box
When you add spring-boot-starter-security to your Spring Boot 3.2 project, the magic begins. Spring Security's auto-configuration kicks in via SecurityAutoConfiguration and UserDetailsServiceAutoConfiguration. Here's what you get for free:
- A default SecurityFilterChain bean that secures all endpoints with HTTP Basic authentication and form login.
- A UserDetailsService that stores a single user with username 'user' and a random UUID password logged at INFO level.
- A default login page at /login and a logout page at /logout.
- CSRF protection enabled (which is a problem for REST APIs).
- Session fixation protection enabled.
- XSS protection headers enabled.
Let's see the default configuration in action. Create a simple controller and observe the auto-configured behavior.
The key takeaway: Spring Boot assumes you're building a traditional web application with server-side rendering. If you're building a REST API, these defaults will cause you pain. The random password is especially dangerous—it's generated once at startup and never changes, so if someone reads the logs, they have full access.
What the Official Docs Won't Tell You
The Spring Security reference documentation is excellent for reference, but it glosses over the real-world pain points. Here's what I've learned from years of debugging:
- Auto-configuration order matters. Spring Boot's SecurityAutoConfiguration runs after your custom beans. If you define a SecurityFilterChain bean, it replaces the default. But if you define a UserDetailsService bean, it's picked up automatically. The problem: if you have multiple UserDetailsService beans, Spring Boot picks the first one, and you might get the wrong one.
- CSRF is enabled by default. For REST APIs, this is a nightmare. Every POST/PUT/DELETE request needs a CSRF token, which breaks mobile and SPA clients. The docs mention it, but they don't emphasize that you should disable CSRF for stateless APIs.
- The default SecurityFilterChain is a single chain. You can't have different security rules for different endpoints without customizing. For example, you might want /api/public/ to be unauthenticated and /api/admin/ to require ADMIN role. The default chain applies the same rules to everything.
- Password encoding is not configured by default. Spring Boot 3.2 uses DelegatingPasswordEncoder with multiple encodings, but the default is '{bcrypt}' for new passwords. If you're migrating from an older system with plaintext passwords, you'll get errors. You need to explicitly configure a PasswordEncoder bean.
- The default login page is ugly and insecure. It's a generic HTML form that's vulnerable to brute force attacks. In production, you should use a custom login page with rate limiting or OAuth2.
Customizing Authentication: Users and Roles
The default UserDetailsService with a single user is rarely sufficient. In production, you'll need to authenticate against a database, LDAP, or OAuth2 provider. Spring Boot makes this easy with auto-configuration that picks up your UserDetailsService bean.
Let's create a custom UserDetailsService that loads users from a MySQL database using Spring Data JPA. This is the most common pattern for SaaS applications.
First, define a User entity and a UserRepository. Then implement UserDetailsService to load users by username. The key point: Spring Boot's UserDetailsServiceAutoConfiguration will detect your bean and disable the default in-memory user. This happens because the auto-configuration has @ConditionalOnMissingBean(UserDetailsService.class).
But there's a catch: if you have multiple UserDetailsService beans (e.g., one for local users and one for OAuth2), Spring Boot will pick the first one. To control which one is used, mark your primary bean with @Primary or use @Qualifier.
For password encoding, always use BCryptPasswordEncoder or DelegatingPasswordEncoder. Never store plaintext passwords. Spring Boot 3.2 defaults to DelegatingPasswordEncoder, which supports multiple encoding formats. This is useful for migrating from an old system that used MD5 or SHA-1.
Let's see the code:
Customizing Authorization: Role-Based Access Control
Customizing the Security Filter Chain
The SecurityFilterChain is the heart of Spring Security. It defines the order of filters that process each request. By default, Spring Boot creates one chain that applies to all requests. But you can define multiple chains for different URL patterns.
This is useful when you have a mix of public endpoints, API endpoints, and admin endpoints that need different security rules. For example, you might want: - A chain for /api/ that uses JWT authentication and disables CSRF. - A chain for /admin/ that uses form login and requires ADMIN role. - A chain for /public/** that allows anonymous access.
To create multiple chains, define multiple SecurityFilterChain beans and annotate them with @Order. The chain with the lowest order value runs first. Spring Boot will match the first chain whose request matcher matches the request.
But there's a gotcha: if you have multiple chains, you must ensure they don't overlap. If two chains match the same request, the first one wins, which can lead to unexpected behavior.
Let's see a multi-chain configuration:
Customizing Authentication Providers
Sometimes you need more than just a UserDetailsService. You might need to authenticate against multiple sources: a database, LDAP, and OAuth2. Or you might need custom authentication logic, like two-factor authentication or CAPTCHA verification.
Spring Security allows you to define custom AuthenticationProvider beans. When you define one, Spring Boot's auto-configuration picks it up and adds it to the provider manager. You can also define multiple providers and control their order.
Each AuthenticationProvider has a supports() method that checks if it can handle the given authentication token. For example, a provider that handles username/password tokens would return true for UsernamePasswordAuthenticationToken.class.
Here's a real-world example: a custom provider that validates a one-time password (OTP) in addition to regular credentials:
Customizing Error Handling and Exception Translation
Default error handling in Spring Security is minimal. You get a generic 401 Unauthorized or 403 Forbidden response with a default error page. For REST APIs, this is unacceptable. You need JSON responses with proper error codes and messages.
Spring Security provides two key interfaces for customizing error handling: AuthenticationEntryPoint for 401 errors and AccessDeniedHandler for 403 errors. You can also customize the ExceptionTranslationFilter to handle other security exceptions.
Here's the common pattern: define a custom AuthenticationEntryPoint that returns a JSON response with a 401 status code. Similarly, define an AccessDeniedHandler for 403 responses. Then configure them in your SecurityFilterChain.
But there's a trap: if you're using @ControllerAdvice for global exception handling, it won't catch security exceptions because they are thrown before the controller is reached. You must handle them at the security filter level.
Let's see a complete example:
Testing Security Configuration
Security configuration is notoriously hard to test. A misconfigured security rule can expose sensitive endpoints or block legitimate users. Spring Boot Test provides excellent support for testing security with @WebMvcTest and @WithMockUser.
But there's a catch: @WebMvcTest does not load the full security auto-configuration. It only loads the controller and security configuration you specify. This means you might miss interactions between multiple filter chains or custom providers.
For comprehensive testing, use @SpringBootTest with a random port and TestRestTemplate. This loads the full application context, including all security beans. You can then make HTTP requests and verify the responses.
Another common mistake: testing with @WithMockUser but forgetting to set the correct roles. The annotation creates a mock SecurityContext, but it doesn't go through the actual authentication process. This means your custom AuthenticationProvider is not tested.
Let's see both approaches:
The Default Password That Cost $50,000
- Never rely on the default random password for production.
- Always override spring.security.user.password or use a custom UserDetailsService.
- Use Spring Boot Actuator to verify security configuration at runtime.
curl -v http://localhost:8080/hello -u user:passwordgrep 'Using generated security password' logs/spring.log| File | Command / Code | Purpose |
|---|---|---|
| DemoController.java | @RestController | What Auto-Configuration Provides Out of the Box |
| SecurityConfig.java | @Configuration | What the Official Docs Won't Tell You |
| CustomUserDetailsService.java | @Service | Customizing Authentication |
| MultiChainSecurityConfig.java | @Configuration | Customizing the Security Filter Chain |
| CustomAuthenticationProvider.java | @Component | Customizing Authentication Providers |
| SecurityErrorConfig.java | @Configuration | Customizing Error Handling and Exception Translation |
| SecurityTest.java | @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) | Testing Security Configuration |
Key takeaways
Interview Questions on This Topic
Explain how Spring Boot Security auto-configuration works and what beans are created by default.
Frequently Asked Questions
20+ years shipping production Java in banking & fintech. Drawn from code that ran under real load.
That's Spring Security. Mark it forged?
5 min read · try the examples if you haven't