51

As described in CORS preflight request fails due to a standard header if you send requests to OPTIONS endpoints with the Origin and Access-Control-Request-Method headers set then they get intercepted by the Spring framework, and your method does not get executed. The accepted solution is the use @CrossOrigin annotations to stop Spring returning a 403. However, I am generating my API code with Swagger Codegen and so I just want to disable this and implement my OPTIONS responses manually.

So can you disable the CORS interception in Spring?

baynezy
  • 6,493
  • 10
  • 48
  • 73

10 Answers10

54

For newer versions of spring boot:

@Configuration
public class WebConfiguration implements WebMvcConfigurer {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**").allowedMethods("*");
    }
}

The Kotlin way

@Configuration
class WebConfiguration : WebMvcConfigurer {
    override fun addCorsMappings(registry: CorsRegistry) {
        registry.addMapping("/**").allowedMethods("*")
    }
}
Panthro
  • 3,247
  • 2
  • 32
  • 37
42

From their documentation:

If you are using Spring Web MVC

@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {

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

If you are using Spring Boot:

@Configuration
public class MyConfiguration {

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

Yuriy Yunikov answer is correct as well. But I don't like the "custom" filter.

In case you have Spring Web Security which causes you trouble. Check this SO Answer.

d0x
  • 11,040
  • 17
  • 69
  • 104
  • 14
    This configuration enables CORS for all origins and all endpoints, sending "Access-Control-Allow-Origin: *", which is the opposite of disabling it. – timomeinen Nov 22 '18 at 21:15
  • 1
    As of Spring 5.0, WebMvcConfigurerAdapter is deprecated and WebMvcConfigurer used instead. – Scott Jan 02 '21 at 16:51
  • @timomeinen No, why do you say this, and why is this upvoted ? Last edit is one year before your comment, and the answer clearly allows all methods with "allowedMethods" – Tristan Apr 09 '23 at 17:38
  • @Tristan The question was how to **disable** CORS, but instead the answer sends the CORS header on every response. Sure, this will allow all origins to access the response, but it is still CORS enabled in the Spring filter. – timomeinen May 04 '23 at 09:49
  • Still not sure what you mean, for me and for every answerer below, the "disable" refers to "stop Spring returning a 403", and this is what this answer and other answers achieve to do. – Tristan May 06 '23 at 12:45
  • In case anyone is doing this on the latest version of Spring-Boot, you have to change `WebMvcConfigurerAdapter` to `WebMvcConfigurer`. If you have any doubts you can check the Spring-Boot's reference documentation at `CORS Support` section. – late1 Jul 16 '23 at 07:54
32

Try to add a following filter (you can customize it for you own needs and methods supported):

@Component
public class CorsFilter extends OncePerRequestFilter {

    @Override
    protected void doFilterInternal(final HttpServletRequest request, final HttpServletResponse response,
                                    final FilterChain filterChain) throws ServletException, IOException {
        response.addHeader("Access-Control-Allow-Origin", "*");
        response.addHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT, PATCH, HEAD");
        response.addHeader("Access-Control-Allow-Headers", "Origin, Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers");
        response.addHeader("Access-Control-Expose-Headers", "Access-Control-Allow-Origin, Access-Control-Allow-Credentials");
        response.addHeader("Access-Control-Allow-Credentials", "true");
        response.addIntHeader("Access-Control-Max-Age", 10);
        filterChain.doFilter(request, response);
    }
}
yyunikov
  • 5,719
  • 2
  • 43
  • 78
20

I use Spring Security in my Spring Boot application and enable access from specific domains (or from all domains).

My WebSecurityConfig:

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    // ...

    @Override
    protected void configure(HttpSecurity http) throws Exception {

        // add http.cors()
        http.cors().and().csrf().disable().authorizeRequests()
                .antMatchers("/get/**").permitAll()
                .antMatchers("/update/**").hasRole("ADMIN")
                .anyRequest().authenticated()
                .and()
                .httpBasic(); // Authenticate users with HTTP basic authentication

        // REST is stateless
        http.sessionManagement()
               .sessionCreationPolicy(SessionCreationPolicy.STATELESS);
    }

    // To enable CORS
    @Bean
    public CorsConfigurationSource corsConfigurationSource() {
        final CorsConfiguration configuration = new CorsConfiguration();

        configuration.setAllowedOrigins(ImmutableList.of("https://www.yourdomain.com")); // www - obligatory
//        configuration.setAllowedOrigins(ImmutableList.of("*"));  //set access from all domains
        configuration.setAllowedMethods(ImmutableList.of("GET", "POST", "PUT", "DELETE"));
        configuration.setAllowCredentials(true);
        configuration.setAllowedHeaders(ImmutableList.of("Authorization", "Cache-Control", "Content-Type"));

        final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);

        return source;
    }

}

Sometimes is needed to clear browser history before testing.

Detailed information may be seen here: http://appsdeveloperblog.com/crossorigin-restful-web-service/


Just for those who use Angular. From Angular I run requests to backend:

export class HttpService {

