IE11 CORS rejecting OPTIONS on https

All we need is an easy explanation of the problem, so here it is.

IE11 for some reason is rejecting a PUT request but only when I use https.
I have very hard time to find the issue as using http, localhost and other browsers works fine.

The console is showing two errors

SEC7124: Request method PUT was not present in the Access-Control-Allow-Methods list.
SCRIPT7002: XMLHttpRequest: Network Error 0x80070005, Access is denied.

OPTION request sent from the browser is

Accept: */*
Accept-Encoding: gzip, deflate
Access-Control-Request-Headers: accept, content-type, session-id
Access-Control-Request-Method: PUT   
Cache-Control: no-cache 
Connection: Keep-Alive  
Content-Length: 0  
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko

and the response from the server is following:

X-Powered-By: Servlet/2.5
Server: server
Content-Encoding: gzip
Access-Control-Expose-Headers: Session-Id
Access-Control-Allow-Origin: *
Access-Control-Max-Age: -1
Access-Control-Allow-Methods: OPTIONS, GET, POST, PUT, DELETE
Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: accept, origin, Content-Type, session-id, authorization, portal-url
Content-Type: application/vnd.sun.wadl+xml
Content-Length: 352
Date: Tue, 19 Jan 2016 15:33:38 GMT

AngularJS is used on client side standard $http PUT is used.
Java with jersey is used on server side and request filter to handle CORS is the following:

 public ContainerResponse filter( final ContainerRequest request, final ContainerResponse response )
    if ( request.getHeaderValue( "Origin" ) != null ) 
        final MultivaluedMap<String, Object> headers = response.getHttpHeaders();
        headers.add( "Access-Control-Allow-Origin", "*" );
        headers.add( "Access-Control-Expose-Headers", "Session-Id" );
        headers.add( "Access-Control-Allow-Credentials", Boolean.TRUE.toString() );

    if ( "OPTIONS".equals( request.getMethod() ) ) 
        final MultivaluedMap<String, Object> headers = response.getHttpHeaders();
        for ( String method : ["OPTIONS", "GET", "POST", "PUT", "DELETE"] ) 
            headers.add( "Access-Control-Allow-Methods", method );
        headers.add( "Access-Control-Allow-Headers",
                "accept, origin, Content-Type, session-id, authorization, portal-url, " 
                + "If-Modified-Since, Cache-Control, Pragma" );
        headers.add( "Access-Control-Max-Age", "-1" );            

    return response;

Maybe you can see what may be wrong with that.


How to solve :

I know you bored from this bug, So we are here to help you! Take a deep breath and look at the explanation of your problem. We have many solutions to this problem, But we recommend you to use the first method because it is tested & true method that will 100% work for you.

Method 1

I have managed to find the issue.

I saw this issue on https only because the portal and the host where on different domains. I could not replicate the issue on localhost because both the server and portal are on this same domain. This means the OPTION request was not sent and everything worked as expected. After running the portal on localhost and using IP address as a server URL instead of localhost the OPTION request was included in the request and I could replicate my issue.

And the issue it self was down to following code on the server

    for ( String method : ["OPTIONS", "GET", "POST", "PUT", "DELETE"] ) 
        headers.add( "Access-Control-Allow-Methods", method );

for some reason IE did not like multiple Access-Control-Allow-Methods headers. After changing code to the following issue was solved.

 List<String> ALLOWED_METHODS = Arrays.asList( "OPTIONS", "GET", "POST", "PUT", "DELETE" );
 headers.add( "Access-Control-Allow-Methods", ALLOWED_METHODS );

Note: Use and implement method 1 because this method fully tested our system.
Thank you 🙂

All methods was sourced from or, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply