How to add CORS support on the server side in Java with Jersey


Codever Logo

(P) Codever is an open source bookmarks and snippets manager for developers & co. See our How To guides to help you get started. Public bookmarks repos on Github ⭐🙏


In this post I will present how easy it is to enable HTTP response headers on the server sidein Java with Jersey, as defined by the Cross-Origing Resource Sharing (CORS) specification. For that I have extended the REST API  built in the post Tutorial – REST API design and implementation in Java with Jersey and Spring, with CORS support.

But before we delve into that, I would like to start with a quick introduction to CORS as found on various great website like Wikipedia or Mozilla Development Network (MDN), I would myself like to reference later.

1. Quick intro to CORS

Well, according to Wikipedia:

“Cross-origin resource sharing (CORS) is a mechanism that allows JavaScript on a web page to make XMLHttpRequests to another domain, not the domain the JavaScript originated from. Such “cross-domain” requests would otherwise be forbidden by web browsers, per the same origin security policy. CORS defines a way in which the browser and the server can interact to determine whether or not to allow the cross-origin request. It is more useful than only allowing same-origin requests, but it is more secure than simply allowing all such cross-origin requests.” [1]

1.1. Overview

“The Cross-Origin Resource Sharing standard works by adding new HTTP headers that allow servers to describe the set of origins that are permitted to read that information using a web browser.  Additionally, for HTTP request methods that can cause side-effects on user data (in particular, for HTTP methods other than GET, or for POST usage with certain MIME types), the specification mandates that browsers “preflight” the request, soliciting supported methods from the server with an HTTP OPTIONS request method, and then, upon “approval” from the server, sending the actual request with the actual HTTP request method.  Servers can also notify clients whether “credentials” (including Cookies and HTTP Authentication data) should be sent with requests.” [2]

The OPTIONS method represents a request for information about the communication options available on the request/response chain identified by the Request-URI. This method allows the client to determine the options and/or requirements associated with a resource, or the capabilities of a server, without implying a resource action or initiating a resource retrieval.[7]

1.2. CORS HTTP headers

The HTTP headers as defined by CORS are:

1.2.1. Client/Browser side – HTTP request headers

