I need to access my web api hosted remotely from my react app. On the server side i did below to allow cross domain communication:
import javax.ws.rs.core.Response;
import com.mypackage.ResponseDto;
#Override
public Response fetch(String id, String env) throws ServiceException
{
ResponseDto res = new ResponseDto();
res = updateResp(id, env); // not important
return Response.ok().header("Access-Control-Allow-Origin","*").entity(res).build();
}
When i check from postman i can see cors header correctly set as below:
access-control-allow-origin →*
content-type →application/json
date →Wed, 16 Aug 2017 11:07:16 GMT
server →web
transfer-encoding →chunked
But when i access the same endpoint from react app, browsers starts complaining with below error:
Fetch API cannot load
http://myservices.com/myservice-app/services/. Response to
preflight request doesn't pass access control check: No
'Access-Control-Allow-Origin' header is present on the requested
resource. Origin 'http://localhost:3000' is therefore not allowed
access. If an opaque response serves your needs, set the request's
mode to 'no-cors' to fetch the resource with CORS disabled
Any idea whats going on here?
Edit#1
Did below change still see the same error:
return Response.ok()
.header("Access-Control-Allow-Origin", "*")
.header("Access-Control-Allow-Methods", "POST, GET, PUT, UPDATE, OPTIONS")
.header("Access-Control-Allow-Headers", "Content-Type, Accept, X-Requested-With")
.entity(response).build();
I have no experience with whatever Java library you're using, but something like this must work:
#Override
public Response options() throws ServiceException
{
ResponseDto res = new ResponseDto();
return Response.ok().header("Access-Control-Allow-Origin","*").entity(res).build();
}
If the library works like I think it does, this will send a 200 OK on every OPTIONS request you send to your server, with header Access-Control-Allow-Origin = *. That's what you should be aiming for.
Related
I'm making HTTPS request to a private API (hosted Itop), I get an response but I get CORS Multiple Origin Not Allow error so my JavaScript program can't use the response content.
I'm supposed to have CORS authorization
The requests are POST, made with fetch, there isn't preflight (OPTIONS) request made before (fetch did them alone for my other GET API request but didn't here)
Also some server response time is long for firefox (~2s) but it don't seems to change anything
It's not allowed to send multiple Access-Control-Allow-Origin headers or multiple origins in one header in the same response. In the comments, you described two same Access-Control-Allow-Origin headers in one response. Even two same origins aren't allowed. Remove one header in the backend code.
firefox is the best browser to identify this issue,
you can fix this issue by following this path.
when you sending a request from frontend,and then response will come from backend. but browser is not allowed to aceess to javascript. this is the cors error.
1.open ur backend, then create a package call CorsFilter.
2. and then create a filter servlet
3. paste this code
CorsFilter
#WebFilter(filterName = "CorsFilter", urlPatterns = "/*")
public class CorsFilter extends HttpFilter {
#Override
protected void doFilter(HttpServletRequest req, HttpServletResponse res, FilterChain chain) throws IOException, ServletException {
String origin = req.getHeader("Origin");
if (origin != null && origin.toLowerCase().contains(getServletContext().getInitParameter("origin"))) {
res.setHeader("Access-Control-Allow-Origin", origin);
res.setHeader("Access-Control-Allow-Headers", "Content-Type");
res.setHeader("Access-Control-Expose-Headers", "Content-Type");
if (req.getMethod().equals("OPTIONS")) {
res.setHeader("Access-Control-Allow-Methods", "OPTIONS, GET, PUT, POST, DELETE, HEAD");
}
}
chain.doFilter(req, res);
}
}
im making an api using Javalin and trying to send data to it from javascript, however i get cors errors whenever i try to do so. i can recieve data just fine but not send data. Here is my error: Response to preflight request doesn't pass access control check: It does not have HTTP ok status.
-----------javascript-----------
function sendOurAjax(){
console.log("ajax using fetch")
let ourCustomSuper = {
"name": "SpaceMonkey",
"superpower": "person atmosphere",
"bounty": 0
}
fetch(`http://localhost:8000/api`, {
method: "post",
'headers': {
'Content-Type': 'application/json',
'BARNACLES': 'custom header value'
},
'body': JSON.stringify(ourCustomSuper)
})
.then(
function(daResponse){
console.log(daResponse);
const convertedResponse = daResponse.json();
return convertedResponse;
}
).then(
function(daSecondResponse){
console.log("Fetch is a thing. We did it.");
console.log(daSecondResponse);
}
).catch(
(stuff) => {console.log("this sucker exploded")}
)
}
-----------java-----------
app.get("/api", context ->{
context.header("Access-Control-Allow-Origin", "*");
context.header("Access-Control-Allow-Methods: GET, POST, PATCH, PUT, DELETE, OPTIONS");
context.header("Access-Control-Allow-Headers: Origin, Content-Type, X-Auth-Token");
System.out.println("The endpoint method has fired");
context.result("endpoint handler has fired");
context.json(myList);
});
Why was the CORS error there in the first place?
The error stems from a security mechanism that browsers implement called the same-origin policy.
The same-origin policy fights one of the most common cyber attacks out there: cross-site request forgery. In this maneuver, a malicious website attempts to take advantage of the browser’s cookie storage system.
For every HTTP request to a domain, the browser attaches any HTTP cookies associated with that domain. This is especially useful for authentication, and setting sessions. For instance, it’s feasible that you would sign into a web app like facebook-clone.com. In this case, your browser would store a relevant session cookie for the facebook-clone.com domain:
here a link on the cors subject
How To Fix CORS Error
Offhand is see you do have the
Access-Control-Allow-Origin: *
Access-Control-Allow-Origin: http://localhost:3000
set but the content type might be wrong i.e json
something along the lines of
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers: Authorization, Content-Type
Content-Type: application/json
My stack is as follows:
Backend: Spring boot(Java) exposed at :8088
Frontend: Vue hosted on a Node development server exposed at :8080
On the frontend, I am re-configuring axios in a http-common.js to put the baseURL to the Spring boot application, and allow connection from the node development server:
import axios from 'axios'
export const AXIOS = axios.create({
baseURL: `http://localhost:8088`,
headers: {
'Access-Control-Allow-Origin': 'http://localhost:8080'
}
})
However, when attempting to make a post request to log in, I will get the following message in the console:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:8088/api/login. (Reason: CORS preflight channel did not succeed).
Which makes me think: Is the issue with the spring boot application?
But no, in the main method, I have enabled CORS globally when reaching the /api/* endpoints from the node application running at :8080:
#Bean
public WebMvcConfigurer corsConfigurer() { // Enables CORS globally
return new WebMvcConfigurerAdapter() {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/*").allowedOrigins("http://localhost:8080");
}
};
}
To me it looks as if it should be configured correctly. However, as of now, the following POST of username + password never even reaches the backend Spring boot application at all. The issue must be with the Node application?
This is the Login method in the frontend:
login ({commit}, authData) {
AXIOS.post('/api/login', {
username: authData.username,
password: authData.password,
withCredentials: true
})
.then(res => {
console.log(res)
commit('authUser', {
token: res.data.idToken,
userId: res.data.localId
})
})
.catch(error => console.log(error))
}
To further solidate my point, i can cURL to the spring boot application and get the correct response(a valid JWT!):
Request:
curl -i -H "Content-Type: application/json" -X POST -d '{
"username": "sysadmin",
"password": "sysadmin"
}' http://localhost:8088/api/login
Response:
HTTP/1.1 200
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: DENY
X-Application-Context: application:8088
authentication: <very long JWT string>
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
So, via cUR - I get a HTTP 200 OK, and a valid JWT. But via the same POST method from :8080, I get a 403 and a warning message.
As per other posts, I have attempted to add CORS to my dev server configuration(Node/Express):
var app = express()
app.use(cors())
app.options('*', cors())
app.use(function (req, res, next) {
// Website you wish to allow to connect
res.setHeader('Access-Control-Allow-Origin', 'http://localhost:8088')
// Request methods you wish to allow
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE')
// Request headers you wish to allow
res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type')
// Set to true if you need the website to include cookies in the requests sent
// to the API (e.g. in case you use sessions)
res.setHeader('Access-Control-Allow-Credentials', true)
// Pass to next layer of middleware
next()
})
The result is exactly the same as previously
Adding the 'Access-Control-Allow-Origin' header to your ajax post call is useless since is part of cors specification and must be set by the server as part of the http response.
export const AXIOS = axios.create({
baseURL: `http://localhost:8088`,
headers: {
//you can remove this header
'Access-Control-Allow-Origin': 'http://localhost:8080'
}
})
You can curl the application because the cors exception is caused by the browser disallowing you to access the payload. The browser performs the preflight (OPTION) request before any Cross domain call, and before your actual http request to make sure you have the rights to see the payload, you can see it just inspecting the console under the network tab.
the issue is most likely server side, somehow you did not configure correctly the cors header to your http response.
make sure you're setting not only the Access-Control-Allow-Origin header (that must contain the specific domain, not * since you're in credential mode), but even Access-Control-Allow-Credential since you're sending credentials, and the Access-Control-Allow-Methods (that must contain at least the PUSH and the OPTION methods)
in your chrome dev tools console under the network tab if you inspect your ajax call you can see the header of the http response, should end up with something like this.
Have you tried to add #CrossOrigin to your login REST method?
#CrossOrigin(origins = "http://localhost:8080")
#GetMapping("/greeting")
public Greeting greeting(#RequestParam(required=false, defaultValue="World") String name) {
System.out.println("==== in greeting ====");
return new Greeting(counter.incrementAndGet(), String.format(template, name));
}
Update: I just read this on javadoc:
Exact path mapping URIs (such as "/admin") are supported as well as Ant-style path patterns (such as "/admin/**").
I don't see here a path with one star, but your path is a correct Ant-style path..
I'm developing a java script client application, in server-side I need to handle CORS, all the services I had written in JAX-RS with JERSEY.
My code:
#CrossOriginResourceSharing(allowAllOrigins = true)
#GET
#Path("/readOthersCalendar")
#Produces("application/json")
public Response readOthersCalendar(String dataJson) throws Exception {
//my code. Edited by gimbal2 to fix formatting
return Response.status(status).entity(jsonResponse).header("Access-Control-Allow-Origin", "*").build();
}
As of now, i'm getting error No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8080' is therefore not allowed access.”
Please assist me with this.
Thanks & Regards
Buddha Puneeth
Note: Make sure to read the UPDATE at the bottom. The original answer includes a "lazy" implementation of the CORS filter
With Jersey, to handle CORS, you can just use a ContainerResponseFilter. The ContainerResponseFilter for Jersey 1.x and 2.x are a bit different. Since you haven't mentioned which version you're using, I'll post both. Make sure you use the correct one.
Jersey 2.x
import java.io.IOException;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerResponseContext;
import javax.ws.rs.container.ContainerResponseFilter;
#Provider
public class CORSFilter implements ContainerResponseFilter {
#Override
public void filter(ContainerRequestContext request,
ContainerResponseContext response) throws IOException {
response.getHeaders().add("Access-Control-Allow-Origin", "*");
response.getHeaders().add("Access-Control-Allow-Headers",
"CSRF-Token, X-Requested-By, Authorization, Content-Type");
response.getHeaders().add("Access-Control-Allow-Credentials", "true");
response.getHeaders().add("Access-Control-Allow-Methods",
"GET, POST, PUT, DELETE, OPTIONS, HEAD");
}
}
If you use package scanning to discover providers and resources, the #Provider annotation should take care of the configuration for you. If not, then you will need to explicitly register it with the ResourceConfig or the Application subclass.
Sample code to explicitly register filter with the ResourceConfig:
final ResourceConfig resourceConfig = new ResourceConfig();
resourceConfig.register(new CORSFilter());
final final URI uri = ...;
final HttpServer httpServer = GrizzlyHttpServerFactory.createHttpServer(uri, resourceConfig);
For Jersey 2.x, if you are having problems registering this filter, here are a couple resources that might help
Registering Resources and Providers in Jersey 2
What exactly is the ResourceConfig class in Jersey 2?
Jersey 1.x
import com.sun.jersey.spi.container.ContainerRequest;
import com.sun.jersey.spi.container.ContainerResponse;
import com.sun.jersey.spi.container.ContainerResponseFilter;
#Provider
public class CORSFilter implements ContainerResponseFilter {
#Override
public ContainerResponse filter(ContainerRequest request,
ContainerResponse response) {
response.getHttpHeaders().add("Access-Control-Allow-Origin", "*");
response.getHttpHeaders().add("Access-Control-Allow-Headers",
"CSRF-Token, X-Requested-By, Authorization, Content-Type");
response.getHttpHeaders().add("Access-Control-Allow-Credentials", "true");
response.getHttpHeaders().add("Access-Control-Allow-Methods",
"GET, POST, PUT, DELETE, OPTIONS, HEAD");
return response;
}
}
web.xml configuration, you can use
<init-param>
<param-name>com.sun.jersey.spi.container.ContainerResponseFilters</param-name>
<param-value>com.yourpackage.CORSFilter</param-value>
</init-param>
Or ResourceConfig you can do
resourceConfig.getContainerResponseFilters().add(new CORSFilter());
Or package scanning with the #Provider annotation.
EDIT
Please note that the above example can be improved. You will need to know more about how CORS works. Please see here. For one, you will get the headers for all responses. This may not be desirable. You may just need to handle the preflight (or OPTIONS). If you want to see a better implemented CORS filter, you can check out the source code for the RESTeasy CorsFilter
UPDATE
So I decided to add a more correct implementation. The above implementation is lazy and adds all the CORS headers to all requests. The other mistake is that being that it is only a response filter, the request is still processes. This means that when the preflight request comes in, which is an OPTIONS request, there will be no OPTIONS method implemented, so we will get a 405 response, which is incorrect.
Here's how it should work. So there are two types of CORS requests: simple requests and preflight requests. For a simple request, the browser will send the actual request and add the Origin request header. The browser expects for the response to have the Access-Control-Allow-Origin header, saying that the origin from the Origin header is allowed. In order for it to be considered a "simple request", it must meet the following criteria:
Be one of the following method:
GET
HEAD
POST
Apart from headers automatically set by the browser, the request may only contain the following manually set headers:
Accept
Accept-Language
Content-Language
Content-Type
DPR
Save-Data
Viewport-Width
Width
The only allowed values for the Content-Type header are:
application/x-www-form-urlencoded
multipart/form-data
text/plain
If the request doesn't meet all of these three criteria, a Preflight request is made. This is an OPTIONS request that is made to the server, prior to the actual request being made. It will contain different Access-Control-XX-XX headers, and the server should respond to those headers with its own CORS response headers. Here are the matching headers:
REQUEST HEADER
RESPONSE HEADER
Origin
Access-Control-Allow-Origin
Access-Control-Request-Headers
Access-Control-Allow-Headers
Access-Control-Request-Method
Access-Control-Allow-Methods
XHR.withCredentials
Access-Control-Allow-Credentials
With the Origin request header, the value will be the origin server domain, and the response Access-Control-Allow-Origin should be either this same address or * to specify that all origins are allowed.
If the client tries to manually set any headers not in the above list, then the browser will set the Access-Control-Request-Headers header, with the value being a list of all the headers the client is trying to set. The server should respond back with a Access-Control-Allow-Headers response header, with the value being a list of headers it allows.
The browser will also set the Access-Control-Request-Method request header, with the value being the HTTP method of the request. The server should respond with the Access-Control-Allow-Methods response header, with the value being a list of the methods it allows.
If the client uses the XHR.withCredentials, then the server should respond with the Access-Control-Allow-Credentials response header, with a value of true. Read more here.
So with all that said, here is a better implementation. Even though this is better than the above implementation, it is still inferior to the RESTEasy one I linked to, as this implementation still allows all origins. But this filter does a better job of adhering to the CORS spec than the above filter which just adds the CORS response headers to all request. Note that you may also need to modify the Access-Control-Allow-Headers to match the headers that your application will allow; you may want o either add or remove some headers from the list in this example.
#Provider
#PreMatching
public class CorsFilter implements ContainerRequestFilter, ContainerResponseFilter {
/**
* Method for ContainerRequestFilter.
*/
#Override
public void filter(ContainerRequestContext request) throws IOException {
// If it's a preflight request, we abort the request with
// a 200 status, and the CORS headers are added in the
// response filter method below.
if (isPreflightRequest(request)) {
request.abortWith(Response.ok().build());
return;
}
}
/**
* A preflight request is an OPTIONS request
* with an Origin header.
*/
private static boolean isPreflightRequest(ContainerRequestContext request) {
return request.getHeaderString("Origin") != null
&& request.getMethod().equalsIgnoreCase("OPTIONS");
}
/**
* Method for ContainerResponseFilter.
*/
#Override
public void filter(ContainerRequestContext request, ContainerResponseContext response)
throws IOException {
// if there is no Origin header, then it is not a
// cross origin request. We don't do anything.
if (request.getHeaderString("Origin") == null) {
return;
}
// If it is a preflight request, then we add all
// the CORS headers here.
if (isPreflightRequest(request)) {
response.getHeaders().add("Access-Control-Allow-Credentials", "true");
response.getHeaders().add("Access-Control-Allow-Methods",
"GET, POST, PUT, DELETE, OPTIONS, HEAD");
response.getHeaders().add("Access-Control-Allow-Headers",
// Whatever other non-standard/safe headers (see list above)
// you want the client to be able to send to the server,
// put it in this list. And remove the ones you don't want.
"X-Requested-With, Authorization, " +
"Accept-Version, Content-MD5, CSRF-Token, Content-Type");
}
// Cross origin requests can be either simple requests
// or preflight request. We need to add this header
// to both type of requests. Only preflight requests
// need the previously added headers.
response.getHeaders().add("Access-Control-Allow-Origin", "*");
}
}
To learn more about CORS, I suggest reading the MDN docs on Cross-Origin Resource Sharing (CORS)
Remove annotation "#CrossOriginResourceSharing(allowAllOrigins = true)"
Then Return Response like below:
return Response.ok()
.entity(jsonResponse)
.header("Access-Control-Allow-Origin", "*")
.build();
But the jsonResponse should replace with a POJO Object!
The other answer might be strictly correct, but misleading. The missing part is that you can mix filters from different sources together. Even thought Jersey might not provide CORS filter (not a fact I checked but I trust the other answer on that), you can use tomcat's own CORS filter.
I am using it successfully with Jersey. I have my own implementation of Basic Authentication filter, for example, together with CORS. Best of all, CORS filter is configured in web XML, not in code.
peeskillet's answer is correct. But I get this error when refresh the web page (it is working only on first load):
The 'Access-Control-Allow-Origin' header contains multiple values '*, *', but only one is allowed. Origin 'http://127.0.0.1:8080' is therefore not allowed access.
So instead of using add method to add headers for response, I using put method. This is my class
public class MCORSFilter implements ContainerResponseFilter {
public static final String ACCESS_CONTROL_ALLOW_ORIGIN = "Access-Control-Allow-Origin";
public static final String ACCESS_CONTROL_ALLOW_ORIGIN_VALUE = "*";
private static final String ACCESS_CONTROL_ALLOW_CREDENTIALS = "Access-Control-Allow-Credentials";
private static final String ACCESS_CONTROL_ALLOW_CREDENTIALS_VALUE = "true";
public static final String ACCESS_CONTROL_ALLOW_HEADERS = "Access-Control-Allow-Headers";
public static final String ACCESS_CONTROL_ALLOW_HEADERS_VALUE = "Cache-Control, Pragma, Origin, Authorization, Content-Type, X-Requested-With, Accept";
public static final String ACCESS_CONTROL_ALLOW_METHODS = "Access-Control-Allow-Methods";
public static final String ACCESS_CONTROL_ALLOW_METHODS_VALUE = "GET, POST, PUT, DELETE, OPTIONS, HEAD";
public static final String[] ALL_HEADERs = {
ACCESS_CONTROL_ALLOW_ORIGIN,
ACCESS_CONTROL_ALLOW_CREDENTIALS,
ACCESS_CONTROL_ALLOW_HEADERS,
ACCESS_CONTROL_ALLOW_METHODS
};
public static final String[] ALL_HEADER_VALUEs = {
ACCESS_CONTROL_ALLOW_ORIGIN_VALUE,
ACCESS_CONTROL_ALLOW_CREDENTIALS_VALUE,
ACCESS_CONTROL_ALLOW_HEADERS_VALUE,
ACCESS_CONTROL_ALLOW_METHODS_VALUE
};
#Override
public ContainerResponse filter(ContainerRequest request, ContainerResponse response) {
for (int i = 0; i < ALL_HEADERs.length; i++) {
ArrayList<Object> value = new ArrayList<>();
value.add(ALL_HEADER_VALUEs[i]);
response.getHttpHeaders().put(ALL_HEADERs[i], value); //using put method
}
return response;
}
}
And add this class to init-param in web.xml
<init-param>
<param-name>com.sun.jersey.spi.container.ContainerResponseFilters</param-name>
<param-value>com.yourpackage.MCORSFilter</param-value>
</init-param>
To solve this for my project I used Micheal's answer and arrived at this:
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<executions>
<execution>
<id>run-embedded</id>
<goals>
<goal>run</goal>
</goals>
<phase>pre-integration-test</phase>
<configuration>
<port>${maven.tomcat.port}</port>
<useSeparateTomcatClassLoader>true</useSeparateTomcatClassLoader>
<contextFile>${project.basedir}/tomcat/context.xml</contextFile>
<!--enable CORS for development purposes only. The web.xml file specified is a copy of
the auto generated web.xml with the additional CORS filter added -->
<tomcatWebXml>${maven.tomcat.web-xml.file}</tomcatWebXml>
</configuration>
</execution>
</executions>
</plugin>
The CORS filter being the basic example filter from the tomcat site.
Edit:
The maven.tomcat.web-xml.file variable is a pom defined property for the project and it contains the path to the web.xml file (located within my project)
Techies--
I've been going around in a circle, alternating between the error:
https://anyurlwithcreds.com/x?$format=JSON&$top=2. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'null' is therefore not allowed access. The response had HTTP status code 403.
when the javascript looks like this:
HTTPSFResponse.open("GET", "https://anyurlwithcreds.com/x?$format=JSON&$top=2", true);
HTTPSFResponse.setRequestHeader('Access-Control-Allow-Origin', '*');
HTTPSFResponse.setRequestHeader('Access-Control-Allow-Methods', 'GET');
HTTPSFResponse.setRequestHeader('Access-Control-Allow-Headers', 'Content-Type');
...and the error :
'setRequestHeader' on 'XMLHttpRequest': The object's state must be OPENED.
...when the code looks like this;
HTTPSFResponse.setRequestHeader('Access-Control-Allow-Origin', '*');
HTTPSFResponse.setRequestHeader('Access-Control-Allow-Methods', 'GET');
HTTPSFResponse.setRequestHeader('Access-Control-Allow-Headers', 'Content-Type');
HTTPSFResponse.open("GET", "https://anyurlwithcreds.com/x$format=JSON&$top=2", true);
Clearly I am missing something. Either I've misunderstood Access-Control-Allow-Origin's role as a header in CORs or perhaps there's a remote setting necessary on the site that's serving the pages? Please advise on how to solve this.