Introduction
In Spring Security, POST, PUT, and DELETE are not usually “disabled” in a global sense. The real issue is that state-changing requests are often blocked by security rules, most commonly authorization rules or CSRF protection, so enabling them means configuring the security chain correctly for the kind of application you are building.
What Usually Blocks These Methods
When developers say “GET works but POST, PUT, and DELETE do not,” the cause is usually one of these:
the request is not authorized for that path or method
CSRF protection rejects the request
CORS preflight is not configured for browser clients
So the fix is not just to “allow methods.” It is to match the HTTP method, path, and authentication model correctly.
Authorizing by HTTP Method
In modern Spring Security, use a SecurityFilterChain bean and method-specific request matchers.
1import org.springframework.context.annotation.Bean;
2import org.springframework.context.annotation.Configuration;
3import org.springframework.http.HttpMethod;
4import org.springframework.security.config.Customizer;
5import org.springframework.security.config.annotation.web.builders.HttpSecurity;
6import org.springframework.security.web.SecurityFilterChain;
7
8@Configuration
9public class SecurityConfig {
10
11 @Bean
12 public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
13 http
14 .authorizeHttpRequests(auth -> auth
15 .requestMatchers(HttpMethod.GET, "/api/items/**").permitAll()
16 .requestMatchers(HttpMethod.POST, "/api/items/**").hasRole("EDITOR")
17 .requestMatchers(HttpMethod.PUT, "/api/items/**").hasRole("EDITOR")
18 .requestMatchers(HttpMethod.DELETE, "/api/items/**").hasRole("ADMIN")
19 .anyRequest().authenticated()
20 )
21 .httpBasic(Customizer.withDefaults());
22
23 return http.build();
24 }
25}
This does not disable any method. It defines who may use each method on a given route.
CSRF Is the Common Surprise
By default, Spring Security protects browser-based state-changing requests with CSRF checks. That means:
If you are building a stateless REST API for non-browser clients and using tokens instead of session cookies, it is common to disable CSRF:
1import org.springframework.context.annotation.Bean;
2import org.springframework.context.annotation.Configuration;
3import org.springframework.http.HttpMethod;
4import org.springframework.security.config.annotation.web.builders.HttpSecurity;
5import org.springframework.security.web.SecurityFilterChain;
6
7@Configuration
8public class SecurityConfig {
9
10 @Bean
11 public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
12 http
13 .csrf(csrf -> csrf.disable())
14 .authorizeHttpRequests(auth -> auth
15 .requestMatchers(HttpMethod.POST, "/api/**").authenticated()
16 .requestMatchers(HttpMethod.PUT, "/api/**").authenticated()
17 .requestMatchers(HttpMethod.DELETE, "/api/**").authenticated()
18 .anyRequest().permitAll()
19 );
20
21 return http.build();
22 }
23}
Do this only when it matches your authentication model. If you are using browser sessions and cookies, disabling CSRF casually is usually the wrong move.
CORS for Browser Clients
If the client is a browser app hosted on another origin, the problem may be CORS rather than Spring Security method authorization. In that case, add CORS support explicitly.
1import java.util.List;
2import org.springframework.context.annotation.Bean;
3import org.springframework.context.annotation.Configuration;
4import org.springframework.web.cors.CorsConfiguration;
5import org.springframework.web.cors.CorsConfigurationSource;
6import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
7
8@Configuration
9public class CorsConfig {
10
11 @Bean
12 public CorsConfigurationSource corsConfigurationSource() {
13 CorsConfiguration config = new CorsConfiguration();
14 config.setAllowedOrigins(List.of("http://localhost:3000"));
15 config.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE", "OPTIONS"));
16 config.setAllowedHeaders(List.of("*"));
17
18 UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
19 source.registerCorsConfiguration("/**", config);
20 return source;
21 }
22}
Then enable it in the security chain with http.cors(...).
A Full REST-Style Example
1import org.springframework.context.annotation.Bean;
2import org.springframework.context.annotation.Configuration;
3import org.springframework.security.config.Customizer;
4import org.springframework.security.config.annotation.web.builders.HttpSecurity;
5import org.springframework.security.web.SecurityFilterChain;
6
7@Configuration
8public class SecurityConfig {
9
10 @Bean
11 public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
12 http
13 .csrf(csrf -> csrf.disable())
14 .cors(Customizer.withDefaults())
15 .authorizeHttpRequests(auth -> auth
16 .requestMatchers("/api/public/**").permitAll()
17 .requestMatchers("/api/**").authenticated()
18 .anyRequest().denyAll()
19 )
20 .httpBasic(Customizer.withDefaults());
21
22 return http.build();
23 }
24}
In this style, authenticated clients can use the protected API routes with all needed HTTP methods, assuming the controller mappings exist.
Common Pitfalls
One common mistake is blaming Spring Security method support when the real failure is CSRF. A 403 on POST with a working GET often points there first.
Another issue is allowing the method in authorization rules but forgetting browser CORS configuration, which makes the request fail before it reaches the controller.
A third pitfall is disabling CSRF without understanding whether the application still uses cookie-based browser sessions.
Summary
'POST, PUT, and DELETE are usually blocked by security rules, not globally disabled.'
Use method-specific request matchers to authorize those methods cleanly.
For stateless APIs, disabling CSRF is common; for session-based browser apps, be more careful.
Configure CORS when browser clients call the API from another origin.
Check authorization, CSRF, and CORS before assuming the HTTP method itself is the problem.