How to enable Cross domain requests on JAX-RS web services?

CorsJax RsCross DomainJava Ee-7Wildfly 8

Cors Problem Overview


I developed a set of restful web services. I couldn't call any of these methods from remote clients due to the error No 'Access-Control-Allow-Origin' header is present on the requested resource.

The services work perfectly on localhost. Is there any changes or configs to do on the server side to resolve the issue. i.e. to enable cross domain requests.

I'm using WildFly 8, JavaEE 7

Cors Solutions


Solution 1 - Cors

I was wondering the same thing, so after a bit of research I found that the easiest way was simply to use a JAX-RS ContainerResponseFilter to add the relevant CORS headers. This way you don't need to replace the whole web services stack with CXF (Wildfly uses CXF is some form, but it doesn't look like it uses it for JAX-RS maybe only JAX-WS).

Regardless if you use this filter it will add the headers to every REST webservice.

package com.yourdomain.package;

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.ext.Provider;

@Provider
public class CORSFilter implements ContainerResponseFilter {

   @Override
   public void filter(final ContainerRequestContext requestContext,
                      final ContainerResponseContext cres) throws IOException {
      cres.getHeaders().add("Access-Control-Allow-Origin", "*");
      cres.getHeaders().add("Access-Control-Allow-Headers", "origin, content-type, accept, authorization");
      cres.getHeaders().add("Access-Control-Allow-Credentials", "true");
      cres.getHeaders().add("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS, HEAD");
      cres.getHeaders().add("Access-Control-Max-Age", "1209600");
   }

}

Then when I tested with curl, the response had the CORS headers:

$ curl -D - "http://localhost:8080/rest/test"
HTTP/1.1 200 OK
X-Powered-By: Undertow 1
Access-Control-Allow-Headers: origin, content-type, accept, authorization
Server: Wildfly 8
Date: Tue, 13 May 2014 12:30:00 GMT
Connection: keep-alive
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
Transfer-Encoding: chunked
Content-Type: application/json
Access-Control-Max-Age: 1209600
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS, HEAD

My understanding is that it's the @Provider annotation that tells the JAX-RS runtime to use the filter, without the annotation nothing happens.

I got the idea about using the ContainerResponseFilter from a Jersey example.

Solution 2 - Cors

I was facing a similar problem, and had tried to use @Alex Petty's solution, but apart from having to set the CORS headers on each JAX-RS endpoint in my class, as such:

@GET
@Produces(MediaType.APPLICATION_JSON)
public Response getMemberList() {
    List<Member> memberList = memberDao.listMembers();
    members.addAll(memberList);
    return Response
            .status(200)
            .header("Access-Control-Allow-Origin", "*")
            .header("Access-Control-Allow-Headers", "origin, content-type, accept, authorization")
            .header("Access-Control-Allow-Credentials", "true")
            .header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS, HEAD")
            .header("Access-Control-Max-Age", "1209600")
            .entity(memberList)
            .build();
}

I had to further define a catch-all OPTIONS endpoint that would return the CORS headers for any other OPTIONS request in the class, and thus catch all endpoint of the sort:

@OPTIONS
@Path("{path : .*}")
public Response options() {
    return Response.ok("")
            .header("Access-Control-Allow-Origin", "*")
            .header("Access-Control-Allow-Headers", "origin, content-type, accept, authorization")
            .header("Access-Control-Allow-Credentials", "true")
            .header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS, HEAD")
            .header("Access-Control-Max-Age", "1209600")
            .build();
}

Only after doing this, could I properly use my JAX-RS API endpoints from Jquery Ajax clients on other domains or hosts.

Solution 3 - Cors

I found an even easier (RestEasy-specific) way to enable CORS on Wildfly without using a filter and where you can control your APIs response header configuration at the resource level.

For example:

@GET
@Produces(MediaType.APPLICATION_JSON)
public Response getMemberList() {
    List<Member> memberList = memberDao.listMembers();
    members.addAll(memberList);
    return Response
            .status(200)
            .header("Access-Control-Allow-Origin", "*")
            .header("Access-Control-Allow-Headers", "origin, content-type, accept, authorization")
            .header("Access-Control-Allow-Credentials", "true")
            .header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS, HEAD")
            .header("Access-Control-Max-Age", "1209600")
            .entity(memberList)
            .build();
}

Solution 4 - Cors

I have had good luck configuring Cross-origin resource sharing (CORS) for my API (on Wildfly) by using this lib:

<dependency>
<groupId>com.thetransactioncompany</groupId>
<artifactId>cors-filter</artifactId>
<version>2.1</version>
</dependency>

It's very easy to setup. Just add the above dependency to your pom and then add the following config to the webapp section of your web.xml file.

<filter>
	<filter-name>CORS</filter-name>
	<filter-class>com.thetransactioncompany.cors.CORSFilter</filter-class>

	<init-param>
		<param-name>cors.allowGenericHttpRequests</param-name>
		<param-value>true</param-value>
	</init-param>
	
	<init-param>
		<param-name>cors.allowOrigin</param-name>
		<param-value>*</param-value>
	</init-param>
	
	<init-param>
		<param-name>cors.allowSubdomains</param-name>
		<param-value>false</param-value>
	</init-param>
	
	<init-param>
		<param-name>cors.supportedMethods</param-name>
		<param-value>GET, HEAD, POST, DELETE, OPTIONS</param-value>
	</init-param>
	
	<init-param>
		<param-name>cors.supportedHeaders</param-name>
		<param-value>*</param-value>
	</init-param>
	
	<init-param>
		<param-name>cors.supportsCredentials</param-name>
		<param-value>true</param-value>
	</init-param>
	
	<init-param>
		<param-name>cors.maxAge</param-name>
		<param-value>3600</param-value>
	</init-param>