  username = '..';
  password = '..';
  host = environment.api;
  uriUpdateTank = '/update/tank';

  headers: HttpHeaders = new HttpHeaders({
    'Content-Type': 'application/json',
    Authorization: 'Basic ' + btoa(this.username + ':' + this.password)
  });

  constructor(private http: HttpClient) {
  }

  onInsertTank(tank: Tank) {
    return this.http.put(this.host + this.uriUpdateTank, tank, {
      headers: this.headers
    })
      .pipe(
        catchError(this.handleError)
      );
  }
...
}

Old version. In my Spring Boot application no other ways worked then this:

import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class RequestFilter implements Filter {

    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) {

        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;

        response.setHeader("Access-control-Allow-Origin", "*");
        response.setHeader("Access-Control-Allow-Methods", "POST, PUT, GET, OPTIONS, DELETE");
        response.setHeader("Access-Control-Allow-Headers", "x-requested-with, x-auth-token");
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Credentials", "true");

        if (!(request.getMethod().equalsIgnoreCase("OPTIONS"))) {
            try {
                chain.doFilter(req, res);
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        } else {
            System.out.println("Pre-flight");
            response.setHeader("Access-Control-Allowed-Methods", "POST, GET, DELETE");
            response.setHeader("Access-Control-Max-Age", "3600");
            response.setHeader("Access-Control-Allow-Headers", "authorization, content-type,x-auth-token, " +
                    "access-control-request-headers, access-control-request-method, accept, origin, authorization, x-requested-with");

            response.setStatus(HttpServletResponse.SC_OK);
        }

    }

    public void init(FilterConfig filterConfig) {
    }

    public void destroy() {
    }

}
Kirill Ch
  • 5,496
  • 4
  • 44
  • 65
10

Try this one if you have at least Java 8:

@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.cors().configurationSource(request -> new CorsConfiguration().applyPermitDefaultValues());
    }
}
marketmi
  • 28
  • 3
200OK
  • 701
  • 5
  • 14
7

Previous answers almost all about ENABLING CORS, this worked for me to disable.

@Configuration
public class MyConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.cors().and().csrf().disable();
    }

    @Bean
    public WebMvcConfigurer corsConfigurer() {
        return new WebMvcConfigurer() {
            @Override
            public void addCorsMappings(CorsRegistry registry) {
                registry.addMapping("/**").allowedMethods("*");
            }
        };
    }
}
oasis
  • 91
  • 1
  • 5
4

Spring MVC

@Configuration(proxyBeanMethods = false)
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**").allowedMethods("*").allowedHeaders("*");
    }
}

Spring Boot

@Configuration(proxyBeanMethods = false)
public class MyConfiguration {

    @Bean
    public WebMvcConfigurer corsConfigurer() {
        return new WebMvcConfigurer() {
            @Override
            public void addCorsMappings(final CorsRegistry registry) {
                registry.addMapping("/**").allowedMethods("*").allowedHeaders("*");
            }
        };
    }
}

Spring Security ( with Spring MVC or Spring Boot)

If using Spring Security, set following configuration additionally:

@Configuration(proxyBeanMethods = false)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(final HttpSecurity http) throws Exception {
        // ...

        // see also: https://docs.spring.io/spring-security/site/docs/5.5.3/reference/html5/#csrf-when
        http.csrf().disabled();

        // if Spring MVC is on classpath and no CorsConfigurationSource is provided,
        // Spring Security will use CORS configuration provided to Spring MVC
        http.cors(Customizer.withDefaults());
    }
}
3

None of the above worked for me. Here is how I did it for Spring-Boot 2.6.7 and Java 18.

(I know I will have to look this up myself the next time I have to set up a spring backend again):

@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.cors().and().csrf().disable();
    }

    @Bean
    public CorsFilter corsFilter() {
        final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        final CorsConfiguration config = new CorsConfiguration();
        config.addAllowedOrigin("*");
        config.addAllowedHeader("*");
        config.addAllowedMethod("*");
        source.registerCorsConfiguration("/**", config);
        return new CorsFilter(source);
    }
}
Jonathan R
  • 3,652
  • 3
  • 22
  • 40
3

Most of the answers use deprecated api. The following snippet will allow all headers, methods and urls to bypass the cors security rule using the suggested approach of configuring HttpSecurity by spring

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http.cors(httpSecurityCorsConfigurer -> 
        httpSecurityCorsConfigurer.configurationSource(request -> 
           new CorsConfiguration().applyPermitDefaultValues()
        )
    );
    return http.build();
}
ordago
  • 377
  • 3
  • 20
0

I use spring boot and this is solved my problem. I am using React for front-end.

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

@Configuration
public class CorsConfig extends WebMvcConfigurerAdapter {

    @Bean
    public WebMvcConfigurer corsConfigurer() {
        return new WebMvcConfigurerAdapter() {
            @Override
            public void addCorsMappings(CorsRegistry registry) {
                registry.addMapping("/**")
                        .allowedMethods("HEAD", "GET", "PUT", "POST", "DELETE", "PATCH");
            }
        };
    }
}
enesergen
  • 3
  • 3