Spring OAUTH2 and CORS Configuration

I recently added Oauth2 to a Restful API that I have been developing and it was quite fun despite the very many headaches of configuring the application. The application uses Spring MVC. Now after developing the API and testing that it works okay (I usually test the endpoints using Postman) and having the mobile app work okay, I assumed my work is done.

I decided that it would be a good idea to have an admin console which runs separately and would access information using the API developed. My thoughts for the admin app were it would be better if it is web based meaning it would run on the browser. As I set out to develop it, i figured I would need to enable CORS on the API application in order for the admin app to connect well since they would run on separate domains.

As I set out to configure CORS, I did the simple configuration for any Java web application, adding the CORS filter to web.xml. However upon testing, I realized that the OPTIONS request for oauth/token was failing with error code 401. Searching around I did not find any solutions which gave the correct answer. For me this is what worked.

  1. Web Security configuration, I had to permit requests to /oauth/token, particularly OPTIONS as shown below
http.csrf().disable().authorizeRequests().antMatchers(HttpMethod.OPTIONS, "/oauth/token").permitAll()

This would basically be on your WebSecurityConfigurerAdapter

2. In your ResourceServer if you override the configure method for HttpSecurity remember to also add the line above.

3. Add a custom CORS filter. I got this from

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

public SimpleCorsFilter() {
}

@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) res;
HttpServletRequest request = (HttpServletRequest) req;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "x-requested-with, authorization");

if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
response.setStatus(HttpServletResponse.SC_OK);
} else {
chain.doFilter(req, res);
}
}

@Override
public void init(FilterConfig filterConfig) {
}

@Override
public void destroy() {
}
}

The above code I got from https://stackoverflow.com/a/30638914/4124134

The code ensures that OPTIONS request do not go through the whole filter chain. If you have a web.xml file defined, add this filter above to your web.xml as below

<filter>
<filter-name>simpleCorsFilter</filter-name>
<filter-class>com.medium.muiruri.SimpleCorsFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>simpleCorsFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

With that I was able to send requests to the API from a different server/domain.

Note : if you read on the question from the StackOverflow link above, you are supposed to add @Order(-1) on your WebSecurity. That did not work for me and I would get 403 error.

Also if you had specified any other CORS filter in web.xml, you should remove it.

I hope this helps.