CORS issue during development with Cloudflare tunnel not reaching my backend

Topic summary

A developer encountered a CORS error when trying to fetch data from their Shopify app backend through a customer account extension. The preflight request triggered by the Authorization header was failing, but the request never reached the Express server.

Key findings:

  • Removing the Authorization header allowed requests to reach the server without CORS errors
  • The issue was traced to Cloudflare tunnel not properly proxying preflight requests
  • Root cause: Missing CORS configuration in Vite’s defineConfig

Solution:
Adding cors: true to the Vite configuration’s server settings resolved the issue:

server: {
  cors: true,
}

Important caveat: This cors: true setting should only be used for development. It creates security vulnerabilities in production and should be replaced with more restrictive CORS configurations before releasing the app.

Summarized with AI on October 24. AI used: claude-sonnet-4-5-20250929.

I’m trying to reach my the backend server of my shopify app from a customer account extension (which doesn’t support app proxy) using the following code:

  useEffect(() => {
    void (async () => {
      const token = await sessionToken.get();
      void fetch(`${process.env.APP_URL}/api/extensions/hello-world`, {
        headers: {
          Authorization: `Bearer ${token}`,
        },
      })
        .then((res) => res.json())
        .then((data) => {
          console.log('data', data);
        });
    })();
  }, []);

This will fail with the CORS error:

Access to fetch at 'https://kw-soup-tvs-floor.trycloudflare.com/api/extensions/hello-world' from origin 'https://extensions.shopifycdn.com' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

The preflight request triggered by the inclusion of the Authorization header is failing here, but the request never reaches my server. I am logging all requests (backend is an express app from an old template).

If I remove the Authorization header, the request is logged on my server and no CORS error is triggered.

The issue seems to be Cloudflare not properly proxying the preflight request to my server. How can I fix this? I would rather not have to configure my own tunnel, since this setup is supposed to work for the rest of the team and I don’t want to complicate their setup.

Thans.

Is this an LLM response?

1 Like

So my setup is using an old template that uses express for the backend, and the main entry point for the app is the frontend with vite that proxies api/ requests to that express app. I needed to change the cors setting in the defineConfig and that solved it.

You may want to have FOR DEVELOPMENT something like this in the vite.config.js file:  server: {
    host: "localhost",
    port: process.env.FRONTEND_PORT,
    hmr: hmrConfig,
    proxy: {
      "^/(\\?.*)?$": proxyOptions,
      "^/api(/|(\\?.*)?$)": proxyOptions,
    },
    cors: true, // LOOK HERE. ADD THIS.
  },

Alternatively, you can add an object with configurations that are more suitable to production. DO NOT LEAVE THE cors: true when you release your app as it opens up a security issue.