Disabling Spring Security for a Specific Profile in Spring Boot
Learn how to conditionally disable Spring Security for a specific profile in Spring Boot.
20+ years shipping production Java in banking & fintech. Drawn from code that ran under real load.
- ✓Basic knowledge of Spring Boot and Spring Security.
- ✓Familiarity with Spring profiles and
@Profileannotation. - ✓A Spring Boot application with Spring Security dependency.
- Use
@Profileon a@Configurationclass that extendsWebSecurityConfigurerAdapterto conditionally disable security. - For reactive apps, use
@ProfileonSecurityWebFilterChainbean. - Avoid
spring.autoconfigure.excludein profile-specific properties; it's brittle. - Use
@ConditionalOnMissingBeanto provide a no-op security config for the profile. - Test with
@ActiveProfilesand@WebMvcTestto verify security is disabled.
Think of your Spring Boot app like a nightclub with a bouncer (Spring Security) checking IDs. For a special 'backstage' profile (like local development), you want to let everyone in without checking IDs. You can tell the bouncer to take a break when that profile is active. That's what we're doing—conditionally disabling the bouncer for a specific profile.
Let's face it: not every environment needs the same security. In production, you lock everything down with OAuth2, JWT, or form login. But in local development or integration tests, that security layer is a pain. You just want to hit your endpoints without generating tokens or dealing with CSRF. The naive approach—commenting out security config—works until you commit it. Then someone pushes to production and you have an incident.
I've seen teams disable security globally with @EnableWebSecurity(false) or exclude SecurityAutoConfiguration from auto-configuration. Both are fragile and can lead to security holes. The right way is to conditionally disable Spring Security for a specific profile using Spring's profile mechanism. This keeps your production security intact while giving developers a friction-free local experience.
In this article, I'll show you the battle-tested approaches to disable Spring Security for a specific profile. I'll cover the classic Servlet stack, WebFlux, and the gotchas that the official docs gloss over. By the end, you'll have a clean, maintainable solution that won't bite you in production.
The Right Way: Using @Profile on a Security Configuration
The cleanest approach is to create a configuration class that extends WebSecurityConfigurerAdapter (for Servlet-based apps) or defines a SecurityWebFilterChain bean (for WebFlux) and annotate it with @Profile. This class will override the security settings to permit all requests. The key is to have this configuration active only for the desired profile, while the default security configuration (from auto-configuration) remains active for all other profiles.
Here's a concrete example for a Servlet-based Spring Boot application. Assume you have a profile called dev where you want to disable security.
@Profile("!production") to disable security for all non-production environments. That's dangerous because it includes staging and QA. Always be explicit with the profile name.@Profile on a security configuration class to conditionally relax security for a specific profile. This keeps your production security intact.Alternative: Using @ConditionalOnMissingBean and a No-Op Config
Another approach is to define a no-op security configuration that is conditionally created only if no other security configuration is present. This is useful if you want to completely disable Spring Security (including auto-configuration) for a profile. However, this approach is riskier because it removes all security auto-configuration, which might include other important beans like SecurityProperties.
Here's how you can do it: Create a configuration class that defines a SecurityFilterChain bean (or extends WebSecurityConfigurerAdapter) and annotate it with @ConditionalOnMissingBean(SecurityFilterChain.class). Then, use @Profile to limit it to the desired profile.
But I recommend the first approach over this one. The reason: @ConditionalOnMissingBean can lead to subtle bugs if the order of bean creation changes. Also, if you have multiple security configurations, you might accidentally create multiple SecurityFilterChain beans.
@ConditionalOnMissingBean approach is more fragile. Stick with @Profile on a WebSecurityConfigurerAdapter subclass.What the Official Docs Won't Tell You
The Spring Security reference guide tells you how to configure security, but it doesn't tell you the pitfalls of disabling it for a profile. Here are the gotchas I've seen in production:
- Profile name mismatch: The
@Profileannotation value must exactly match the active profile name. Case-sensitive. I've seen developers use@Profile("dev")but the environment variable setSPRING_PROFILES_ACTIVE=DEV(uppercase). It won't match. - Auto-configuration still runs: Even if you define your own
SecurityFilterChain, Spring Boot's security auto-configuration still runs and creates beans likeSecurityProperties. This can lead to unexpected behavior if you're not careful. For example, the default security properties might still enforce a login page. - Actuator endpoints: If you have Spring Boot Actuator, security for actuator endpoints is configured separately. Disabling security for the main app doesn't automatically disable it for actuator endpoints. You need to configure them explicitly.
- Testing: When writing tests with
@WebMvcTest, the security auto-configuration is still applied. You need to explicitly exclude security auto-configuration or use@AutoConfigureMockMvc(addFilters = false). But if you're testing a profile-specific config, use@ActiveProfiles("dev"). - Multiple security filter chains: If you have multiple
SecurityFilterChainbeans (e.g., one for API and one for web), disabling security for a profile means you need to handle both. The@Profileapproach works per bean. - WebFlux vs Servlet: The approach for WebFlux is similar but uses
SecurityWebFilterChaininstead. Don't mix them up.
@Profile("dev") but the CI pipeline set SPRING_PROFILES_ACTIVE=development. The security config never activated, and they spent hours debugging why security was still on in dev.Testing Your Profile-Specific Security Configuration
You must test that your profile-specific security works correctly. Write integration tests that activate the profile and verify that endpoints are accessible without authentication. Also write tests for the default profile to ensure security is enabled.
Use @SpringBootTest with @ActiveProfiles("dev") to load the application with the dev profile. Then use TestRestTemplate or MockMvc to make requests without authentication and assert that you get a 200 response instead of 401/403.
For the production profile, you can test with @ActiveProfiles("prod") and expect that unauthenticated requests are rejected.
@ActiveProfiles are essential to verify that your profile-specific security works as expected.Common Mistakes and How to Avoid Them
Here are the most common mistakes I've seen when disabling Spring Security for a profile:
- Using
spring.autoconfigure.excludein profile-specific properties: This disables all security auto-configuration, which can have unintended side effects. As mentioned in the production incident, this is fragile. - Forgetting to disable CSRF: In development, you often need to disable CSRF for tools like Postman or Swagger. If you don't, you'll get 403 errors on POST requests.
- Not disabling frame options: If you use H2 console or Swagger UI, you need to disable frame options to allow rendering in iframes.
- Profile name mismatch: Ensure the profile name in
@Profilematches exactly the active profile name. Use lowercase and avoid typos. - Overriding the wrong method: In
WebSecurityConfigurerAdapter, you need to overrideconfigure(HttpSecurity). Overridingconfigure(AuthenticationManagerBuilder)won't disable security. - Not testing: Many developers assume the config works without testing. Write tests as shown above.
Disabling Security for WebFlux Applications
If you're using Spring WebFlux, the approach is similar but you use SecurityWebFilterChain instead of WebSecurityConfigurerAdapter. Create a @Configuration class annotated with @Profile and define a SecurityWebFilterChain bean that permits all requests.
Note that WebFlux security auto-configuration is separate from Servlet stack. You need to ensure you're not mixing them. If your application uses WebFlux, use the reactive security configuration.
SecurityWebFilterChain and @EnableWebFluxSecurity with @Profile.The Dev Profile That Leaked Into Staging
application-dev.properties file contained spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration. When the staging environment accidentally had the 'dev' profile active due to a misconfigured CI/CD pipeline, security was completely disabled.@Profile-annotated configuration class that extends WebSecurityConfigurerAdapter and overrides configure(HttpSecurity) to permit all requests. This way, even if the profile is active, the security is only relaxed, not completely disabled (other auto-configuration like CSRF protection remained).- Never use
spring.autoconfigure.excludein profile-specific properties for security—it's too broad and disables all security auto-configuration. - Always use
@Profileon a configuration class to conditionally disable security. This keeps other security features intact. - Review CI/CD pipeline configurations to prevent profile leaks.
- Add a test that verifies security is enabled when the production profile is active.
- Use
@ActiveProfilesin integration tests to explicitly test each security configuration.
curl -X GET /actuator/env/spring.profiles.active. If the wrong profile is active, fix your environment configuration.logging.level.org.springframework.security=DEBUG. Look for SecurityFilterChain beans being registered.@ConditionalOnMissingBean issues. Ensure the profile is active.SecurityFilterChain beans. Use @Order to specify precedence. Ensure only one configuration is active per profile.curl -X GET /actuator/env/spring.profiles.activecat /proc/1/environ | tr '\0' '\n' | grep SPRING_PROFILES_ACTIVE| File | Command / Code | Purpose |
|---|---|---|
| DevSecurityConfig.java | @Profile("dev") | The Right Way |
| NoOpSecurityConfig.java | @Profile("dev") | Alternative |
| WebFluxDevSecurityConfig.java | @Profile("dev") | What the Official Docs Won't Tell You |
| SecurityProfileTest.java | @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) | Testing Your Profile-Specific Security Configuration |
| CommonMistakesExample.java | @Profile("dev") | Common Mistakes and How to Avoid Them |
| ReactiveDevSecurityConfig.java | @Profile("dev") | Disabling Security for WebFlux Applications |
Key takeaways
@Profile on a WebSecurityConfigurerAdapter subclass to conditionally disable security for a specific profile. This is the cleanest and safest approach.spring.autoconfigure.exclude for security; it's too broad and can lead to production incidents.@ActiveProfiles.Interview Questions on This Topic
How would you conditionally disable Spring Security for a 'dev' profile in a Spring Boot application?
WebSecurityConfigurerAdapter and annotate it with @Profile("dev"). Override the configure(HttpSecurity) method to permit all requests and disable CSRF. This ensures the security configuration is only active when the 'dev' profile is active.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?
3 min read · try the examples if you haven't