Careeroza
Configuring CORS in Spring Security
CorsConfigurationSource Bean
The preflight has no Authorization header, so if Spring Security sees it first, it answers 401 and the browser reports a "CORS error". http.cors(...) adds a CorsFilter early in the chain that answers preflights before authentication runs.
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
@Configuration
public class CorsConfig {
@Bean
CorsConfigurationSource corsConfigurationSource(
@Value("${shopease.cors.allowed-origins}") List<String> origins) {
CorsConfiguration config = new CorsConfiguration();
config.setAllowedOrigins(origins); // exact origins, no "*"
config.setAllowedMethods(List.of("GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"));
config.setAllowedHeaders(List.of("Authorization", "Content-Type", "X-XSRF-TOKEN"));
config.setExposedHeaders(List.of("Location"));
config.setAllowCredentials(true); // needed for the refresh cookie
config.setMaxAge(3600L); // cache the preflight for 1 hour
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/api/**", config);
return source;
}
}
// in SecurityConfig
http.cors(Customizer.withDefaults()); // uses the CorsConfigurationSource bean aboveConfig
application.yml
shopease:
cors:
allowed-origins: http://localhost:5173,https://shopease.inTesting a Preflight with curl
Example
Allowed origin vs unknown origin:
curl -i -X OPTIONS localhost:8080/api/orders \
-H "Origin: http://localhost:5173" \
-H "Access-Control-Request-Method: POST" \
-H "Access-Control-Request-Headers: authorization,content-type"
curl -i -X OPTIONS localhost:8080/api/orders \
-H "Origin: https://evil.example" \
-H "Access-Control-Request-Method: POST"Example output
HTTP/1.1 200 OK Vary: Origin, Access-Control-Request-Method, Access-Control-Request-Headers Access-Control-Allow-Origin: http://localhost:5173 Access-Control-Allow-Methods: GET,POST,PUT,PATCH,DELETE,OPTIONS Access-Control-Allow-Headers: authorization, content-type Access-Control-Allow-Credentials: true Access-Control-Max-Age: 3600 HTTP/1.1 403 Forbidden Invalid CORS request
Common Mistakes
allowedOrigins("*")withallowCredentials(true): not allowed by browsers, and Spring throws an error. List exact origins (or usesetAllowedOriginPatternslikehttps://*.shopease.in).- Configuring CORS only in a
WebMvcConfigurerbut not callinghttp.cors(...): preflights hit security first and fail with 401. - Forgetting
withCredentials: truein axios: the browser silently does not send the refresh cookie.