📘 Premium Read: Access my best content on Medium member-only articles — deep dives into Java, Spring Boot, Microservices, backend architecture, interview preparation, career advice, and industry-standard best practices.
🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my Udemy courses are real-time and project oriented courses.
▶️ Subscribe to My YouTube Channel (176K+ subscribers): Java Guides on YouTube
▶️ For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh Fadatare on YouTube
If you’ve ever worked on a Spring Boot backend paired with a React, Angular, or Vue frontend, chances are you’ve run into that dreaded error:
Access to fetch at 'http://localhost:8080/api/data' from origin 'http://localhost:3000'
has been blocked by CORS policy.
It’s the bane of many frontend-backend integrations — CORS (Cross-Origin Resource Sharing) errors that break communication, confuse newcomers, and waste hours of debugging time.
What if fixing it didn’t require a complex setup or custom headers?
Here’s the good news: one clean CORS configuration in Spring Boot can solve all these problems — across dev, staging, and production — without exposing your app to security risks.
Let’s break it down.
What Is CORS, and Why Does It Block Your Requests?
CORS is a browser security mechanism. It prevents JavaScript on one origin (say, localhost:3000
) from making requests to another origin (localhost:8080
) unless the server explicitly allows it.
While it protects users from malicious cross-site attacks, it can also block legitimate communication between your frontend and backend during development or in microservice setups.
🚫 Common Symptoms of CORS Issues
- Fetch or Axios requests from frontend apps fail
- Preflight (OPTIONS) requests return
403 Forbidden
- Authentication tokens aren’t sent or accepted
- Errors only happen in browsers — not Postman or cURL
The cause? Your Spring Boot backend doesn’t know it’s supposed to allow requests from your frontend origin.
The Cleanest Fix: Global CORS Mapping in Spring Boot
The most robust and maintainable way to handle CORS in Spring Boot is by using a WebMvcConfigurer
bean.
✅ Add This One Config:
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**") // Apply to all paths
.allowedOrigins("http://localhost:3000") // Frontend origin
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
.allowedHeaders("*")
.allowCredentials(true);
}
}
Why This Works
addMapping("/**")
: Applies to all endpoints in your appallowedOrigins(...)
: Only allows requests from your frontend (can be multiple origins)allowedMethods(...)
: Supports all major HTTP verbsallowCredentials(true)
: Allows cookies or Authorization headers to be sentallowedHeaders("*")
: Accepts any custom headers (likeAuthorization
,Content-Type
, etc.)
This configuration lives in a single place, scales well across endpoints, and can be easily extended for multiple environments or microservices.
Real-World Example: React + Spring Boot
React app making a request:
fetch("http://localhost:8080/api/products", {
method: "GET",
credentials: "include", // Needed if using cookies
headers: {
"Content-Type": "application/json"
}
});
Spring Boot backend returns:
Access-Control-Allow-Origin: http://localhost:3000
Access-Control-Allow-Credentials: true
The browseraccepts the response. No CORS error. Request successful.
🛡 Security Note
You might be tempted to write:
.allowedOrigins("*")
That will work, but it’s not secure — especially if you’re using allowCredentials(true)
(which Spring will reject if *
is used).
Use explicit origins (http://localhost:3000
, https://yourfrontend.com
) to avoid exposing your backend to untrusted sources.
Handling Multiple Frontend Origins
For environments like dev, staging, and production:
.allowedOrigins(
"http://localhost:3000",
"https://staging.frontend.com",
"https://www.frontend.com"
)
Or load them from application.properties
:
cors.allowed-origins=http://localhost:3000,https://frontend.com
Then bind using @ConfigurationProperties
or @Value
in your config class.
Alternative: Controller-Level CORS (Not Recommended for Large Apps) using @CrossOrigin annotation
You can also add CORS config per controller:
@CrossOrigin(origins = "http://localhost:3000")
@RestController
@RequestMapping("/api")
public class ProductController {
...
}
This is fine for small or isolated APIs, but becomes hard to maintain across multiple controllers and environments.
Prefer global config unless you have a specific reason to isolate CORS per controller.
Spring Security + CORS: The Common Gotcha
If you’re using Spring Security and still getting CORS errors after adding WebMvcConfigurer
, the reason might be that Spring Security is overriding CORS behavior.
✅ Fix:
You must enable CORS in the security filter chain too:
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.cors() // Enables CORS
.and()
.csrf(AbstractHttpConfigurer::disable)
.authorizeHttpRequests()
.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;
}
}
Important:
- When using Spring Security,
@CrossOrigin
andWebMvcConfigurer
alone won’t work. - The security filter chain must include
cors()
and aCorsConfigurationSource
.
Debugging CORS Issues
✅ Use Browser DevTools
- Open the Network tab
- Click on the failed request
- Check Response Headers
- Look for missing
Access-Control-Allow-Origin
or mismatched values
✅ Use cURL with Origin Header
curl -H "Origin: http://localhost:3000" \
-H "Access-Control-Request-Method: GET" \
-X OPTIONS http://localhost:8080/api/products -v
If the response doesn’t include the proper CORS headers, the backend is misconfigured.
Summary: One CORS Config to Rule Them All

Conclusion
CORS is one of the most misunderstood issues in modern web development — not because it’s complex, but because the fix is often misplaced.
Spring Boot makes it easy to configure CORS the right way. With just one configuration class, it’s possible to:
- Eliminate development-time errors
- Enable secure cross-origin requests
- Scale from local testing to production deployments
No more jumping through hoops or disabling browser security. Just clean, declarative configuration.
Comments
Post a Comment
Leave Comment