1

I’m building a full stack react application. I have the stack operating and pulling information from the backend when I’m calling it from the frontend. I’m using axios on the frontend to hit the endpoints I’ve set up on the backend. I’m having an issue with frontend authentication though. I’m using passport and passport-google-oauth20 to log users in with Google OAuth2.0. I have this working correctly. The problem I’m having: when a user hits a specific URL (controlled by react-router-dom) I have a function called authVerify run that pings the backend and checks if the user is logged in (by looking at the cookie - not accessible in JS). The function runs correctly and correctly updates the state. I have a state field for authenticated originally set to false, and on a successful 200 response I setState for authenticated to true. But, the protected routes I’ve built aren’t working. If the user is authenticated, they should be able to go to that route. If not, they get redirected to the login page. But, everything just redirects to the login page.

Here is the Router.js code:

import React from 'react';
import axios from 'axios';
import { BrowserRouter, Route, Switch } from 'react-router-dom';

import PrivateRoute from './PrivateRoute';
import Login from './Login';
import SignUp from './SignUp';
import App from './App';
import NotFound from './NotFound';

class Router extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      authenticated: false,
    };
  }

  componentDidMount() {
    this.authVerify()
      .then((res) => {
        if (res.status === 200) {
          console.log(this.state);
          this.setState({
            authenticated: true,
          });
          console.log(this.state);
        }
      })
      .catch(err => console.log(err));
  }

  authVerify = () => axios.get('/authVerify')

  render() {
    return (
      <BrowserRouter>
        <Switch>
          <PrivateRoute path="/" component={App} />
          <Route exact path="/pages/signup" component={SignUp} />
          <Route exact path="/pages/login" component={Login} />
          <PrivateRoute path="/pages/dashboard" authenticated={this.state.authenticated} component={App} />
          <Route component={NotFound} />
        </Switch>
      </BrowserRouter>
    );
  }
}

export default Router;

And here is the PrivateRoute.js code:

import React from 'react';
import { Route, Redirect, withRouter } from 'react-router-dom';

const PrivateRoute = ({ component: Component, authenticated, ...rest }) => (
  <Route
    {...rest}
    render={props => (authenticated === true ? <Component {...props} /> : <Redirect to="/pages/login" />)}
  />
);

export default withRouter(PrivateRoute);

I have console logged the response from the API and I successfully get a 200 response. I’ve also console logged the state before and after the call to the API and before it’s false and after it’s true. But, I’m always redirected to the login page.

I think the issue is that the call to the API is taking too long and the component is mounting before authentication is verified. But, I thought by setting the state in the componentDidMount function would update the component and redirect appropriately. Any help would be appreciated.

Josh
  • 45
  • 3
  • 9

2 Answers2

2

I had the same problem when working with private routes, the issue is that your component is rendered before the resolution of your API call, the solution for me was to wait for the response to finish before rendering the component.

I used a isSendingRequest which starts as true and prevented my component from rendering (maybe you can display a spinner when this happens) after that when the request is finished, isSendingRequest is set to false and the component is rendered.

Hope it helps!

Rodrigo Ferreira
  • 1,045
  • 6
  • 11
  • 1
    Refactored and added a isSendingReqeust to state and it works! Two days of googling and you answered this in less than 10 minutes! Thank you! – Josh Jul 18 '18 at 17:28
  • 2
    can share your piece of code where you have used issendingrequest. – schezwan Software Aug 28 '18 at 06:25
  • Thanks! I was actually using redux-react-session, and it was a matter of checking if the session was loaded (using the `checked` flag) before rendering. – Adriana Pineda Jun 19 '19 at 03:50
0

Please always add root path route "/" below of all other routes like:

<Route path="/checkout" component={YourComponent} />
.....
.....
<Route path="/" component={App} />
Shahriat Hossain
  • 324
  • 2
  • 12