CORS is dumb. CORS is here to stay. CORS has a bit of usefulness. As my daughter opined recently, cry me a river, build a bridge, and get over it.

After spending days on it, I now have a five minute fix for CORS in a dev environment where the frontend is split from the backend during development.

GIVEN:

  • a server that serves up your RESTful API using backend data
  • that same server, serving up your nicely bundled front end, after you bake it for prod
  • https in prod, and http in dev
  • a modern front end development environment that maximizes your local web development speed while also bundling it tight for prod ( 💕 Vite 💕 )

You may have been sailing along with that sweet setup for a while now. But then one day, CORS arrives in your neighborhood. Perhaps you realize your Node front end can now use native fetch(), how nice (at first). Or your browser just got updated and all of a sudden it’s very unhappy serving your JWT tokens. Any way you get there, you will probably hit CORS issues. They tell you you are a bad person for trying to reach your backend from your frontend. Bad dev!

The problem is that is actually now blocked as a cross-site request. This blockage is now ubiquitous. How else can you still get to your favorite awful monster sites if they are sideloading dozens of malware ads? Why should megasite be responsible for the ads they serve? Let the browser block them! We need to protect the sheeple!! But i digress…

To fix your CORS issues, quickly, you simply add proxying to your Vite environment. The proxy takes all your backend calls, sends them off, and when they return, gently stuffs all the weird painful CORS headers you need in the response to keep your frontend from having a seizure.

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [react()],
  server: {
    // For back end calls, make sure to use the API prefix.
    // Our vite dev environment will proxy those calls to the back end,
    // and return them to us, with fetch's xss concerns disabled via CORS:
    //    front -> proxy -> back -> proxy -> (ADD CORS) -> front
    proxy: {
      '/api': {
        'target': 'http://backend:8080',
        changeOrigin: true,
      },
    },
    port: 8008,
  },
})

Beautiful. In addition to that, if you can just slightly touch your server side cookie header to make it fit the CORS rulebook, you can get all that cross-site protection in prod, and never deal with a CORS issue in local dev again:

if (dev_environment) {
    cookie_header += " SameSite=Lax;";
  } else {
    cookie_header += " Secure; SameSite=Strict;";
  }