CORS Explained for Java and Spring Developers

    CORS Explained for Java and Spring Developers

    11/08/2025

    Introduction

    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.

    What is CORS?

    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.

    CORS Architecture

    How CORS Works

    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.

    CORS Flow

    Configuring CORS in a Java Spring Backend

    Now, let's look at how to configure CORS in a Spring Boot application to allow requests from our frontend.

    1. Global CORS Configuration

    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.

    2. Controller-Level CORS Configuration

    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.

    3. Handler-Method-Level CORS Configuration

    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"; } }

    4. CORS Configuration with Spring Security

    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.

    Basic Spring Security CORS 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; } }

    Conclusion

    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.

    Summarise

    Transform Your Learning

    Get instant AI-powered summaries of YouTube videos and websites. Save time while enhancing your learning experience.

    Instant video summaries
    Smart insights extraction
    Channel tracking