web-services

Cross-Origin Resource Sharing (CORS) with Spring

Cross-Origin Resource Sharing (CORS) with Spring

The Spring team has made CORS implementation much easier in recent versions of Spring, so I’ll try to simply not repeat what the docs already cover.

Deconstructing the AJAX Request

The basic idea of CORS is to declaratively allow client applications to make AJAX requests originating outside of the service application’s domain. By default, if CORS is not setup, then no requests originating outside of the domain will be permitted. When a client application makes an AJAX request, the browser initially sends a preflight OPTIONS request to determine what the client is permitted to do. This is true for all requests except a GET request. The server response to the OPTIONS request contains headers that instruct the browser on what the client is allowed to do when making the actual AJAX request. These response headers each serve a specific purpose.

The first header is Access-Control-Allow-Origin which tells the browser which origins can make AJAX requests. The value of this header could be * which indicates all origins can make requests, or it could contain an actual domain such as http://example.com which specifies only requests originating from http://example.com are permitted.

Next is the Access-Control-Expose-Headers header which tells the browser which headers it is allowed to access when receiving responses from the server.

The Access-Control-Max-Age header is used to tell the browser how long it can cache the results of the OPTIONS request in seconds. Setting this value to a reasonable amount of time means the browser won’t need to make an OPTIONS request every time until the time expires.

The Access-Control-Allow-Credentials is a bit more interesting. This header tells the browser if the response to the AJAX request can be exposed to the client when the credentials flag is set to true on the AJAX request. This header also allows the client to send cookies to the server, such as authentication cookies. When a client makes an AJAX request with credentials set to true, the response from the server must contain the Access-Control-Allow-Credentials with value true, otherwise the response is ignored by the browser and not available to the client. This has certain implications when making CORS GET requests. Like I mentioned earlier, a GET request does not invoke an OPTIONS preflight request first. So when making a GET request with credentials set to true, the server must respond with the header Access-Control-Allow-Credentials set to true as well in order for the response to be made available to the client. Another point to note is if the Access-Control-Allow-Credentials is set to true, then the Access-Control-Allow-Origin header coming back from the server must not contain the wildcard *. It must contain an actual domain, otherwise the browser will ignore the response.

The Access-Control-Allow-Methods header tells the browser which methods are permitted when making an AJAX request. This header can contain 1 or more methods, ie: GET, POST, etc.

The Access-Control-Allow-Headers header tells the browser which headers can be used when making an AJAX request.

CORS Global Configuration

When I originally wrote this post, I attempted to keep CORS configuration out of my controllers. Although Spring has made adding CORS to a controller much cleaner, I’ll talk about global configuration first which has also seen it’s fair share of improvements. The following global configuration enables CORS requests from any origin to any endpoint in the application.

@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
  @Override
  public void addCorsMappings(CorsRegistry registry) {
    registry.addMapping("/**");
  }
}

If you want to lock this down a bit more, the registry.addMapping method returns a CorsRegistration object which can be used for additional configuration. There’s an allowedOrigins method which you can use to specify an array of allowed origins. This can be useful if you need to load this array from an external source at runtime. There’s also allowedMethods, allowedHeaders, exposedHeaders, maxAge and allowCredentials which can be used to set the response headers as I’ve described them above.

CORS Fine Grain Configuration

Spring has recently added the @CrossOrigin annotation which can be used in controllers. This allows for a more fine grain configuration.

@RestController
@RequestMapping("/orders")
public class OrderController {
  @CrossOrigin
  @RequestMapping(value = "/{orderNumber}", method = RequestMethod.GET)
  public Order order(@PathVariable long orderNumber) {
    // lookup the order and return it
  }
}

As you can see, all we’ve done here is add the @CrossOrigin annotation to an ordinary request mapping method. With no additional attributes, this would expose the /orders/{orderNumber} endpoint to any origin. You may also use a combination of controller level and method level annotations. As a result, Spring combines the controller level and method level annotations when building the response headers. The @CrossOrigin annotation also contains attributes very similar to the the global configuration methods, such as origins, methods, allowedHeaders, exposedHeaders, maxAge and allowCredentials.

Conclusion

Hopefully I’ve done a better job explaining CORS concepts in this updated post. As well I hope that I’ve shown you how much simpler it is to configure CORS in a Spring application using all the improvements that have been made.

Happy Coding!

Posted by Patrick Grimard in Programming, 0 comments