Home Java Disabling Spring Security for a Specific Profile in Spring Boot
Intermediate 3 min · July 14, 2026

Disabling Spring Security for a Specific Profile in Spring Boot

Learn how to conditionally disable Spring Security for a specific profile in Spring Boot.

N
Naren Founder & Principal Engineer

20+ years shipping production Java in banking & fintech. Drawn from code that ran under real load.

Follow
Production
production tested
July 15, 2026
last updated
2,398
articles · all by Naren
Before you start⏱ 15-20 min read
  • Basic knowledge of Spring Boot and Spring Security.
  • Familiarity with Spring profiles and @Profile annotation.
  • A Spring Boot application with Spring Security dependency.
 ● Production Incident 🔎 Debug Guide ⚙ Triage Commands
Quick Answer
  • Use @Profile on a @Configuration class that extends WebSecurityConfigurerAdapter to conditionally disable security.
  • For reactive apps, use @Profile on SecurityWebFilterChain bean.
  • Avoid spring.autoconfigure.exclude in profile-specific properties; it's brittle.
  • Use @ConditionalOnMissingBean to provide a no-op security config for the profile.
  • Test with @ActiveProfiles and @WebMvcTest to verify security is disabled.
✦ Definition~90s read
What is Disabling Spring Security for a Specific Profile in Spring Boot?

Disabling Spring Security for a specific profile means conditionally deactivating security constraints (like authentication and CSRF protection) only when a particular Spring profile is active, allowing unrestricted access to endpoints in that environment.

Think of your Spring Boot app like a nightclub with a bouncer (Spring Security) checking IDs.
Plain-English First

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.

DevSecurityConfig.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@Profile("dev")
@Configuration
public class DevSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .anyRequest().permitAll()
            .and()
                .csrf().disable()
                .headers().frameOptions().disable(); // For H2 console
    }
}
💡Don't forget CSRF and frame options
📊 Production Insight
I once saw a team use @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.
🎯 Key Takeaway
Use @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.

NoOpSecurityConfig.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.SecurityFilterChain;

@Profile("dev")
@Configuration
public class NoOpSecurityConfig {

    @Bean
    @ConditionalOnMissingBean(SecurityFilterChain.class)
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .anyRequest().permitAll()
            .and()
                .csrf().disable();
        return http.build();
    }
}
⚠ ConditionalOnMissingBean can cause double beans
🎯 Key Takeaway
The @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:

  1. Profile name mismatch: The @Profile annotation value must exactly match the active profile name. Case-sensitive. I've seen developers use @Profile("dev") but the environment variable set SPRING_PROFILES_ACTIVE=DEV (uppercase). It won't match.
  2. Auto-configuration still runs: Even if you define your own SecurityFilterChain, Spring Boot's security auto-configuration still runs and creates beans like SecurityProperties. This can lead to unexpected behavior if you're not careful. For example, the default security properties might still enforce a login page.
  3. 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.
  4. 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").
  5. Multiple security filter chains: If you have multiple SecurityFilterChain beans (e.g., one for API and one for web), disabling security for a profile means you need to handle both. The @Profile approach works per bean.
  6. WebFlux vs Servlet: The approach for WebFlux is similar but uses SecurityWebFilterChain instead. Don't mix them up.
WebFluxDevSecurityConfig.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
import org.springframework.security.config.web.server.ServerHttpSecurity;
import org.springframework.security.web.server.SecurityWebFilterChain;

@Profile("dev")
@Configuration
@EnableWebFluxSecurity
public class WebFluxDevSecurityConfig {

    @Bean
    public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
        http
            .authorizeExchange()
                .anyExchange().permitAll()
            .and()
                .csrf().disable();
        return http.build();
    }
}
🔥Actuator security is separate
📊 Production Insight
In a recent project, a developer used @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.
🎯 Key Takeaway
Be aware of the hidden gotchas: case-sensitive profile names, actuator security, and testing complexities.

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.

SecurityProfileTest.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.test.context.ActiveProfiles;

import static org.assertj.core.api.Assertions.assertThat;

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@ActiveProfiles("dev")
class SecurityProfileTest {

    @Autowired
    private TestRestTemplate restTemplate;

    @Test
    void shouldAllowUnauthenticatedAccessInDevProfile() {
        ResponseEntity<String> response = restTemplate.getForEntity("/api/public", String.class);
        assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
    }

    @Test
    void shouldAllowAccessToAnyEndpoint() {
        ResponseEntity<String> response = restTemplate.getForEntity("/api/private", String.class);
        assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
    }
}
💡Test both profiles
🎯 Key Takeaway
Integration tests with @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:

  1. Using spring.autoconfigure.exclude in profile-specific properties: This disables all security auto-configuration, which can have unintended side effects. As mentioned in the production incident, this is fragile.
  2. 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.
  3. Not disabling frame options: If you use H2 console or Swagger UI, you need to disable frame options to allow rendering in iframes.
  4. Profile name mismatch: Ensure the profile name in @Profile matches exactly the active profile name. Use lowercase and avoid typos.
  5. Overriding the wrong method: In WebSecurityConfigurerAdapter, you need to override configure(HttpSecurity). Overriding configure(AuthenticationManagerBuilder) won't disable security.
  6. Not testing: Many developers assume the config works without testing. Write tests as shown above.
CommonMistakesExample.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// WRONG: Using spring.autoconfigure.exclude in properties
// application-dev.properties:
// spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration

