Careeroza
CORS
Same-Origin Policy
Browsers block JavaScript on one origin from reading responses from another origin. An origin is scheme + host + port. Your React app on http://localhost:5173 calling http://localhost:8080 is cross-origin, so the browser blocks it unless the API says it is allowed. That permission system is CORS (Cross-Origin Resource Sharing).
Example
Two URLs share an origin only if scheme, host and port all match:
import java.net.URI;
public class Main {
static String origin(String url) {
URI u = URI.create(url);
int port = u.getPort() != -1 ? u.getPort() : (u.getScheme().equals("https") ? 443 : 80);
return u.getScheme() + "://" + u.getHost() + ":" + port;
}
public static void main(String[] args) {
String api = "https://api.shopease.in/products";
String[] pages = {
"https://api.shopease.in/docs",
"https://shopease.in/cart",
"http://api.shopease.in/products",
"https://api.shopease.in:8443/products",
};
for (String page : pages) {
boolean same = origin(page).equals(origin(api));
System.out.printf("%-40s %s%n", page, same ? "same origin" : "CROSS-ORIGIN");
}
}
}Output
https://api.shopease.in/docs same origin https://shopease.in/cart CROSS-ORIGIN http://api.shopease.in/products CROSS-ORIGIN https://api.shopease.in:8443/products CROSS-ORIGIN
Preflight Requests
Example
For non-simple requests (JSON body, Authorization header, PUT/DELETE) the browser first sends an OPTIONS preflight:
curl -i -X OPTIONS localhost:8080/api/orders \
-H "Origin: http://localhost:5173" \
-H "Access-Control-Request-Method: POST" \
-H "Access-Control-Request-Headers: content-type,authorization"Example output
HTTP/1.1 200 Access-Control-Allow-Origin: http://localhost:5173 Access-Control-Allow-Methods: GET,POST,PUT,DELETE Access-Control-Allow-Headers: content-type, authorization Access-Control-Allow-Credentials: true Access-Control-Max-Age: 3600
Enabling CORS With Spring Security
@Bean
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.cors(Customizer.withDefaults()) // uses the CorsConfigurationSource bean below
.authorizeHttpRequests(auth -> auth.anyRequest().authenticated())
.httpBasic(Customizer.withDefaults());
return http.build();
}
@Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration config = new CorsConfiguration();
config.setAllowedOrigins(List.of("http://localhost:5173", "https://shopease.in"));
config.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE"));
config.setAllowedHeaders(List.of("Content-Type", "Authorization"));
config.setAllowCredentials(true);
config.setMaxAge(3600L);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/api/**", config);
return source;
}- Configure CORS in Spring Security (
http.cors(...)), otherwise the preflight is rejected with 401 before it reaches your@CrossOrigincontroller. - Never use
"*"as an allowed origin together with credentials. - CORS is a browser protection. curl and Postman ignore it, and it does not replace authentication.