3.10 CORS Configuration
Browsers block API calls to a different origin (protocol + host + port) by default due to Same-Origin Policy. If the frontend is https://front.com and the API is https://api.com, the server must send CORS (Cross-Origin Resource Sharing) headers.
Reference: Spring Boot 3.2.x
1. What is CORS?
- Origin: Protocol + host + port (e.g.
https://front.com:443) - The browser may send a preflight (OPTIONS) request; the server responds with Access-Control-Allow-Origin and related headers to allow the actual request.
2. Global Config (WebMvcConfigurer)
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/**")
.allowedOrigins("https://front.example.com", "http://localhost:3000")
.allowedMethods("GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS")
.allowedHeaders("*")
.allowCredentials(true)
.maxAge(3600);
}
}
- addMapping: URL pattern to apply CORS to
- allowedOrigins: Allowed origins.
*and allowCredentials(true) cannot be used together - allowedMethods: Allowed HTTP methods
- allowedHeaders: Allowed request headers.
*or enumerated list - allowCredentials: Allow cookies and authentication info
- maxAge: Preflight response cache duration (seconds)
3. With Spring Security
When using Security, it is cleaner to configure CORS with a CorsConfigurationSource bean.
@Configuration
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.cors(cors -> cors.configurationSource(corsConfigurationSource()))
.authorizeHttpRequests(auth -> auth.anyRequest().authenticated());
return http.build();
}
@Bean
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration config = new CorsConfiguration();
config.setAllowedOrigins(List.of("https://front.example.com"));
config.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE", "OPTIONS"));
config.setAllowedHeaders(List.of("*"));
config.setAllowCredentials(true);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/api/**", config);
return source;
}
}
4. Method/Controller Level (@CrossOrigin)
Use @CrossOrigin when you only want to allow specific APIs.
@RestController
@RequestMapping("/api/public")
@CrossOrigin(origins = "https://front.example.com", maxAge = 3600)
public class PublicController { ... }
- When overlapping with global config, they are merged. In production, using global config uniformly is common.
tip
In production, restrict allowedOrigins to concrete domains and do not use * with allowCredentials(true) at the same time.