Story
The following code is an implementation of a CORS filter that just works fine without a security layer.
public class SimpleCorsFilter implements Filter { @Override public void init(final FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain) throws IOException, ServletException { HttpServletResponse resp = (HttpServletResponse) response; HttpServletRequest req = (HttpServletRequest) request; resp.setHeader("Access-Control-Allow-Origin", "*"); resp.setHeader("Access-Control-Allow-Methods", "*"); resp.setHeader("Access-Control-Max-Age", "3600"); resp.setHeader("Access-Control-Allow-Headers", "x-requested-with, authorization, Content-Type, Authorization, credential, X-XSRF-TOKEN"); } @Override public void destroy() { } }
However, to use this filter with secured resources, the preflight check will raise a 401 Unauthorized error in the browser. That is because the prelight OPTIONS
request doesn't have any authorization header with it to be sent to the server.
Solution
Intercept the preflight OPTIONS
response and set the response as a 2XX status code.
@Override public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain) throws IOException, ServletException { // set headers.. omitted for brevity if ("OPTIONS".equalsIgnoreCase(req.getMethod())) { resp.setStatus(HttpServletResponse.SC_OK); } else { chain.doFilter(request, response); } }
Lesson Learnt
OPTIONS
preflight check could be intercepted and set a success status code back to the client to proceed with the actual request.