Authenticated routes using react-router

Published December 5, 2017 #react #howto

Here’s a simple walk through on how to use authenticated routes with react-router.

  1. create-react-app route-test
  2. cd route-test
  3. yarn add react-router-dom

And for src/App.js:

import React, { Component } from 'react';
import {
    BrowserRouter as Router,
    Route,
    Link,
    Switch
} from 'react-router-dom';

const Nav = () => (
  <ul>
    <li><Link to='/'>Home</Link></li>
    <li><Link to='/about'>About</Link></li>
    <li><Link to='/session'>Session</Link></li>
    <li><Link to='/secret'>Secret</Link></li>
  </ul>
)

const Welcome = () => (
  <div>
    <h1>Welcome</h1>
    <p>This is some text</p>
  </div>
)

const About = () => (
  <div>
    <h1>About</h1>
    <p>Sure, stuff</p>
  </div>
)

const Secret = () => (
  <div>
    <h1>This is a secret</h1>
    <p>Sorry, not everyone can see this</p>
  </div>
)

const Session = ({login}) => (
  <div>
    <button onClick={login}>Click me</button>
  </div>
)

class App extends Component {
  state = {login: false}
  login = () => {this.setState( {login: true} ) }

  render() {
    return (
      <Router>
        <div>
          <Nav/>
          { this.state.login && <p>Logged in</p>}
          <Switch>
            <Route path="/secret" component={Secret}/>
            <Route path="/about" component={About}/>
            <Route path="/session" component={() => <Session login={this.login}/> } />
            <Route component={Welcome}/>
          </Switch>
        </div>
      </Router>
    );
  }
}

export default App;

Secret isn’t so secret

Lets create an authenticated component. The idea is that if the user is not authenticated, we will redirect to /session which will show whatever login form we have.

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

class AuthenticatedRoute extends Component {
  render() {
    const {authed, component: Component, ...rest} = this.props;

    if( authed ) {
      return <Route {...rest} render={(props) => <Component {...props }/>}/>
    } else {
      return <Route {...rest} render={(props) => <Redirect to={{pathname: '/session', state: {from: props.location}}} />}/>
    }
  }
}

export default AuthenticatedRoute;

Now we just need to update the switch to use the new AuthenticatedRoute. We are passing in an authed property that the main App component is maintaining.

<AuthenticatedRoute authed={this.state.login} path=”/secret” component={Secret}/>

Now we need to update the Session component to handle the login. In the case that we aren’t logged in, we show a button that calls the login method on the container component. This will change the login state and trigger a rerender of the components. Once that happens, authed will be true so we look inside of the location property to see if there was a protected route stored in the router history state. If so, we redirect back to that. Otherwise, we redirect back to home.

const Session = ({authed,location,login}) => {
  if( authed ) {
    let l = location.location;
    let pathname = "/";
    if( l && l.state && l.state.from ) {
      pathname = l.state.from.pathname;
    }
    return <Redirect to={pathname}/>
  } else {
    return (
      <div>
        <button onClick={() => {login()}}>Click me</button>
      </div>
    )
  }
}

And finally, we need to wire all this up in the main routes.

<Route path="/session" render={(location) => <Session location={location} login={this.login} authed={this.state.authed}/> }/> } />

Here we aren’t just passing in component={Session} but rather a function that gets wired up to a number of local callbacks. This is mainly so that the login function can call setState and then trigger the render. In a case where this would be something that came from a server, you could use the normal asynchronous methods and not need to force this directly.

Read next

See also

Styling and theming with material-ui: React + Material Design

We’ve looked at building and styling with rmwc, now lets look a the king of the React Material libraries, Material-UI! The implementation strategy here is different — instead of including a generated CSS file that applies to all of the elements, each component includes the CSS that it needs in an isolated way. import Button from ‘material-ui/Button’; will include all of the necessary CSS to render that element. This is done with webpack basically.

Read more

Styling and theming with rmwc: React + Material Design

There are a couple of good material design libraries out there, and I’m going to build a basic site with create-react-app to test out how to really make them work. Material design released a new version of their web components, and we’re going to look at a few React libraries that will help us use them. Material Components For Web These components were written in SASS and JS. There are various ways to customize them and build your design.

Read more

Save your Medium articles to your computer in markdown

I really like the editing tools and community on Medium, but I want to keep all my writing in a centralized place. So I wrote a script based upon my dataflow programming with Rake post that pulls down my latest medium articles, converts to markdown, and downloads any associated images so I can keep my own copy on my domain. I really like the tools, but I want to own my data.

Read more