Search code examples
expresshttp-redirectcorskeycloakopenid-connect

Express.js res.redirect() is not working when using fetch()


I keep getting CORS error when I use fetch() to hit endpoint that has res.redirect(). It's only problematic when I use fetch(), because redirect works fine if I directly type in browser's address bar or use <a> tag in frontend code.


Backent Code:

const corsOptions = {
  origin: function (origin, callback) {
    callback(null, true);
  },
};

/** THIS SENDS FRONTEND (HTML) CODE **/
router.get("/", (req, res) => {
  res.sendFile(path.join(__dirname, "view", "index.html"));
});

/** THIS IS THE REDIRECT ENDPOINT **/
// I tried removing/modifying cors but nothing worked.
router.get("/redirector", cors(corsOptions), (req, res) => {
  res.redirect("https://google.com");
});

app.use(
  bodyParser.urlencoded({
    extended: true,
  }),
  bodyParser.json(),
  router
);

const server = http.createServer(app);
server.listen(8080, () => {
  console.log("http://localhost:8080");
});

Frontend Code:

<body>
   <h1>Home</h1>
   <br />
   <button id="btn">FETCH TO REDIRECT ROUTE</button>

   <script>
      const btn = document.getElementById('btn');
      btn.addEventListener('click', async () => {
         try {
            const response = await fetch('/redirector');
         } catch (error) {
            console.error(error);
         }
      });
   </script>
</body>

Visual Representation of above codes: enter image description here


I know this has to work somehow because NPM packages like keycloak-connect implements same redirect logic and it works just fine. I just can't figure out how to make it work myself.


Solution

  • It's unclear that you understand what await fetch('/redirector'); does. All that does is obtain whatever response comes from /redirector for your Javascript. It does NOT display anything in the browser. It does not cause the browser to navigate to a new page. It just gets data for your Javascript. And, because it's a Javascript request from within a web page, it is subject to CORS limitations which limits where it can be redirected to.

    If you want to cause the browser to redirect to a new page, then set window.location to the new location you want the browser to go to, don't use fetch().

    If you want fetch() to follow a redirect (which it does by default), then the redirect has to be to a location that you have cross origin permissions to or it will not be able to follow the redirect.

    So, for example, if what you're really trying to accomplish with the fetch() call is to get the redirect location and then change the browser page to that location, you can do this:

    window.location = "/redirector";
    

    That will cause the browser to go to /redirector which will then successfully see the redirect and tell the browser to go to: https://google.com. Letting the browser follow the redirect in this way will not run into a CORS error.