// CORRECT: Using @Profile on a configuration class
@Profile("dev")
@Configuration
public class DevSecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().anyRequest().permitAll()
            .and().csrf().disable()
            .headers().frameOptions().disable();
    }
}
⚠ Never use spring.autoconfigure.exclude for security
🎯 Key Takeaway
Avoid common pitfalls like using auto-configuration exclusion, forgetting CSRF/frame options, and profile name mismatches.

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.

ReactiveDevSecurityConfig.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
import org.springframework.security.config.web.server.ServerHttpSecurity;
import org.springframework.security.web.server.SecurityWebFilterChain;

@Profile("dev")
@Configuration
@EnableWebFluxSecurity
public class ReactiveDevSecurityConfig {

    @Bean
    public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
        http
            .authorizeExchange()
                .anyExchange().permitAll()
            .and()
                .csrf().disable()
                .headers().frameOptions().disable();
        return http.build();
    }
}
🔥WebFlux vs Servlet
🎯 Key Takeaway
For WebFlux, use SecurityWebFilterChain and @EnableWebFluxSecurity with @Profile.
● Production incidentPOST-MORTEMseverity: high

The Dev Profile That Leaked Into Staging

Symptom
Users could access any endpoint without authentication in the staging environment.
Assumption
The developer assumed that the 'dev' profile would only be active on local machines.
Root cause
The 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.
Fix
Removed the auto-configuration exclusion from properties. Instead, used a @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).
Key lesson
  • Never use spring.autoconfigure.exclude in profile-specific properties for security—it's too broad and disables all security auto-configuration.
  • Always use @Profile on 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 @ActiveProfiles in integration tests to explicitly test each security configuration.
Production debug guideSymptom to Action4 entries
Symptom · 01
Endpoints are accessible without authentication in an environment where security should be enabled.
Fix
Check the active profiles: curl -X GET /actuator/env/spring.profiles.active. If the wrong profile is active, fix your environment configuration.
Symptom · 02
Security configuration doesn't seem to apply even though the profile is correct.
Fix
Enable debug logging for security: logging.level.org.springframework.security=DEBUG. Look for SecurityFilterChain beans being registered.
Symptom · 03
Getting 403 Forbidden errors when security should be disabled.
Fix
Verify that the no-op security configuration bean is actually created. Check for @ConditionalOnMissingBean issues. Ensure the profile is active.
Symptom · 04
Application fails to start with multiple security configurations.
Fix
Check for duplicate SecurityFilterChain beans. Use @Order to specify precedence. Ensure only one configuration is active per profile.
★ Quick Debug Cheat SheetQuick commands and actions for debugging security profile issues.
Security unexpectedly disabled
Immediate action
Check active profiles
Commands
curl -X GET /actuator/env/spring.profiles.active
cat /proc/1/environ | tr '\0' '\n' | grep SPRING_PROFILES_ACTIVE
Fix now
Set correct profile in environment variable or configuration file.
Security still enabled when it should be disabled+
Immediate action
Check if no-op config is loaded
Commands
curl -X GET /actuator/beans | grep -i security
Check logs for 'NoOpSecurityConfig' bean creation
Fix now
Ensure @Profile annotation matches the profile name and the config class is scanned.
Multiple security filter chains+
Immediate action
List all SecurityFilterChain beans
Commands
curl -X GET /actuator/beans | grep -i securityFilterChain
Check @Order annotations
Fix now
Add @Order(0) to the no-op config and @Order(SecurityProperties.BASIC_AUTH_ORDER) to the secure config.
ApproachProsCons
@Profile on WebSecurityConfigurerAdapterClean, explicit, keeps other auto-configuration intactRequires a separate configuration class
@ConditionalOnMissingBean with @ProfileCan completely replace auto-configurationFragile, can cause duplicate beans, riskier
spring.autoconfigure.exclude in propertiesQuick and easyDisables all security auto-configuration, dangerous, not recommended
⚙ Quick Reference
6 commands from this guide
FileCommand / CodePurpose
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

1
Use @Profile on a WebSecurityConfigurerAdapter subclass to conditionally disable security for a specific profile. This is the cleanest and safest approach.
2
Avoid spring.autoconfigure.exclude for security; it's too broad and can lead to production incidents.
3
Always test your profile-specific security configuration with integration tests using @ActiveProfiles.
4
Remember to disable CSRF and frame options in the dev config for tools like H2 console and Swagger UI.
INTERVIEW PREP · PRACTICE MODE

Interview Questions on This Topic

Q01SENIOR
How would you conditionally disable Spring Security for a 'dev' profile ...
Q02SENIOR
What are the risks of using `spring.autoconfigure.exclude` to disable se...
Q03SENIOR
How would you test that security is disabled for the 'dev' profile?
Q01 of 03SENIOR

How would you conditionally disable Spring Security for a 'dev' profile in a Spring Boot application?

ANSWER
Create a configuration class that extends 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.
FAQ · 3 QUESTIONS

Frequently Asked Questions

01
Can I disable security for multiple profiles?
02
What if I want to disable security for all profiles except production?
03
Does disabling security for a profile affect actuator endpoints?
N
Naren Founder & Principal Engineer

20+ years shipping production Java in banking & fintech. Drawn from code that ran under real load.

Follow
Verified
production tested
July 15, 2026
last updated
2,398
articles · all by Naren
🔥

That's Spring Security. Mark it forged?

3 min read · try the examples if you haven't

Previous
SAML 2.0 Single Sign-On with Spring Boot and Spring Security
29 / 31 · Spring Security
Next
A Complete Guide to CSRF Protection in Spring Security