Configuring CORS with Spring Boot

In this post, I will cover how to configure CORS in a Spring Boot project. If you want to understand how CORS works, you can check out the article Understanding CORS.

Configuring HTTP Request CORS

Controller CORS Configuration

Use @CrossOrigin annotation

Add a @CrossOrigin annotation to the controller class

// no credentials
@CrossOrigin
@RestController
@RequestMapping("/my")
public class MyController {
@GetMapping
public String testGet() {
return "hello \n" + new Date();
}
}

Add a @CrossOrigin annotation to the controller method

@RestController
@RequestMapping("/my")
public class MyController {
// no credentials
@CrossOrigin
@GetMapping
public String testGet() {
return "hello \n" + new Date();
}
}
// with credentials
@CrossOrigin(origins = {"http://localhost"}, allowCredentials = "true")
// or
@CrossOrigin(originPatterns = {"http://localhost:[*]"}, allowCredentials = "true")

Properties of CrossOrigin

  • origins: by default, it’s *. You can specify allowed origins like @CrossOrigin(origins = {"http://localhost"}). You also can specify allowed origins by patterns like @CrossOrigin(originPatterns = {"http://*.taogen.com:[*]"}).

Add a @CrossOrigin annotation to the controller method or the controller class. It is equivalent to

  1. responding a successful result to the preflight request. For example

    HTTP/1.1 204 No Content
    Connection: keep-alive
    Access-Control-Allow-Origin: https://foo.bar.org
    Access-Control-Allow-Methods: POST, GET, OPTIONS, DELETE, PUT
    Access-Control-Max-Age: 86400
  2. adding the following headers to the HTTP response headers

    Access-Control-Allow-Origin: *
    Vary: Access-Control-Request-Headers
    Vary: Access-Control-Request-Method
    Vary: Origin

Update HTTP response headers

Only for GET, POST and HEAD requests without custom headers. In other words, it does not work for preflight requests.

@RestController
@RequestMapping("/my")
public class MyController {

@GetMapping
public String testGet(HttpServletResponse response) {
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Max-Age", "86400");
return "test get\n" + new Date();
}

@PostMapping
public String testPost(HttpServletResponse response) {
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Max-Age", "86400");
return "test post\n" + new Date();
}
}
// with credentials
response.setHeader("Access-Control-Allow-Origin", "{your_host}"); // e.g. http://localhost or reqs.getHeader("Origin")
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Max-Age", "86400");

For ‘DELETE + Preflight’ or ‘PUT + Preflight’ requests, adding header ‘Access-Control-Allow-Origin: *’ to HttpServletResponse does not enable CORS. This will result in the following error

Access to XMLHttpRequest at 'http://localhost:8080/my' from origin 'http://localhost' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.

For requests with custom headers, adding header ‘Access-Control-Allow-Origin: *’ to HttpServletResponse does not enable CORS. This will result in the following error

Access to XMLHttpRequest at 'http://localhost:8080/my' from origin 'http://localhost' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.

Global CORS configuration

WebMvcConfigurer.addCorsMappings

The WebMvcConfigurer.addCorsMappings has the same function as the @CrossOrigin annotation.

@Configuration
public class CorsConfiguration {
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
@Override
public void addCorsMappings(CorsRegistry registry) {
// no credentials
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("GET", "POST", "HEAD", "PUT", "DELETE", "PATCH");
}
};
}
}
// with credentials
registry.addMapping("/**")
.allowedOrigins("{your_host}") // e.g. http://localhost
.allowCredentials(true)
.allowedMethods("GET", "POST", "HEAD", "PUT", "DELETE", "PATCH");
  • pathPattern: /myRequestMapping, /**, /myRequestMapping/**, /*
  • allowedOrigins: By default, all origins are allowed. Its default value is *. You can specify allowed origins like "http://localhost".
  • allowedOriginPatterns: for example, http://localhost:[*], http://192.168.0.*:[*], https://demo.com
  • allowedMethods: By default, GET, HEAD, and POST methods are allowed. You can enable all methods by setting its value to "GET", "POST", "HEAD", "PUT", "DELETE", "PATCH".

Filters

@Component
public class CorsFilter implements Filter {

@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) res;
HttpServletRequest reqs = (HttpServletRequest) req;
// no credentials
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, PATCH, DELETE, PUT, PATCH");
response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
response.setHeader("Access-Control-Max-Age", "86400");
chain.doFilter(req, res);
}
}
// with credentials
response.setHeader("Access-Control-Allow-Origin", "{your_host}"); // e.g. http://localhost or reqs.getHeader("Origin")
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, DELETE, PUT, PATCH");
response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
response.setHeader("Access-Control-Max-Age", "86400");