CORS Error Fixed in Spring Boot Backend with a React, Angular, or Vue Frontend

📘 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 app
  • allowedOrigins(...): Only allows requests from your frontend (can be multiple origins)
  • allowedMethods(...): Supports all major HTTP verbs
  • allowCredentials(true): Allows cookies or Authorization headers to be sent
  • allowedHeaders("*"): Accepts any custom headers (like Authorization, 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 and WebMvcConfigurer alone won’t work.
  • The security filter chain must include cors() and a CorsConfigurationSource.

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

Spring Boot 3 Paid Course Published for Free
on my Java Guides YouTube Channel

Subscribe to my YouTube Channel (165K+ subscribers):
Java Guides Channel

Top 10 My Udemy Courses with Huge Discount:
Udemy Courses - Ramesh Fadatare