Cross-Origin Resource Sharing (CORS) is a security feature implemented by web browsers to control how web pages in one domain can request and interact with resources from another domain. While essential for security, sometimes it can become a source of frustration for developers while integrating frontend and backend.
In this guide, we'll explain what CORS is, how it works, and how to configure it in a Java Spring backend.
CORS is a mechanism that uses additional HTTP headers to tell browsers to give a web application running at one origin/domain, access to selected resources from a different origin.
For security reasons, browsers restrict cross-origin HTTP requests initiated from scripts. For example, XMLHttpRequest
and the Fetch API
follow the same-origin policy. This means that a web application using those APIs can only request resources from the same origin the application was loaded from, unless the response from the other origin includes the right CORS headers.
The target API server can be configured to allow calls only from specific domains. When configured this way, requests from the allowed domain succeed, while requests from other domains are blocked by the browser's security policy.
For certain types of cross-origin requests, the browser sends a "preflight" request before the actual request. This is an OPTIONS
request sent to the resource on the other origin/domain, to determine if the actual request is safe to send.
The preflight request includes headers that describe the actual request, such as:
Access-Control-Request-Method
: The HTTP method of the actual request (e.g., POST
, PUT
, DELETE
).Access-Control-Request-Headers
: The headers that will be sent with the actual request.The server then responds to the preflight request with information about what it will allow:
Access-Control-Allow-Origin
: The origin that is allowed to make the request.Access-Control-Allow-Methods
: The HTTP methods that are allowed.Access-Control-Allow-Headers
: The headers that are allowed.Access-Control-Max-Age
: How long the results of the preflight request can be cached.If the server's response indicates that the actual request is allowed, the browser then sends the actual request.
Now, let's look at how to configure CORS in a Spring Boot application to allow requests from our frontend.
The most common and powerful way to configure CORS in a Spring application is through a global configuration. This allows you to define your CORS policy in a single place.
Create a WebConfig
class that implements the WebMvcConfigurer
interface:
import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.CorsRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration public class WebConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedOrigins("http://localhost:3000") .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS") .allowedHeaders("*") } }
In this configuration:
addMapping("/**")
: Applies the CORS configuration to all endpoints in the application.allowedOrigins("http://localhost:3000")
: Allows requests from the frontend application running on http://localhost:3000
.allowedMethods(...)
: Specifies the allowed HTTP methods.allowedHeaders("*")
: Allows all headers.You can also configure CORS at the controller level using the @CrossOrigin
annotation. This is useful if you want to apply different CORS policies to different controllers.
import org.springframework.web.bind.annotation.CrossOrigin; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController @CrossOrigin(origins = "http://localhost:3000") public class MyController { @GetMapping("/api/data") public String getData() { return "Some data from the backend"; } }
The @CrossOrigin
annotation on the controller applies the specified CORS policy to all handler methods in that controller.
For even more granular control, you can apply the @CrossOrigin
annotation to individual handler methods.
import org.springframework.web.bind.annotation.CrossOrigin; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class MyController { @CrossOrigin(origins = "http://localhost:3000") @GetMapping("/api/data") public String getData() { return "Some data from the backend"; } @GetMapping("/api/other-data") public String getOtherData() { // This endpoint does not have CORS enabled return "Some other data"; } }
When using Spring Security, you can configure CORS using the CorsConfiguration
class for more fine-grained control. This approach is particularly useful when you need to integrate CORS with your security configuration.
@Configuration @EnableWebSecurity public class SecurityConfig { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http .cors(cors -> cors.configurationSource(corsConfigurationSource())) .authorizeHttpRequests(authz -> authz .requestMatchers("/api/public/**").permitAll() .anyRequest().authenticated() ) .csrf(csrf -> csrf.disable()); return http.build(); } @Bean public CorsConfigurationSource corsConfigurationSource() { CorsConfiguration configuration = new CorsConfiguration(); // Allow specific origins configuration.setAllowedOriginPatterns(Arrays.asList("http://localhost:3000", "https://yourdomain.com")); // Allow specific HTTP methods configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS")); // Allow specific headers configuration.setAllowedHeaders(Arrays.asList("Authorization", "Content-Type", "X-Requested-With")); // Allow credentials configuration.setAllowCredentials(true); // Set max age for preflight requests configuration.setMaxAge(3600L); // Expose headers to the client configuration.setExposedHeaders(Arrays.asList("Authorization", "Content-Length")); UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration("/**", configuration); return source; } }
CORS is a vital security feature, but it doesn't have to be a roadblock in your development process. By understanding how it works and how to configure it properly in your Spring backend, you can build secure and robust web applications with a separate frontend and backend.
Remember to be specific with your allowedOrigins
in a production environment to maintain security. Using a wildcard (*
) is generally not recommended for production applications that handle sensitive data.
Learn how to implement JWT authentication with Spring 6 Security following best practices recommended in Spring docs and without custom filters.
This guide explores the features and usage of the RestClient introduced in Spring 6, providing a modern and fluent API for making HTTP requests. It demonstrates how to create and customize RestClient instances, make API calls, and handle responses effectively.
Get instant AI-powered summaries of YouTube videos and websites. Save time while enhancing your learning experience.