0

I tried to make a connection between my Angular frontend and a REST Endpoint in Java / Spring (which I didn't developed and don't know so well). By GET, all works. By POST, I receive the message in the terminal

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.

and, in the Network tab from the dev instruments, an error 403 on OPTIONS method

Request Method: OPTIONS
Status Code: 403 
Remote Address: xx.xx.xx.xx:xxxx
Referrer Policy: strict-origin-when-cross-origin

So, I found this case after several searching in internet and the cause is CORS settings: usually, in this scenario, a OPTIONS call is sent before a POST; but, due to CORS, an OPTIONS call is not allowed. So, I tried to set this row on my controller

@CrossOrigin(origins = "*", methods = {RequestMethod.OPTIONS, RequestMethod.GET, RequestMethod.POST, RequestMethod.PUT, RequestMethod.DELETE})

This time the error changed in

Multiple CORS header 'Access-Control-Allow-Origin' not allowed
But the code I added is the only similar to @CrossOrigin, I dind't found others similar.

So, in according to the post CORS issue - No 'Access-Control-Allow-Origin' header is present on the requested resource, I tried the following solution:

@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedMethods("HEAD", "GET", "PUT", "POST", "DELETE", "PATCH");
    }
}

and

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
//        http.csrf().disable();
        http.cors();
    }

    @Bean
    public CorsConfigurationSource corsConfigurationSource() {
        final CorsConfiguration configuration = new CorsConfiguration();
        configuration.setAllowedOrigins(ImmutableList.of("*"));
        configuration.setAllowedMethods(ImmutableList.of("HEAD",
                "GET", "POST", "PUT", "DELETE", "PATCH"));
        // setAllowCredentials(true) is important, otherwise:
        // The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'.
        configuration.setAllowCredentials(true);
        // setAllowedHeaders is important! Without it, OPTIONS preflight request
        // will fail with 403 Invalid CORS request
        configuration.setAllowedHeaders(ImmutableList.of("Authorization", "Cache-Control", "Content-Type"));
        final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }
}

But this time the error I see in the console became

has been blocked by CORS policy: The 'Access-Control-Allow-Origin' header contains multiple values '*, *', but only one is allowed.

So, this is the last point I reached. How can I solve this last error about multiple values? Each time I work on this, I do a step ahead and the error changes but it is still there.

halfer
  • 19,824
  • 17
  • 99
  • 186
Archimede
  • 699
  • 3
  • 15
  • 28
  • Could you add the request with headers to your question. What is the value of the `origin` header? Also add the response with headers? How many `Access-Control-Allow-Origin` are in the response? – dur Mar 27 '21 at 11:30
  • You could try to remove `@CrossOrigin(origins = "*", methods = {RequestMethod.OPTIONS, RequestMethod.GET, RequestMethod.POST, RequestMethod.PUT, RequestMethod.DELETE})`. – dur Mar 27 '21 at 11:30
  • It looks like you have two different filters, wich add the `Access-Control-Allow-Origin` header. – dur Mar 27 '21 at 11:32

1 Answers1

3

Just add this to your WebSecurityConfigurerAdapter

@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    
/*@Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedMethods("HEAD", "GET", "PUT", "POST", "DELETE", "PATCH");
    }*/ not needed

@Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            // by default uses a Bean by the name of corsConfigurationSource
            .cors(withDefaults())
            ...
    }

    @Bean
    CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();
        configuration.setAllowedOrigins(Arrays.asList("https://localhost:5000"));// if your front end running on localhost:5000
        configuration.setAllowedMethods(Arrays.asList("GET","POST"));
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }
}

Make sure you don't have any other filter or annotation for cors except the code above

Spring CORS section in Spring Security documentation.

If you are not using Spring Security:

package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@SpringBootApplication
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }


    @Bean
    public WebMvcConfigurer corsConfigurer() {
        return new WebMvcConfigurer() {
            @Override
            public void addCorsMappings(CorsRegistry registry) {
                registry
                .addMapping("/**")
                .allowedOrigins("*","http://localhost:5000");// list all domains
            }
        };
    }
}
Arfat Binkileb
  • 641
  • 4
  • 18
  • 2
    I would suggest not to use `*` in allowedOrigins. Instead user your Angular app's domain. `http://localhost:5000` for example – Arfat Binkileb Mar 24 '21 at 18:28
  • Sorry but I don't understand, 1) Which other settings should I remove 2) Where should I add the mentioned rows? Can you reply me by editing your original reply, so is more clear than in this comments? So much suggestions but I don't know exactly where should I apply. Thank you for your time. – Archimede Mar 24 '21 at 18:28
  • I have done exactly what you wrote, but I see the same error. I also tried to remove the allowOrigin row, and I have seen another error about the allow origin fault. Why? Thank you – Archimede Mar 25 '21 at 12:00
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/230373/discussion-between-archimede-and-arfat-binkileb). – Archimede Mar 25 '21 at 15:40
  • @Archimede Hi, I am having same error about CORS 'Access-Control-Allow-Origin' header contains multiple values. In my case, it is Spring Boot REST API and Angular client talking to it. All API endpoints are working fine. But one of them calls another API which adds its own CORS and returns it in response header therefore having multiple values. How would I address this? Much appreciated – pixel Apr 28 '22 at 18:00