3

I have a single page client being served by a Spring Boot REST MVC API application (spring boot version 1.5.2).

My app is secured via Auth0 JWT tokens. When things are working, the CORS headers for responses are provided by a ServletFilter that gets configured as part of setting up the security:

  protected void configure(HttpSecurity http) throws Exception {
    ...
    http.addFilterBefore(simpleCORSFilter(), Auth0AuthenticationFilter.class);
    ...
  }

This seems to work everywhere I've tested it so far - but one place where it's not working is with the default Spring error page (path "/error", rendered by default by the BasicErrorController class).

When there's an exception thrown in my service methods, the error page works and renders the content I want as JSON in the response body, but the client app can't access the http response body because the response lacks CORS headers.

So the question: "how do I add CORS headers to the error page"?

Should I be removing the CORS filter from my security setup and applying the CORS filter more globally? Where would that be done - I can't find anything relevant in the Spring doccumentation.

Or should I be writing a custom Error controller? The only example of a custom error controller in the documentation just seems to allow you to return a string.

Shorn
  • 19,077
  • 15
  • 90
  • 168
  • FWIW for future readers: if you are simply trying to add CORS or other content-security headers to **static** error pages (and other static content), you may follow a [different approach](https://stackoverflow.com/questions/43780327/how-to-add-response-header-when-reaching-static-content-using-spring-boot/70024617#70024617). – Janaka Bandara Nov 19 '21 at 02:52

2 Answers2

2

You can define a separate Controller for Error and allow cross origin to it using

@CrossOrigin("*")
Poorvi Nigotiya
  • 438
  • 1
  • 4
  • 16
1

Combining Poorvi's answer with Joni Karppinen's custom error controller code gives:

@RestController
public class ErrorController 
implements org.springframework.boot.autoconfigure.web.ErrorController 
{
  private static final String PATH = "/error";

  @Autowired private ErrorAttributes errorAttributes;

  @Override
  public String getErrorPath(){
    return PATH;
  }

  // I guess when time comes to lock down cors header, we could use a spring 
  // value configuration here to share with corsfilter.
  @CrossOrigin("*")  
  @RequestMapping(value = PATH, produces = "application/json")
  public @ResponseBody
  ErrorJson error(HttpServletRequest request, HttpServletResponse response){
    return new ErrorJson(
      response.getStatus(), 
      getErrorAttributes(request, false) );
  }

  private Map<String, Object> getErrorAttributes(
    HttpServletRequest request,
    boolean includeStackTrace
  ){
    RequestAttributes requestAttributes = new ServletRequestAttributes(request);
    return errorAttributes.getErrorAttributes(
      requestAttributes,
      includeStackTrace);
  }  

}

class ErrorJson {

  public Integer status;
  public String error;
  public String message;
  public String timeStamp;
  public String trace;

  public ErrorJson(int status, Map<String, Object> errorAttributes){
    this.status = status;
    this.error = (String) errorAttributes.get("error");
    this.message = (String) errorAttributes.get("message");
    this.timeStamp = errorAttributes.get("timestamp").toString();
    this.trace = (String) errorAttributes.get("trace");
  }

}

Which seems to do the job for me.

Shorn
  • 19,077
  • 15
  • 90
  • 168