Forbes magazine logo Ranked Best Coding Bootcamps 2023

React Router Restricted Routes

Altcademy Team wrote on 7 February 2018

This document serves as an annotated guide to the official react router documentation on restricted routes.

To start, we need to setup a base app with a few routes and a couple links to navigate.
language=>JSX import React from 'react' import { BrowserRouter as Router, Route, Link, Redirect, withRouter } from 'react-router-dom' const AuthExample = () => ( <Router> <div> <AuthButton/> <ul> <li><Link to="/public">Public Page</Link></li> <li><Link to="/protected">Protected Page</Link></li> </ul> <Route path="/public" component={Public}/> <Route path="/login" component={Login}/> <PrivateRoute path="/protected" component={Protected}/> </div> </Router> ) // Add the other functions and components here export default AuthExample
To make this example app work, we need to build the following components and functions.
  • fakeAuth - an object that emulates authentication
  • AuthButton - a component that handles signing out and provides login status
  • PrivateRoute - a higher order component that verifies whether user is logged in
  • Login - a component page that lets the user login
  • Public - a component page that shows the public page
  • Protected - a component page that shows the protected page

fakeAuth

We need an object to emulate logging in, signing out, and provides an authentication state. To do this, we create the fakeAuth object with three properties:

  • isAuthenticated - stores the login state (true or false)
  • authenticate - [function (cb)] a function that accepts a callback function, will change isAuthenticated to true and execute the callback function after 100 milliseconds.
  • signout - [function (cb)] a function that accepts a callback function, will change isAuthenticated to false and execute the callback function after 100 milliseconds.

The object looks like this:
language=>JSX const fakeAuth = { isAuthenticated: false, authenticate(cb) { this.isAuthenticated = true setTimeout(cb, 100) // fake async }, signout(cb) { this.isAuthenticated = false setTimeout(cb, 100) } }
In production scenario, you are likely to keep the isAuthenticated state (session state probably a better name) in a redux store so it can be easily shared across the application. The authenticate and signout functions will be making actual API requests to the server to perform those processes.

AuthButton

The AuthButton component will show a simple message prompting the login status, and display a signout button if the user is already signed in. A simple function component will do the job as there is no state required in this component. We wrap the component with withRouter function so it will have access to the router prop history so it can change the url to root / when the user signs out.
language=>JSX const AuthButton = withRouter(({ history }) => ( fakeAuth.isAuthenticated ? ( <p> Welcome! <button onClick={() => { fakeAuth.signout(() => history.push('/')) }}>Sign out</button> </p> ) : ( <p>You are not logged in.</p> ) ))
In production scenario, you will probably change the "You are not logged in." paragraph to a login button instead.

PrivateRoute

The PrivateRoute component is a higher order component, which means it accepts another component as a prop and returns a component. Its use is to simply check whether the user is logged in and decides whether to return the restricted component or redirect the user to the login page. At its heart, it uses a Route component from react-router-dom. The path prop is passed to Route via the ...rest object spread. If the user is not logged in, a Redirect component is returned that brings the user to the login page. A state prop with the current location data is passed to redirect so that after the user logs in, we can redirect the user to the restricted page. Here is the code.
language=>JSX const PrivateRoute = ({ component: Component, ...rest }) => ( <Route {...rest} render={props => ( fakeAuth.isAuthenticated ? ( <Component {...props}/> ) : ( <Redirect to={{ pathname: '/login', state: { from: props.location } }}/> ) )}/> )

Login

The Login component displays a login button, and handles the redirection to the restricted page after login. It uses a state to determine execution of the redirection. After the user clicks login, it calls fakeAuth.authenticate and passes it a callback that will change the state property redirectToReferrer to true. After the state change, the component re-renders and a Redirect component is returned to bring the user back to the restricted page.
language=>JSX class Login extends React.Component { state = { redirectToReferrer: false } login = () => { fakeAuth.authenticate(() => { this.setState({ redirectToReferrer: true }) }) } render() { const { from } = this.props.location.state || { from: { pathname: '/' } } const { redirectToReferrer } = this.state if (redirectToReferrer) { return ( <Redirect to={from}/> ) } return ( <div> <p>You must log in to view the page at {from.pathname}</p> <button onClick={this.login}>Log in</button> </div> ) } }

Public and Protected page

These two are simple, we just need a h3 to provide a prompt which page the user is on.
language=>JSX const Public = () => <h3>Public</h3> const Protected = () => <h3>Protected</h3>
That's all you need to setup a restricted route with React Router. The full code is pasted below for review.
language=>JSX import React from 'react' import { BrowserRouter as Router, Route, Link, Redirect, withRouter } from 'react-router-dom' const AuthExample = () => ( <Router> <div> <AuthButton/> <ul> <li><Link to="/public">Public Page</Link></li> <li><Link to="/protected">Protected Page</Link></li> </ul> <Route path="/public" component={Public}/> <Route path="/login" component={Login}/> <PrivateRoute path="/protected" component={Protected}/> </div> </Router> ) const fakeAuth = { isAuthenticated: false, authenticate(cb) { this.isAuthenticated = true setTimeout(cb, 100) // fake async }, signout(cb) { this.isAuthenticated = false setTimeout(cb, 100) } } const AuthButton = withRouter(({ history }) => ( fakeAuth.isAuthenticated ? ( <p> Welcome! <button onClick={() => { fakeAuth.signout(() => history.push('/')) }}>Sign out</button> </p> ) : ( <p>You are not logged in.</p> ) )) const PrivateRoute = ({ component: Component, ...rest }) => ( <Route {...rest} render={props => ( fakeAuth.isAuthenticated ? ( <Component {...props}/> ) : ( <Redirect to={{ pathname: '/login', state: { from: props.location } }}/> ) )}/> ) const Public = () => <h3>Public</h3> const Protected = () => <h3>Protected</h3> class Login extends React.Component { state = { redirectToReferrer: false } login = () => { fakeAuth.authenticate(() => { this.setState({ redirectToReferrer: true }) }) } render() { const { from } = this.props.location.state || { from: { pathname: '/' } } const { redirectToReferrer } = this.state if (redirectToReferrer) { return ( <Redirect to={from}/> ) } return ( <div> <p>You must log in to view the page at {from.pathname}</p> <button onClick={this.login}>Log in</button> </div> ) } } export default AuthExample

Trusted by

Students and instructors from world-class organizations

Imperial College London
Carnegie Mellon University
City University of Hong Kong
Hack Reactor
Cisco Meraki
University of Oxford
Swift
Bazaarvoice
Waterloo
Uber
AtlanTech
Tumblr
Boston College
Bombardier Aerospace
University of St. Andrews
New York University
Minerva Schools at KGI
Merrill Lynch
Riot Games
JP Morgan
Morgan Stanley
Advanced Placement®
Google
KPMG
The University of Hong Kong
University of Toronto
SCMP
Moat
Zynga
Hello Toby
Deloitte
Goldman Sachs
Yahoo
HSBC
General Assembly
Tesla
McGill University
Microsoft

Join the upcoming Cohort #91

Enroll for July 1st, 2024