5
votes

express direct to the wrong endpoint on the production environment but works fine on development. I had built my application using express for back-end and react for front-end and passport for authentication, Here now I'm facing issue with endpoint /auth/google. when I click the button, it should direct to express endpoint auth, but express directs to react app not found component.

simply my app does not hit endpoint auth/google rather render react page

here the codes

server.js

app.use('/auth', require('./router/auth')) // should direct here
app.use('/media', require('./router/media')) 
app.use('/admin', require('./router/admin')) 
app.use('/user', require('./router/user'))

const httpServer = http.createServer(app)

if (process.env.NODE_ENV === 'production') {
 app.use(favicon(path.join(__dirname, '../' + 'build', 'favicon.ico')))

 app.use(express.static(path.join(__dirname, '../' + 'build')));

 app.get("*", (req, res) => { // but always goes here
 res.sendFile(path.join(path.join(__dirname, '../' + 'build', 'index.html')));
  });
}

const PORT = 8080

httpServer.listen(PORT, () => {
 console.log('Server up at:' + PORT)
})

/router/auth.js

router.get('/google', passport.authenticate('google', { // and should hit this 
  scope: ['profile', 'email']
}))
router.get(
  '/google/callback',
  passport.authenticate('google'),
  (req, res) => {
    req.app.set('user', res.req.user)
    return res.redirect('/auth/sign')
  }
)

module.exports = router

passport.js

export default function (passport) {
  passport.serializeUser(function (user, done) {
    done(null, user)
  })

  passport.deserializeUser(function (user, done) {
    done(null, user)
  })

  // GOOGLE OAuth
  passport.use(
    new GoogleStrategy(
      {
        clientID: GOOGLE_CLIENT_ID,
        clientSecret: GOOGLE_CLIENT_SECRET,
        callbackURL: '/auth/google/callback'
      },
      function (_, __, profile, done) {
        profile = {
          ...profile,
          email: profile.emails && profile.emails[0].value,
          profileUrl: profile.photos && profile.photos[0].value
        }
        authUser(profile, done) // function for save user
      }
    )
  )
}

react app.js


 <Switch>
          <Route path="/" exact component={Main} />
          <Route path="/home" exact component={Home} />
          <Route path="/ad/:id" exact component={Ad} />
          <PrivateRoute path="/postad" exact component={createAd} />
          <PrivateRoute path="/ad/edit/:id" exact component={UpdateAd} />
          <Route path="/user/:id" exact component={User} />
          <PrivateRoute path="/setting" exact component={Setting} />
          <PublicRoute path="/sign" exact component={ProviderSign} />
          <Route path="*" exact={true} component={PageNotFound} /> // but render this
 </Switch>

TLDR

My was was also redirecting to react page when it was set "proxy": "http://localhost:8080", and After I found this http-proxy-middleware and setup proxy on the client src folder

const proxy = require("http-proxy-middleware");

module.exports = app => {
  app.use(proxy("/auth/google", { target: "http://localhost:8080/" }));
  app.use(proxy("/auth/facebook", { target: "http://localhost:8080/" }));
};

after this works fine when I start my node server on port 8080 and client on port 3000,

And this is my login page button to hit endpoint /auth/google

<Button className={classes.authBtn}> 
 <a className={classes.removeStyle} href="/auth/google">Google</a>     
</Button>
1
Just to clarify, are you saying when you navigate to /auth/google you can see that it does hit the server but skips those routes and ends up in the catch all route on the server? Are you sure it's not always being by the client catch-all after the initial render?James
So this is happening only for the route /auth/google and not for any other route?Bhumil Sarvaiya
yeah, @James. this is only happening for /auth/googleC.K
I think @James is correct here. (I'm not a front end dev, so stand to be corrected). Try changing the catch-all handler to something else, e.g. notfound and then hit your button. If you get a client side error, you know you are not hitting the API. It doesn't look like you are sending a request to your API server.jeeves
Did you use create-react-app to generate the project? If so, what version? Did you at any point enable the service worker?Jon Church

1 Answers

1
votes

A solution for me is to, create a routes.js file like:

const express = require("express");
const router = express.Router();

const authRouter = require('./router/auth');
const mediaRouter = require('./router/media');
const adminRouter = require('./router/admin');
const userRouter = require('./router/user');

router.get("/", function(req, res, next) {
  res.status(200).json({
    isSuccess: true,
    message: "Server is up and running!"
  });
});

app.use('/auth', authRouter); 
app.use('/media', mediaRouter); 
app.use('/admin', adminRouter); 
app.use('/user', userRouter);

router.get("*", (req, res) => {
  res.status(200).json({
    isSuccess: false,
    message: "Invalid address!"
  });
});

module.exports = router;

Modify your server.js file as:

const httpServer = http.createServer(app);
const indexRouter = require("./routes"); // your routes.js

app.use("/api", indexRouter);

if (process.env.NODE_ENV === 'production') {
 app.use(favicon(path.join(__dirname, '../' + 'build', 'favicon.ico')))

 app.use(express.static(path.join(__dirname, '../' + 'build')));

 app.get("*", (req, res) => { // but always goes here
 res.sendFile(path.join(path.join(__dirname, '../' + 'build', 'index.html')));
  });
}

const PORT = 8080;

httpServer.listen(PORT, () => {
 console.log('Server up at:' + PORT)
})

And finally modify your auth.js as:

router.get('/google', passport.authenticate('google', { // and should hit this 
  scope: ['profile', 'email']
}))
router.get(
  '/google/callback',
  passport.authenticate('google'),
  (req, res) => {
    req.app.set('user', res.req.user)
    return res.redirect('api/auth/sign') // Changed this endpoint
  }
)

module.exports = router

This approach separates your API and Front-end routes. Hope this works for you.