Introduction
When building modern web applications, it's common to have a React frontend communicating with a Spring Boot backend. However, this setup runs into CORS (Cross-Origin Resource Sharing) issues since both the frontend and backend are often hosted on different origins during development.
Without proper CORS configuration, browsers will block cross-origin requests, especially those involving credentials, custom headers, or non-simple HTTP methods like PUT or DELETE.
This article will walk you through setting up CORS correctly in a Spring Boot backend to work seamlessly with a React frontend.
Why CORS Happens
If your React app runs on http://localhost:3000
and your Spring Boot API runs on http://localhost:8080
, requests from the frontend to the backend are considered cross-origin.
Browsers block these requests unless the server explicitly allows the origin.
Solution 1: Use @CrossOrigin
Annotation (Per Controller)
Apply this annotation to specific controllers or methods:
java
@CrossOrigin(origins = "http://localhost:3000")
@RestController
@RequestMapping("/api")
public class MyController {
@GetMapping("/hello")
public String hello() {
return "Hello from backend!";
}
}
You can also allow multiple methods or headers:
java
@CrossOrigin(
origins = "http://localhost:3000",
methods = {RequestMethod.GET, RequestMethod.POST, RequestMethod.PUT},
allowedHeaders = "*"
)
Solution 2: Global CORS Configuration with WebMvcConfigurer
Recommended for centralized CORS configuration:
java
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("http://localhost:3000")
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
.allowedHeaders("*")
.allowCredentials(true);
}
}
Solution 3: CORS with Spring Security
If you’re using Spring Security, CORS must be configured in the security filter chain:
java
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.cors(Customizer.withDefaults()) // Enable CORS
.csrf().disable()
.authorizeHttpRequests(auth -> auth
.anyRequest().permitAll()
);
return http.build();
}
@Bean
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration config = new CorsConfiguration();
config.setAllowedOrigins(List.of("http://localhost:3000"));
config.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE", "OPTIONS"));
config.setAllowedHeaders(List.of("*"));
config.setAllowCredentials(true);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
return source;
}
}
React Frontend: Making Fetch Requests
Ensure that the React frontend includes credentials if needed:
javascript
fetch("http://localhost:8080/api/hello", {
method: "GET",
credentials: "include", // important for cookies/sessions
headers: {
"Content-Type": "application/json"
}
})
.then(response => response.text())
.then(data => console.log(data));
Common CORS Errors and Fixes
Error MessageCauseFixNo 'Access-Control-Allow-Origin' header
Server isn't allowing the originConfigure allowedOrigins in SpringThe value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*'
You're using allowCredentials(true)
with wildcard originReplace *
with a specific originCORS preflight channel did not succeed
Server isn’t handling OPTIONS
requestsEnsure OPTIONS
is in allowed methods
Production Tips
- Use environment variables to separate dev vs prod origins.
- Set appropriate
Access-Control-Max-Age
to reduce preflight requests. - Use
https
and proper headers in production deployments.
Conclusion
CORS configuration is essential when developing a React + Spring Boot application. By using @CrossOrigin
, WebMvcConfigurer
, or configuring Spring Security's CorsConfigurationSource
, you can eliminate CORS errors and ensure smooth communication between frontend and backend.