Performing Authentication on Routes with react-router-v4

In react-router v4, you can make use of render prop to Route along with the lifecycle methods to replace the onEnter functionality existing in react-router v3.

See this answer for more details:

onEnter prop in react-router v4

However since all you want to do is authentication in the onEnter prop, you could easily create a HOC that does that

const RequireAuth = (Component) => { 

    return class App extends Component { 
    
        componentWillMount() { 
            const getToken = localStorage.getItem('token'); 
            if(!getToken) { 
               this.props.history.replace({pathname: "https://stackoverflow.com/"}); 
            } 
        } 
        render() { 
           return <Component {...this.props} /> 
        }
    } 

} 

export { RequireAuth }

and use it like

<Route path={"/Dashboard"} component={RequireAuth(Dashboard)}/>

Edit: In case you need to make a network call to find if the use if authenticated of not, you would write the HOC like

 const RequireAuth = (Component) => { 

    return class App extends Component { 
        state = {
            isAuthenticated: false,
            isLoading: true
        }
    
        componentDidMount() {
            AuthCall().then(() => {
                this.setState({isAuthenticated: true, isLoading: false});
            }).catch(() => {
                this.setState({isLoading: false});
            })
        } 
        render() { 
           const { isAuthenticated, isLoading } = this.state;
           if(isLoading) {
               return <div>Loading...</div>
           }
           if(!isAuthenticated) {
               return <Redirect to="/login" />
           }
           return <Component {...this.props} /> 
        }
    } 

} 

export { RequireAuth }

Update:

In addition to the HOC, you can also go for the PrivateRoute component like

const PrivateRoute = ({component: Component, isAuthenticated, isLoading, ...rest }) => { 
           if(isLoading) {
               return <div>Loading...</div>
           }
           if(!isAuthenticated) {
               return <Redirect to="/login" />
           }
           return <Component {...this.props} /> 
        }
    } 
} 

 export { PrivateRoute };

and you can use it like

  class App extends Component { 
        state = {
            isAuthenticated: false,
            isLoading: true
        }
    
        componentDidMount() {
            AuthCall().then(() => {
                this.setState({isAuthenticated: true, isLoading: false});
            }).catch(() => {
                this.setState({isLoading: false});
            })
        } 
        render() { 
           <Router>
              <div>
                  <Route exact path={"/"} component={Home} />
                  <Route path={"/SignUp"} component={SignUp} />
                  <Route path={"/SignIn"} component={SignIn} />
                  <PrivateRoute path={"/Dashboard"} component={Dashboard} isAuthenticated={this.state.isAuthenticated} isLoading={this.isLoading}/>
               </div>
           </Router>
        }
    } 

   

Leave a Comment