These are headers that clients may use when issuing HTTP requests in order to make use of the cross-sharing feature:

  • Origin: URI indicating the server from which the request initiated.  It does not include any path information, but only the server name.
  • Access-Control-Request-Headers:  used when issuing a preflight request to let the server know what HTTP headers will be used when the actual request is made.
  • Access-Control-Request-Method: used when issuing a preflight request to let the server know what HTTP method will be used when the actual request is made.
  • 1.2.2. Server side – HTTP response headers

    These are the HTTP headers that the server sends back for access control requests as defined by the Cross-Origin Resource Sharing specification:

  • Access-Control-Allow-Origin: specifies the authorized domains to make cross-domain request (you should include the domains of your REST clients or “*” if you want the resource public and available to everyone – the latter is not an option if credentials are allowed during CORS requests)
    • Access-Control-Expose-Headers: lets a server white list headers that browsers are allowed to access
    • Access-Control-Max-Age:  indicates how long the results of a preflight request can be cached.
    • Access-Control-Allow-Credentials: indicates if the server allows credentials during CORS requests
    • Access-Control-Allow-Methods: indicates the methods allowed when accessing the resource
    • Access-Control-Allow-Headers:  used in response to a preflight request to indicate which HTTP headers can be used when making the actual request.

    2. Adding HTTP headers to resources with Jersey

    In this post, because we are concerned with the server side of things, I will only use the Access-Control-Allow-OriginAccess-Control-Allow-Methods and Access-Control-Allow-Headers response headers.

    There are two ways to add headers to a response with Jersey:

    2.1. Response and ResponseBuilder

    The first one is by using the header method of the javax.ws.rs.core.Response. This method adds an arbitrary header to the ResponseBuilder (ResponseBuilder is a class used to build Response instances that contain metadata instead of or in addition to an entity):

    @GET
    @Path("{id}")
    @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
    public Response getPodcastById(@PathParam("id") Long id, @QueryParam("detailed") boolean detailed)
    		throws IOException,	AppException {
    	Podcast podcastById = podcastService.getPodcastById(id);
    	return Response.ok() //200
    			.entity(podcastById, detailed ? new Annotation[]{PodcastDetailedView.Factory.get()} : new Annotation[0])
    			.header("Access-Control-Allow-Origin", "*")
    			.header("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT")
    			.allow("OPTIONS").build();
    }
    

    As you can see on lines 9 and 10, the header method extends the existing ResponseBuilder and adds the HTTP headers Access-Control-Allow-Origin  and Access-Control-Allow-Methods, suggesting that GET requests coming from any domain will be allowed for the resource identified by this method – /podcasts/{id}

    Note: The javax.ws.rs.core.Response has also a ResponseBuilder allow(String... methods) method, that you could also use to set the list of allowed methods for the resource.

    2.2.  ContainerResponseFilter

    Another way to add the headers to the response is by using Jersey filters, which can modify inbound and outbound requests and responses including modification of headers, entity and other request/response parameters.

    I think this is the better way to do it, especially if you want to expose the same HTTP headers in the response, for all the resources of the API – this is a sort of a cross-cutting concern capability powered by Jersey filters.

    Ok, so let’s see how this works:

    package org.codingpedia.demo.rest.util;
    
    import java.io.IOException;
    
    import javax.ws.rs.container.ContainerRequestContext;
    import javax.ws.rs.container.ContainerResponseContext;
    import javax.ws.rs.container.ContainerResponseFilter;
    import javax.ws.rs.core.MultivaluedMap;
    
    public class CORSResponseFilter
    implements ContainerResponseFilter {
    
    	public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext)
    			throws IOException {
    
    		MultivaluedMap<String, Object> headers = responseContext.getHeaders();
    
    		headers.add("Access-Control-Allow-Origin", "*");
    		//headers.add("Access-Control-Allow-Origin", "https://podcastpedia.org"); //allows CORS requests only coming from podcastpedia.org
    		headers.add("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT");
    		headers.add("Access-Control-Allow-Headers", "X-Requested-With, Content-Type, X-Codingpedia");
    	}
    
    }
    

    In the example above the CORSResponseFilter always  adds

  • Access-Control-Allow-Origin header to the response(line 18). The  “*” means the request can come from any domain – this is the way to set this header if you want to make your REST API public where everyone can access it
  • Access-Control-Allow-Methods header to the response (line 20), which indicates that GET, POST, DELETE, PUT methods are allowed when accessing the resource
  • Access-Control-Allow-Headers header to the response (line 21), which indicates that the  X-Requested-With, Content-Type, X-Codingpedia headers can be used when making the actual request.
  • The filter must inherit from the ContainerResponseFilter interface and must be registered as a provider:

    /**
    * Register JAX-RS application components.
    */
    public RestDemoJaxRsApplication(){
       register(CORSResponseFilter.class);
       //other registrations omitted for brevity
    }
    

    Well, that’s it – you’ve learned how easy it is to add CORS support to the server side with Jersey.

    Thanks for sharing and connecting with us.

    3. Resources

    3.1. Source code – GitHub

    3.2. Web

    1. Wikipedia – Cross-origin resource sharing
    2. MDN – HTTP access control (CORS)
    3. W3C Recommendation – Cross-Origin Resource Sharing
    4. Cross-domain Ajax with Cross-Origin Resource Sharing
    5. MDN – XMLHttpRequest
    6. What’s the point of X-Requested-With header?
    7. HTTP 1.1 – RFC2616
    Podcastpedia image

    Adrian Matei

    Creator of Podcastpedia.org and Codepedia.org, computer science engineer, husband, father, curious and passionate about science, computers, software, education, economics, social equity, philosophy - but these are just outside labels and not that important, deep inside we are all just consciousness, right?
    Subscribe to our newsletter for more code resources and news

    Adrian Matei (aka adixchen)

    Adrian Matei (aka adixchen)
    Life force expressing itself as a coding capable human being

    routerLink with query params in Angular html template

    routerLink with query params in Angular html template code snippet Continue reading