Niranga Sandaruwan
Niranga Sandaruwan

Reputation: 711

AJAX cors issue : Request header field access-control-allow-credentials is not allowed by Access-Control-Allow-Headers in preflight response

I am sending an ajax request from host(http://abc.com.au) to the spring cloud API gateway running on host http://localhost:8081 .

jquery AJAX request code.

SimplifiedAdoptionBulkUpload.jsp

setCookie("username", 'abc', 30);

$.ajax({
            type: "POST",
            enctype: 'multipart/form-data',
            url: "http://localhost:8081/api/v1/users/bulkUpload",
            xhrFields: {
                withCredentials: true
            },
            data: newData,
            processData: false,
            contentType: false,
            crossDomain: true,
            cache: false,
            timeout: 600000,
            success: function (data) {

                .....
                
                
            },
            error: function (e) {
                $('#btnSubmit').prop("disabled", false);
                $('#txtMessage').text('Error Occured');
            
            },
            beforeSend: function (xhr) {
                xhr.setRequestHeader('Authorization', 'Bearer ' + token);
                xhr.setRequestHeader('Access-Control-Allow-Credentials', 'true');
                xhr.setRequestHeader('Access-Control-Allow-Headers', "Origin,Cookie,X-Requested-With, Content-Type, Accept, Authorization");
                $('body').addClass("loading");
            }
            
        });

spring cloud gateway cors configuration.

@Configuration
public class PreFlightCorsConfiguration {

    private static final String ALLOWED_HEADERS = "Origin,Cookie,X-Requested-With, Content-Type, Accept, Authorization";
    private static final String ALLOWED_METHODS = "*";
    private static final String ALLOWED_ORIGIN = "http://abc.com.au";
    private static final String ALLOWED_EXPOSE = "*";
    private static final String MAX_AGE = "3600";

    @Bean
    public WebFilter corsFilter() {
        return (ServerWebExchange ctx, WebFilterChain chain) -> {
            ServerHttpRequest request = ctx.getRequest();
            if (CorsUtils.isCorsRequest(request)) {
                ServerHttpResponse response = ctx.getResponse();
                HttpHeaders headers = response.getHeaders();
                headers.set("Access-Control-Allow-Origin", ALLOWED_ORIGIN);
                headers.add("Access-Control-Allow-Methods", ALLOWED_METHODS);
                headers.add("Access-Control-Max-Age", MAX_AGE);
                headers.add("Access-Control-Allow-Headers", ALLOWED_HEADERS);
                headers.add("Access-Control-Expose-Headers", ALLOWED_EXPOSE);
                headers.add("Access-Control-Allow-Credentials", "true");
                if (request.getMethod() == HttpMethod.OPTIONS) {
                    response.setStatusCode(HttpStatus.OK);
                    return Mono.empty();
                }
            }
            return chain.filter(ctx);
        };
    }
}

I am getting the below error in the chrome console.

SimplifiedAdoptionBulkUpload:1 Access to XMLHttpRequest at 'http://localhost:8081/api/v1/users/bulkUpload' from origin 'http://abc.com.au' has been blocked by CORS policy: Request header field access-control-allow-credentials is not allowed by Access-Control-Allow-Headers in preflight response.

Updates:

i removed this line from ajax request.

xhr.setRequestHeader('Access-Control-Request-Headers', "Origin,Cookie,X-Requested-With, Content-Type, Accept, Authorization");

i am setting two cookies(accces_token,refresh_token) to cookies in jsp and servlet filter.

public class AdminSecurityFilter implements Filter {


 public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        boolean error = false;

        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;
        request.setCharacterEncoding("UTF-8");


        if(authenticated) {
                    String accessToken = getUserAccessToken(userStr,passStr);
                    if(!accessToken.isEmpty()) {
                    Cookie cookie = new Cookie("access_token", accessToken);
                    cookie.setPath("/");
                    //cookie.setHttpOnly(true);
                    //cookie.setDomain("localhost");
                    //TODO: When in production must do cookie.setSecure(true);
                    cookie.setMaxAge(3600);
                    response.setHeader("Access-Control-Allow-Credentials", "true");
                    response.setHeader("Access-Control-Allow-Origin", "http://localhost:8081");

                    response.addCookie(cookie);
                    }
                    
                    if(!refreshToken.isEmpty()) {
                        Cookie cookie = new Cookie("refresh_token", refreshToken);
                        cookie.setPath("/");
                        //cookie.setHttpOnly(true);
                        //cookie.setDomain("localhost");
                        //TODO: When in production must do cookie.setSecure(true);
                        cookie.setMaxAge(10000);
                        response.setHeader("Access-Control-Allow-Credentials", "true");
                        response.setHeader("Access-Control-Allow-Origin", "http://localhost:8081");

                        response.addCookie(cookie);
                    }
                }


}

also in jsp file i set value cookie using jquery.

 function setCookie(cname,cvalue,exdays) {
              var d = new Date();
              d.setTime(d.getTime() + (exdays*24*60*60*1000));
              var expires = "expires=" + d.toGMTString();
              document.cookie = cname + "=" + cvalue + ";" + expires + ";path=/";
            }

setCookie("username", 'Nirangaa', 30);

but these cookie values(username,refresh_token,access_token) are missing in headers in spring cloud gateway. why AJAX request are not sending cookies values appended in post request to apigteway side. @T.J. Crowder appreciate if you can explain why this is happening

@Component
public class AccessTokenCheckingGlobalFilterPre extends AbstractGatewayFilterFactory<AccessTokenCheckingGlobalFilterPre.Config> {


    public AccessTokenCheckingGlobalFilterPre() {
        super(AccessTokenCheckingGlobalFilterPre.Config.class);
    }

    @Override
    public GatewayFilter apply(AccessTokenCheckingGlobalFilterPre.Config config) {
        return (exchange, chain) -> {
             Route route = exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR);
             ServerHttpRequest request = null;
             if (route != null) {
                
                
                 request = exchange.getRequest();
                 
                 
                 
                 **//[Host:"localhost:8081", Connection:"keep-alive", Content-Length:"7391", Accept:"*/*", Access-Control-Allow-Credentials:"true", Authorization:"Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsiamFjcGx1c19yZXNvdXJjZSJdLCJFeHBpcmVzSW4iOjM1OTksInVzZXJfbmFtZSI6Im5zYW5kYXJ1d2FAd2lsZXkuY29tIiwic2NvcGUiOlsiUkVBRCxXUklURSJdLCJleHAiOjE2MTUxOTQwNjIsInVzZXJOYW1lIjoibnNhbmRhcnV3YUB3aWxleS5jb20iLCJhdXRob3JpdGllcyI6WyJST0xFX0FkbWluaXN0cmF0b3IiLCJST0xFX3RlYWNoZXIiLCJST0xFX3NjaGFkbWluIiwiUk9MRV9zdHVkZW50Il0sImp0aSI6IjBkMjQ3ZjJkLTg0NjgtNDUwYS04NjI3LTAzOGI4ZmRlZjQ2MCIsImNsaWVudF9pZCI6ImphY3BsdXMifQ.GT0ayX01TO0fNY834n5_vXsqmt2P3s2C7hfMH-_FLvsNT-p9uIj5i0U66ZdouDUaL9xu1iy4wdfxLexfvilwnO10fTX5I0U7DHqHQetLUwCJOhET0hN-PyFcJRe7k3C3BUe8f7iuDd6Y4VbLCYTTpp4KSjWcS5fv-BTrvTvktwtkq5oFK2iCtPS6JwqPcFsvt2MYNi9UlGFeik_a-iyuTTa7xf7VgL2XFnGqcu3bOTUNxj4AhG91YL5har3OnFTbZnKFxVWykEz7MJFSXzmhmSS5rNYAbC5FBg65VFmzD0j9G4j1xPODxmLEEeE2Qj5FSe6VTnEZIiFHTLd27IuYyA", User-Agent:"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36", Origin:"http://abc.com.au", Content-Type:"multipart/form-data; boundary=----WebKitFormBoundaryV5bORQSNHAa3kxFR", Referer:"http://admin.jacplus.com.au/admin/SimplifiedAdoptionBulkUpload", Accept-Encoding:"gzip, deflate, br", Accept-Language:"en-US,en;q=0.9"]**

                 HttpHeaders headers = request.getHeaders();
                 
                 
                 
                 
                 
                 
                 
                 List<String> authorizationHeader = headers.get(HttpHeaders.AUTHORIZATION);
                 String value = authorizationHeader.get(0);
                 
                 MultiValueMap<String, HttpCookie> cookies = request.getCookies(); /// nulll 

                
                 
             }
             
             return chain.filter(exchange.mutate().request(request).build());
            
            
            
        };
    }

Upvotes: 0

Views: 2040

Answers (1)

T.J. Crowder
T.J. Crowder

Reputation: 1074385

The Access-Control-Allow-XYZ headers are response headers, not request headers. Remove them from your $.ajax call. You may want the Access-Control-Request-XYZ header, e.g.:

xhr.setRequestHeader('Access-Control-Request-Headers', "Origin,Cookie,X-Requested-With, Content-Type, Accept, Authorization");
// −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−^^^^^^^

That's a valid request header. (There's no Access-Control-Request-Credentials header listed in the CORS spec, though, so your other line adding a Access-Control-Allow-Credentials header should just be removed.)

More generally, any header in the request has to be allowed by your response's Access-Control-Allow-Headers value, and yours didn't have that in it. But the fix is to remove it from the request, not add it to the Access-Control-Allow-Headers value.

See also: CORS specification

Upvotes: 1

Related Questions