</filter>

<filter-mapping>
	<!-- CORS Filter mapping -->
	<filter-name>CORS</filter-name>
	<url-pattern>*</url-pattern>
</filter-mapping>

You can also configure it with a properties file instead if you prefer. This lib works like a charm and gives you a lot of configuration flexibility!

Solution 5 - Cors

None of the other answers worked for me, but this did:

import javax.ws.rs.core.Response;

Then change the return type of the service method to Response, and change the return statement to:

return Response.ok(resp).header("Access-Control-Allow-Origin", "*").build();

Where resp is the original response object.

Solution 6 - Cors

You can also implement javax.ws.rs.core.Feature as below to implement CORS.

import javax.ws.rs.core.Feature;
import javax.ws.rs.core.FeatureContext;
import javax.ws.rs.ext.Provider;
import org.jboss.resteasy.plugins.interceptors.CorsFilter;

@Provider
 public class CorsFeature implements Feature {

  @Override
  public boolean configure(FeatureContext context) {
    CorsFilter corsFilter = new CorsFilter();
    corsFilter.getAllowedOrigins().add("*");
    context.register(corsFilter);
    return true;
 }

}

Solution 7 - Cors

The solution for this adds some header on the response. In spring or spring boot have annotations, but in the older system, there are maybe no annotations. You can solve with adding a filter.

Filter class:

package com.koushik.restapis.intercepter;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;


public class RestCorsFilter implements Filter {

	@Override
	public void destroy() {
    enter code here
	}

	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
			throws IOException, ServletException {
	
		HttpServletResponse resp = (HttpServletResponse) response;
		resp.addHeader("Access-Control-Allow-Origin", "*");
		resp.addHeader("Access-Control-Allow-Headers", "*");
		resp.addHeader("Access-Control-Allow-Methods", "*");
		
		chain.doFilter(request, resp);
		
	}

	@Override
	public void init(FilterConfig arg0) throws ServletException {
		
	}

}

web.xml

  <filter>
	<filter-name>RestCorsFilter</filter-name>
	<filter-class>com.koushik.restapis.RestCorsFilter</filter-class>
  </filter>
	<filter-mapping>
	<filter-name>RestCorsFilter</filter-name>
	<url-pattern>/apis/*</url-pattern>
  </filter-mapping>

Solution 8 - Cors

Just to add something to other responses. Allowing * is a little bit dangerous. What can be done is configuring a database of the allowed origin (it can be a file)

Then when the request arrive you can do:

// this will return you the origin 
String[] referers = requestContext.getHeaders().get("referer")

// then search in your DB if the origin is allowed
if (referers != null && referers.lenght == 1 && isAllowedOriging(referers[0])) {
        containerResponseContext.getHeaders().add("Access-Control-Allow-Origin", referers[0]);
		containerResponseContext.getHeaders().add("Access-Control-Allow-Headers", "origin, content-type, accept, authorization, <HERE PUT YOUR DEDICATED HEADERS>);
		containerResponseContext.getHeaders().add("Access-Control-Allow-Credentials", "true");
		containerResponseContext.getHeaders().add("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS, HEAD");
		containerResponseContext.getHeaders().add("Access-Control-Max-Age", "1209600");
}

In that way you won't allow everyone.

Solution 9 - Cors

@Joel Pearson answer helped but for someone who is new to JAX-RS like me and is running the service on tomcat by configuring web.xml should be careful while creating the class and putting it anywhere in the project. See the package you specified in under for jersey and create this filter class there. That way it worked for me.

Solution 10 - Cors

I had this problem recently and solved it but basically create a filter that implements ContainerResponseFilter and add the CORS headers as below:

@Override
    public void filter(ContainerRequestContext containerRequestContext, ContainerResponseContext containerResponseContext) throws IOException {
        containerResponseContext.getHeaders().add(
                "Access-Control-Allow-Origin", "*");
        containerResponseContext.getHeaders().add(
                "Access-Control-Allow-Credentials", "true");
        containerResponseContext.getHeaders().add(
                "Access-Control-Allow-Headers",
                "origin, content-type, accept, authorization");
        containerResponseContext.getHeaders().add(
                "Access-Control-Allow-Methods",
                "GET, POST, PUT, DELETE, OPTIONS, HEAD");
    }

Since you're using JAX-RS, your application class extends the Applicaton class and you just need to override its getSingletons method:

@Override
public Set<Object> getSingletons() {
        return mySingletons();
    }

where your singletons could be as below:

public static Set<Object> mySingletons() {
        Set<Object> singletons = new HashSet<>();
        singletons.add(new MyFilter());
        return singletons;
    }

I tried the above answers with the changes on web.xml etc and none of them worked so I came up with this solution, having tried everything.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionNailiView Question on Stackoverflow
Solution 1 - CorsJoel PearsonView Answer on Stackoverflow
Solution 2 - CorsJWLView Answer on Stackoverflow
Solution 3 - CorsAlex PettyView Answer on Stackoverflow
Solution 4 - CorsAlex PettyView Answer on Stackoverflow
Solution 5 - CorsAlex RView Answer on Stackoverflow
Solution 6 - CorsRanukaView Answer on Stackoverflow
Solution 7 - Cors404KoushikView Answer on Stackoverflow
Solution 8 - CorsGeoffreyView Answer on Stackoverflow
Solution 9 - CorsNovice_JSView Answer on Stackoverflow
Solution 10 - CorsRinorView Answer on Stackoverflow