Spring Security: CORS and CSRF Configuration for REST APIs
When building modern Spring Boot REST APIs consumed by frontend single-page applications (SPAs) like React or Next.js, proper security configurations regarding Cross-Origin Resource Sharing (CORS) and Cross-Site Request Forgery (CSRF) are critical.
This guide explains how to configure CORS policies and safely manage CSRF protection for stateless, token-authenticated architectures.
Configuring CORS for Frontend Applications
By default, browsers block frontend applications running on one origin (e.g., http://localhost:3000) from making requests to a backend API running on another origin (e.g., http://localhost:8080) unless explicitly permitted via CORS headers.
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import java.util.List;
@Configuration
public class CorsConfig {
@Bean
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(List.of("http://localhost:3000"));
configuration.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE", "OPTIONS"));
configuration.setAllowedHeaders(List.of("Authorization", "Cache-Control", "Content-Type"));
configuration.setAllowCredentials(true);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/api/**", configuration);
return source;
}
}
Managing CSRF in Stateless REST APIs
Cross-Site Request Forgery (CSRF) exploits vulnerabilities where malicious websites trick a user's browser into executing unwanted actions on a trusted site where they are currently authenticated.
However, if your REST API is entirely stateless—relying exclusively on tokens (such as JWT stored in local storage or custom headers) rather than browser session cookies—CSRF protection is typically disabled because stateless APIs are inherently immune to cookie-based CSRF attacks.
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.config.http.SessionCreationPolicy;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.web.cors.CorsConfigurationSource;
@Configuration
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http, CorsConfigurationSource corsConfigurationSource) throws Exception {
http
.cors(cors -> cors.configurationSource(corsConfigurationSource))
.csrf(csrf -> csrf.disable())
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/auth/**").permitAll()
.anyRequest().authenticated()
)
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS));
return http.build();
}
}
Summary
Properly setting up CORS allows your frontend applications to communicate securely with your backend, while correctly managing CSRF protection ensures your security filter chain matches your application's stateless authentication strategy.