Shikha A
Shikha A

Reputation: 178

Spring Boot CORS headers

I am new to CORS headers and implementing with Spring boot. I am enabling CORS header on POST service which accept request body.

First time preflight request is made which runs fine and return 200 but when actual post request is invoked, it always return 403 forbidden with response body "Invalid CORS request".

I have read almost all spring docs and all google/stackoverflow discussions but could not find out what am I missing..huh..

In Below snippet I have tested by adding crossOrigin at top of class and top of method but no luck.

@CrossOrigin(origins = "https://domain/", allowCredentials = "false")
@RequestMapping(value = ApplicationConstants.URI_PATH)
class MainController {
       @RequestMapping(value = '/postMethod', method = RequestMethod.POST)
       Map<String, Object> postMethod(HttpServletResponse servletResponse, 
       @RequestBody(required = false) AccessToken requestedConsumerInfo) {...}

For POST method - Preflight request is invoked and result is 200 but main POST call returns 403.

Call with OPTIONS: Status code 200

Response headers (616 B)
Access-Control-Allow-Credentials true
Access-Control-Allow-Headers content-type
Access-Control-Allow-Methods POST
Access-Control-Allow-Origin https://domain
Allow GET, HEAD, POST, PUT, DELETE, OPTIONS, PATCH
Cache-Control max-age=0, private, no-cache, …roxy-revalidate, no-transform
Connection close
Content-Length 0
Date Wed, 20 Dec 2017 17:57:14 GMT
Pragma no-cache
Server nginx/1.9.1
Strict-Transport-Security max-age=63072000; includeSubdomains;
Vary Origin,User-Agent
X-Frame-Options SAMEORIGIN
X-XSS-Protection 1; mode=block

Request headers (512 B)
Accept  text/html,application/xhtml+xm…plication/xml;q=0.9,*/*;q=0.8
Accept-Encoding gzip, deflate, br
Accept-Language en-US,en;q=0.5
Access-Control-Request-Headers  content-type
Access-Control-Request-Method   POST
Connection  keep-alive
Host    domain
Origin  https://domain
User-Agent  Mozilla/5.0 (Windows NT 6.1; W…) Gecko/20100101 Firefox/57.0

Call with POST: Status code 403

Response headers (364 B)
Cache-Control   max-age=0, private, no-cache, …roxy-revalidate, no-transform
Connection  close
Content-Length  20
Date    Wed, 20 Dec 2017 17:57:14 GMT
Pragma  no-cache
Server  nginx/1.9.1
Strict-Transport-Security max-age=63072000; includeSubdomains;
Vary    User-Agent
X-Frame-Options SAMEORIGIN
X-XSS-Protection    1; mode=block

Request headers (2.507 KB)  
Accept  application/json, text/plain, */*
Accept-Encoding gzip, deflate, br
Accept-Language en-US,en;q=0.5
Connection  keep-alive
Content-Length  102
Content-Type    application/json
Cookie  rxVisitor=1513720811976ARCUHEC…B4SL3K63V8|6952d9a33183e7bc|1
Host    domain
Origin  https://domain
Referer https://domain/home/account/register
User-Agent  Mozilla/5.0 (Windows NT 6.1; W…) Gecko/20100101 Firefox/57.0

Since this was not working, I have also tested by adding global configurations alone and also along with above snippet but no luck.

@Bean
    public WebMvcConfigurer corsConfigurer() {
        return new WebMvcConfigurerAdapter() {
            @Override
            void addCorsMappings(CorsRegistry registry) {
                super.addCorsMappings(registry);
                registry.addMapping(ApplicationConstants.MEMBER_URL_PATH)
                        .allowedOrigins("https://domain/")
                        .allowedMethods(HttpMethod.GET.toString(), 
                                   HttpMethod.POST.toString(), HttpMethod.PUT.toString());
            }
        }
    }

Upvotes: 1

Views: 4884

Answers (2)

Roberto Rodriguez
Roberto Rodriguez

Reputation: 3347

I had the same issue, then used the annotation @CrossOrigin and it works fine, but just for GET, when I tried to make a POST I still got Cross Origin error, then this fixed for me:

Create an interceptor and added the Access Controll headers to the response. (You might not need all of them)

public class AuthInterceptor extends HandlerInterceptorAdapter {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { 
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse httpResponse, Object handler, ModelAndView modelAndView)
            throws Exception { 
        httpResponse.setHeader("Access-Control-Allow-Methods", "POST, GET, PUT, OPTIONS, DELETE");
        httpResponse.setHeader("Access-Control-Allow-Headers", "*");
        httpResponse.setHeader("Access-Control-Allow-Credentials", "true");
        httpResponse.setHeader("Access-Control-Max-Age", "4800");
    } 
}

Then add the interceptor:

@Configuration
@EnableWebMvc 
public class WebConfig extends WebMvcConfigurerAdapter {

  @Override
    public void addInterceptors(InterceptorRegistry registry) {
        System.out.println("++++++ WebConfig addInterceptors() ");
        registry.addInterceptor(new AuthInterceptor()).addPathPatterns("/**");
    }

}

I hope this save you some time, it took me a while to get this working .

Upvotes: 1

roryhewitt
roryhewitt

Reputation: 4507

On the preflight OPTIONS request, the server should respond with all the following (looks like you're doing this already):

Access-Control-Allow-Origin, Access-Control-Allow-Methods, Access-Control-Allow-Headers, Access-Control-Allow-Credentials (if cookies are passed)

On the actual POST request, you'll need to return at least Access-Control-Allow-Origin and Access-Control-Allow-Credentials. You're not currently returning them for the POST response.

Upvotes: 2

Related Questions