Spring Cross Origin Resource Sharing (CORS) passage with JS frameworks Angular, React, Vue.js etc

Jonathan Turnock
Aug 22, 2019 · 3 min read

CORS is for security, ok, but why?

I don’t intend on making a long deep dive into CORS during this short blog. But we should know the fundamentals.

CORS is an access control mechanism. It’s designed to prevent unauthorised access to an API.

It uses HTTP headers to manage this ACL.

It uses Pre-flight requests when queries are sent across domains. So for example from your frontend server to your backend server.

The below flow chart, courtesy of Wikipedia highlights the path of a cross origin request.

By Bluesmoon — Own work, CC BY-SA 4.0, https://commons.wikimedia.org/w/index.php?curid=42452713

Chances are if you have made a cross origin request using your frontend framework the browser has blocked it because it did not contain the relevant access control headers.

There are two ways around this.

Disable Web Security in the Browser, not recommended but in some use cases this is ok.

This is OK when

  1. You are in development mode
  2. You don’t intent on having the origins different when in production (i.e. Angular SPA gets compiled and static files are included in the war/jar file
  3. When in a framework i.e. Electron and other browser windows cannot be opened and all the request sources are closed and trusted.

This is NOT OK when

  1. You are in anything other than development mode
  2. You intend on deploying the front end separate to the backend, i.e. to a dedicated web server.

Add the required headers and allow the required request types to be sent to your API

Some Solutions

Disabling Browser Security

I will provide some options here because in reality you don’t always own the API side, but you should make and effort to avoid disabling security.

You can disable browser security, give this a google, chrome has the ability to start with security disabled, it can also have an extension added so the state of on/off can be toggled. i.e. Allow-Control-Allow-Origin: *

If you are in Electron you can disable security by editing your main.js config and adding webSecurity: false to the webPreferences for the browser window creation.

function createWindow() {
var electronScreen = electron_1.screen;
var size = electronScreen.getPrimaryDisplay().workAreaSize;
// Create the browser window.
win = new electron_1.BrowserWindow({
x: 0,
y: 0,
width: size.width,
height: size.height,
webPreferences: {
nodeIntegration: true,
webSecurity: false,
devTools: false
}
});

Adding Appropriate Headers

On to the main topic and the reason for this blog.

If your API is built using spring boot you can control the response headers for requests to your API. The below is an example of how to grant the required headers to make CORS permissive.

You should work with this configuration and try to limit the content of Access-Control-Allow-Origin, bring it back from * to being as appropriate to let your requests succeed.

Also take not of the presence of the OPTIONS method. This is the request type sent in the Pre-Flight request and if its not being permitted you will get into difficulty completing the access control workflow of CORS.

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)
class CorsFilter implements Filter {

@Override
void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
final 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", "Authorization, Content-Type");
response.setHeader("Access-Control-Max-Age", "3600");
if (((HttpServletRequest) req).getMethod().equalsIgnoreCase("OPTIONS")) {
response.setStatus(HttpServletResponse.SC_OK);
} else {
chain.doFilter(req, res);
}
}

@Override
void destroy() {
}

@Override
void init(FilterConfig config) throws ServletException {
}
}

Conclusion

We have briefly discussed what CORS is, in a very compact manner, we have discussed where it is enforced and how requests are intercepted by the CORS access control.

Finally we have touched on how you can bring a solution to the table when it comes to implementing a CORS policy that best suits your architecture.

We have seen an example of how a Spring API needs to add headers and allow the OPTIONS request to be made. These fundamentals can be used to apply a solution to your API.

Jonathan Turnock

Written by

☕️Java 🍃 Spring 🐍Python 🐳Docker — Experienced Full Stack Java, Python, Angular and Electron developer.

More From Medium

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade