CORS (Cross-Origin Resource Sharing) errors are one of the most persistent and confusing issues developers face when integrating modern frontend frameworks like Angular and React with a Spring Boot backend.
You may see errors such as:
Access to fetch at 'http://localhost:8080/api/users' from origin 'http://localhost:3000' has been blocked by CORS policy.
Or:
No 'Access-Control-Allow-Origin' header present on the requested resource.
These are not Spring errors — they’re browser security mechanisms rejecting your call because it violates same-origin policy.
This production-safe guide explains:
- What CORS really is
- Why browsers block certain requests
- How to fix CORS properly in Spring Boot
- How to do it securely in production
- Angular and React specific examples
What Is CORS (Explained Simply)
CORS stands for Cross-Origin Resource Sharing — a browser security feature that restricts web pages from making requests to a different domain or port than where the page was served.
For example:
| Frontend | Backend |
|---|---|
| http://localhost:3000 | http://localhost:8080 |
This is considered cross-origin, and by default, browsers block such requests unless the server explicitly allows them.
Important to remember:
CORS is enforced by the browser — not by Spring Boot.
This is why tools like Postman or cURL do not show CORS errors, but browsers do.
Why CORS Errors Occur with Angular or React
Modern frontend applications often run on development servers such as:
- Angular →
http://localhost:4200 - React →
http://localhost:3000
When these apps call a Spring Boot API on a different origin:
- Browser initiates a preflight request (OPTIONS)
- It checks whether the server allows the actual request
- If the server does not send the correct headers → request is blocked
Common Causes
✔ No CORS headers sent on preflight
✔ Spring Security filter ordering
✔ Credentialed requests (withCredentials)
✔ Wildcard origin used insecurely
✔ Allowed methods/headers mismatch
How Spring Boot Handles CORS (Production-Safe)
Spring Boot provides multiple ways to configure CORS.
The recommended production-safe approach is global configuration, not ad-hoc @CrossOrigin everywhere.
Global CORS Configuration (Best Approach)
Using WebMvcConfigurer
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/**")
.allowedOrigins("https://your-frontend.com")
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
.allowedHeaders("*")
.allowCredentials(true)
.maxAge(3600);
}
}
Production rule of thumb:
✔ Only allow trusted domains
✔ Avoid "*"
✔ Limit methods and headers as much as possible
Fixing CORS When Using Spring Security
If your application uses Spring Security, CORS configuration must be integrated with the security filter chain.
Without this, Spring Security may block preflight requests before your global CORS config can take effect.
Example Spring Security CORS Setup
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.cors()
.and()
.csrf().disable()
.authorizeHttpRequests(auth -> auth
.requestMatchers(HttpMethod.OPTIONS, "/**").permitAll()
.anyRequest().authenticated()
);
return http.build();
}
}
Key points:
✔ Call .cors() before security rules
✔ Explicitly allow OPTIONS requests
✔ Do not disable CSRF unless intentional
Angular-Specific CORS Notes
Angular’s HttpClient often sends:
- Custom headers
- JSON content type
- Authentication tokens
This triggers preflight (OPTIONS) before the main request.
If your backend does not handle OPTIONS correctly, the browser will block your calls.
Angular Example
this.httpClient.get('/api/users', { withCredentials: true });
Make sure Spring Boot’s CORS config:
✔ Allows credentials
✔ Matches origin exactly
✔ Supports required methods
React-Specific CORS Notes
React apps using fetch() or Axios may send:
fetch('http://localhost:8080/api/users', {
credentials: 'include',
headers: {
'Content-Type': 'application/json'
}
});
React’s credentials: 'include' will trigger a CORS preflight unless the backend explicitly allows credentialed requests.
Your Spring Boot CORS configuration must include:
.allowCredentials(true)
Why Not Use @CrossOrigin("*") Everywhere?
Using @CrossOrigin("*") or "*" for allowed origins is easy during development, but dangerous in production because:
❌ Opens your API to any origin
❌ Makes API vulnerable to CSRF attacks
❌ Complicates monitoring and security audits
Use trusted domains — not wildcards.
How to Debug CORS Issues (Production Tips)
Browser DevTools
✔ Look at Network tab
✔ Check the OPTIONS preflight request
✔ Inspect response headers
✔ Confirm correct Access-Control-Allow-Origin
Required response headers for CORS:
Access-Control-Allow-Origin: https://your-frontend.com
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: Content-Type
Access-Control-Allow-Credentials: true
Related Spring Boot Guides
Understanding the request lifecycle, profiles, and security helps fix CORS more effectively:
- Request Lifecycle in Spring Boot
https://springbootfixes.com/request-lifecycle-in-spring-boot-from-client-to-response/ - Spring Boot Startup Flow Explained
https://springbootfixes.com/how-spring-boot-application-starts-startup-flow-explained/ - Spring Boot Configuration & Profiles
https://springbootfixes.com/spring-boot-configuration-and-profiles-explained-beginner-to-production-guide/ - REST API Basics in Spring Boot
https://springbootfixes.com/rest-api-basics-in-spring-boot-production-ready-guide/
Summary
CORS errors in Spring Boot are not bugs — they’re browser security policies at work.
Fixing them requires:
✔ Understanding how browsers initiate preflight requests
✔ Correctly configuring Spring Boot (global CORS + Spring Security)
✔ Allowing trusted origins only
✔ Using environment-specific rules for production
With this production-safe approach, your Angular and React frontends will work smoothly with your Spring Boot backend without compromising security.
