CORS policy: No ‘Access-Control-Allow-Origin’ header is present on the requested resource

I am calling custom rest api of JIRA server №1 from frontside JIRA Server 2 .


 var myHeaders = {
              'Authorization': 'Basic ' + btoa(...)   
          };
          $http.get(url, {
              headers: myHeaders
          })
              .then(function successCallback(response) {                
              });
         
          })

Jira server №1 is in white list of Jira server №2 with type Application link and active Allow Incoming.

Custom rest api returned headers (I checked in SOAP UI):
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: OPTIONS, GET, PUT, DELETE
Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: Origin, Content-Type, X-Auth-Token
Access-Control-Expose-Headers: Origin, Authorization, Content-Type

Although, it’s not working. I get the error:

Access to XMLHttpRequest at IRA server №1’s url from origin JIRA server №2’s url has been blocked by CORS policy: Response to preflight request doesn’t pass access control check: No ‘Access-Control-Allow-Origin’ header is present on the requested resource.

@Path("test")
public class TestResource {
    @GET
    @Produces({MediaType.APPLICATION_JSON})
    public Response getTest() throws Exception {      
        return Response.ok()
                .header("Access-Control-Allow-Origin", "*")
                .header("Access-Control-Allow-Methods", "OPTIONS, GET")
                .header("Access-Control-Allow-Headers", "Origin, Content-Type, X-Auth-Token, Access-Control-Allow-Headers, Authorization, X-Requested-With,observe")
                .header("Access-Control-Expose-Headers", "Origin, Authorization, Content-Type, responseType, observe")
                .header("Access-Control-Max-Age", "3600")
                .build();
    }

    @OPTIONS
    public Response optionsTest(){
        Response r = Response.ok()
                .header("Access-Control-Allow-Origin", "*")
                .header("Access-Control-Allow-Methods", "OPTIONS, GET")
                .header("Access-Control-Allow-Headers", "Origin, Content-Type, X-Auth-Token, Access-Control-Allow-Headers, Authorization, X-Requested-With,observe")
                .header("Access-Control-Expose-Headers", "Origin, Authorization, Content-Type, responseType, observe")
                .build();
        return r;
    }
}

What’s wrong?

Have you tried to add “OPTIONS” in the “Access-Control-Allow-Methods” ?

Access-Control-Allow-Methods: GET, OPTIONS

I added, but nothing had happened.

Sorry, I’ve missed you put the request AND the response headers.

Just for your information, you don’t have to add any request headers for CORS, it’s a pure backend configuration that allows one domain to be called from another.

When you trigger your Ajax request, could you capture the response headers and check that you have the “Access-*” headers added correctly to the response ?

When the plugin triggers request, there are no callings any method on the second server, so Access-*” headers are not added correctly.

So, it means you have probably another issue than the CORS, because CORS applies on the response, not on the request.

I mean, CORS headers are added by the server on the response to specify which domains are allowed to read the content of the response. It’s the browser that interprets these response headers and block/authorize the content. By the way, to isolate if it’s a CORS issue, you can easily bypass them by adding an extension to your browser (eg for firefox: CORS Everywhere – Adoptez cette extension pour 🦊 Firefox (fr))

If you don’t see the request triggered by the plugin hitting your backend server, you have another issue.

When I ran the Chrome browser without CORS - everything worked. I added the REST API code.

As I think, the problem is missing authorization’s header where is called API method Options.
When I run chrome browser without CORS, API method Options is not called, only Get and it has authorization’s header.
When I run chrome browser with CORS, API method Options is called and it hasn’t authorization’s header so I got 401 error.
Although. I don’t understand why API method Options hasn’t authorization’s header. I tried to call REST API via angularJS. I tried to call via AJAX. The results are the same - missing authorization’s header and error 401.

AJS.toInit(function() {
$.ajax({
headers: {
‘Authorization’: 'Basic ’ + btoa("…" + “:” + “…”),
},
type: ‘GET’,
dataType: ‘json’,
url: “…”,
success: function(data) {
},
beforeSend: function(xhr) {
xhr.setRequestHeader(“Authorization”, “Basic " + btoa(”…" + “:” + “…”));
},
error: function(){ },
complete: function (){ }
});
});

Because it looks to be part of the spec: Fetch Standard :
“Exclude user credentials”

So, you have to authorize OPTIONS method being called without authorization. (I don’t know if Atlassian specific annotation @AnonymousAllowed on your OPTIONS request mapping is enough in that case, you should probably give it a try)

I read that OPTIONS method never includes Authorization header. For this reason I added annotation for REST API: @AnonymousAllowed. Nothing had changed. When I run plugin function, API method Options is called and I got 401 error.

Based on this ticket ([JRASERVER-59101] Jira doesn't support preflighted requests for CORS - Create and track feature requests for Atlassian products. ), it looks like the only solution is to handle the OPTIONS call in a proxy. (eg: Nginx, Apache or whatever you would have in front of your Jira server).