Search code examples
reactjsnode.jsexpresscorspassport.js

Redirect from Express js throwing CORS errors in React/Next


I'm having a lot of trouble with CORS. I have an express server deployed on my domain, and am currently developing a react app locally on localhost:3000.

When I try to redirect after logging out with passport.js I am greeted with these three errors related to cors.

I have tried any number of combinations trying to get this up and running, simply can't get the redirect to work, and I'm not sure what I am missing here. Wondering if it can be an issue with the Next dev server? Any suggestions would be well appreciated!

Access to fetch at 'http://localhost:3000/login/' (redirected from 'https://api.invoice-app.naughty-cat.com/authentication/logout') from origin 'http://localhost:3000' has been blocked by CORS policy: 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.
GET http://localhost:3000/login/ net::ERR_FAILED
TypeError: Failed to fetch
    at handleLogoutClick (NavBar.jsx:43:11)
    at HTMLUnknownElement.callCallback (react-dom.development.js:17629:30)
    at Object.invokeGuardedCallbackImpl (react-dom.development.js:17667:30)
    at invokeGuardedCallback (react-dom.development.js:17729:39)
    at invokeGuardedCallbackAndCatchFirstError (react-dom.development.js:17741:35)
    at executeDispatch (react-dom.development.js:27186:13)
    at processDispatchQueueItemsInOrder (react-dom.development.js:27206:21)
    at processDispatchQueue (react-dom.development.js:27215:17)
    at dispatchEventsForPlugins (react-dom.development.js:27223:13)
    at eval (react-dom.development.js:27378:24)
    at batchedUpdates$1 (react-dom.development.js:21180:24)
    at batchedUpdates (react-dom.development.js:24349:24)
    at dispatchEventForPluginEventSystem (react-dom.development.js:27377:13)
    at dispatchEvent (react-dom.development.js:25416:17)
    at dispatchDiscreteEvent (react-dom.development.js:25392:17)

Here is my cors configuration:

app.use(
  cors({
    origin: "*", 
    methods: "GET,HEAD,PUT,PATCH,POST,DELETE",
    credentials: true
  })
);

Here is my route doing the redirect after passport.js logout:

authRouter.post('/logout', (req, res, next) => {
    req.logout(function(err){
        if(err){
            return next(err);
        }
        res.redirect('http://localhost:3000/login/');
    })
});

Here is my fetch that's failing:

fetch(`https://api.invoice-app.naughty-cat.com/authentication/logout`,
      { 
        method: "POST",
        redirect: 'follow',
        withCredentials: true,

      }).catch(err => console.log(err));

Edit: So as I am working with this more, I have discovered that login the route will work if it is just set as a link in html using href and everything works as expected. But when I change it to use a fetch (like the above logout example), it receives the same error. I will need to use fetches since the logout route must be a post request. Any ideas what I am missing here?

Edit 2: I have tested normal routes not involving oauth and they are all able to go through just fine. It's only the oauth routes that are throwing this error.


Solution

  • Alright after some digging it appears that using fetch or axios cuases some common problems with this. In the end I was able to get things up and running using the following code. Not totally ideal, but it is pretty clean and efficient. The get request to login can be any kind of link etc, but I had to make the post request to logout a form so that it would send as such.

    <Link
      href={`https://api.invoice-app.naughty-cat.com/authentication/github`}
      className="bodyText font-bold hover:text-purple"
      onClick={() => {
        setIsProfileOpen(!isProfileOpen);
      }}
    >
      Sign in with Github
    </Link>
    
    <form
      action="https://api.invoice-app.naughty-cat.com/authentication/logout"
      method="POST"
    >
      <button
        type="submit"
        className="bodyText font-bold hover:text-purple"
        onClick={() => setIsProfileOpen(!isProfileOpen)}
      >
        Sign Out
      </button>
    </form>