Enabling CORS in Spring Data REST

Tutorial on enabling, configuring, and customizing Cross Origin Resource Sharing (CORS) in Spring Data REST resources with examples.

Overview

Spring Data REST help us build RESTFul Web Services, while avoiding boilerplate components. As there are no boilerplate code blocks, the applications are less error-prone as well as they are fast is building.

In this tutorial we will study the Cross Origin Resource Sharing (CORS) support in Spring Data REST applications.

Without CORS in Spring Data REST

Almost all of the modern browsers disallow AJAX requests to be made to resources that exists on a different domain.

In order to understand that, consider an imaginary website – http://example.com hosts a page. When the page is loaded in browser it fetches students information from a data service, which is located at http://data.example.com.

As shown, the page trying to fetch a list of students from the data service.

var request = new XMLHttpRequest();
request.open("GET", "http://data.example.com/students", false);
request.send();
loadData(request.responseText);Code language: JavaScript (javascript)

As this request is a cross-domain request, browser expects an Access Control Header in the response of data service. If that is not found, the browser does not deliver the response to the web page. Thus, on the browser console we can see an error similar to this.

Access Control Headers

Cross Origin Resource Sharing is driven by access control headers that are sent by the server. Firstly, when a page makes a cross origin request, the browser inserts Origin header into the request. The value is the domain from where the request is being made.

Origin: http://www.example.com

Server can read this header value, and if it wish to share resources with the domain, it adds Access-Control-Allow-Origin (ACAO) header in the response.

Access-Control-Allow-Origin: http://www.example.com

Once, the header value contains the webpage origin, browser serves the response to the page. Else, it throws error as shown in the above screenshot. In our case we haven’t configured our Data Service to include ACAO Header in the response thus the page in browser is getting this error.

Spring Data REST CORS Support

Spring Data REST framework supports setting CORS configuration on the repository resources. Basically, Spring Web provides @CrossOrigin annotation that is added on controllers and then Spring will automatically insert the ACAO Header in the response. Spring Data REST seamlessly supports this annotation.

However as Spring Data REST doesn’t need controllers, we can put these annotations directly on the Repository interface. Having done that, Spring Data REST will allow Cross Origin Resource Sharing access for the respective repository resource.

Alternatively, we can also enable CORS using a Filter. A filter can intercept requests and response, thus we can insert the header manually.

In the next sections, we will cover a different ways of adding CORS configuration in Spring Data REST. For the purpose of demonstration, we will reuse the Spring Data REST Example Application that we developed previously. You can start this application locally and using hosts file in your machine, assign a domain name to your localhost

Enable CORS on Repository REST Resource

Spring Web provides @CrossOrigin annotation where we can specify permitted domains. We can use this annotation on the Spring Data REST @RepositoryRestResource interface.

Using the @CorssOrigin annotation on a repository interface enables CORS access to all operations on the repository resource.

@RepositoryRestResource
@CrossOrigin("http://example.com")
public interface StudentRepository
        extends CrudRepository<Student, Long> {
}Code language: Java (java)

Once, this is added the server will automatically insert the header Access Control Allow Origin into the response with the value of http://example.com.

Let’s execute a curl request and test that.

$ curl -i \
   -H "Origin: http://example.com" \
   -X GET 'http://data.example.com/students/'

HTTP/1.1 200
Vary: Origin
Access-Control-Allow-Origin: http://example.com
Content-Type: application/hal+json
Transfer-Encoding: chunked
// Skipped Lines ... 
Code language: Bash (bash)

Enable CORS on Specific Methods

In the previous example, we added the @CrossOrigin annotation on the Repository interface. That, by default enables CORS on all the methods (HTTP Operations) exposed by the repository.

In case cases, we may want to allow access over a certain of methods. For example HTTP GET is allowed to be accessed from across the origin while others are not. To do that, we can use

@RepositoryRestResource
@CrossOrigin(
        origins = "http://example.com",
        methods = RequestMethod.GET)
public interface StudentRepository
        extends CrudRepository<Student, Long> {
}Code language: PHP (php)

Now, the client at origin http://example.com will only be able to access GET /students or GET /students{id} endpoints. Rest of the methods will be prohibited by the browsers.

Specifying Multiple Origins

The @CrossOrigin also allows to specify an array of origins. This is useful when the server wants to share a resource with multiple client domains.

@RepositoryRestResource
@CrossOrigin(origins = {"http://example.com", "http://example2.com"})
public interface StudentRepository
        extends CrudRepository<Student, Long> {
}Code language: Java (java)

Having this, we can send a request from Origin http://example2.com and receive the server response.

$ curl -i \
   -H "Origin: http://example2.com" \
   -X GET 'http://data.example.com/students/'

HTTP/1.1 200
Vary: Origin
Access-Control-Allow-Origin: http://example2.com
// Skipped Lines ... Code language: Bash (bash)

That shows the ACAO header correctly specifies the newly added origin.

CORS Access to All Origins

If we want a resource to be accessible from any origin we can simply use asterisk (*) in the @CrossOrigin annotation.

@RepositoryRestResource
@CrossOrigin(origins = "*")
public interface StudentRepository
        extends CrudRepository<Student, Long> {
}Code language: Java (java)

Enable CORS Globally

So far, we have used the @CorssOrigin annotation on specific repository classes. However, if we wish to configure CORS support on multiple repositories, we will have to duplicate the configurations.

To avoid that, Spring Data REST offers a programatic way of setting CORS configuration globally. We can provide custom implementation of RepositoryRestConfigurer and customize the CorsRegistry.

@Component
public class SpringDataRestConfig
    implements RepositoryRestConfigurer {

  @Override
  public void configureRepositoryRestConfiguration(
      RepositoryRestConfiguration config, CorsRegistry cors) {

    cors.addMapping("/*")
        .allowedOrigins("*")
        .allowedMethods("GET", "PUT", "DELETE")
        .allowCredentials(false).maxAge(3600);
  }
}Code language: Java (java)

With is the CORS is enabled on the application level and it is applicable to all the repository resources.

Enable CORS using Filters

Another way to configure the CORS globally it to use traditional Filter implementations. To do that we can provide Filter implementation and override doFilter method.

@Component
public class StudentsFilter implements Filter {
  @Override
  public void doFilter(
      ServletRequest servletRequest,
      ServletResponse servletResponse,
      FilterChain filterChain) throws IOException, ServletException {

    HttpServletResponse response = (HttpServletResponse) servletResponse;
    response.addHeader("Access-Control-Allow-Origin", "http://example.com");

    filterChain
      .doFilter(servletRequest, servletResponse);
  }
}Code language: Java (java)

Inside the filter we are setting the Access-Control-Allow-Origin header manually on the HttpServletResponse object.

Summary

In this tutorial we covered a different ways of Enabling CORS access in Spring Data REST application. Firstly, we demonstrated why the CORS setting is important when a page in browser tries to access a resource from a different domain.

Next, we covered how to use Spring Data REST @CrossOrigin annotation to specify the domains that are allowed to access respective Repository REST Resources. In the last sections we demonstrated how to enable CORS configuration globally using a RepositoryRestConfigurer or using Filter implementation.

Refer to our Github Repository for a full source code of Spring Data REST based CRUD Application.