React Login

Sample Project

Download this sample project configured with your Auth0 API Keys.

System Requirements
  • React 15.3
Show requirements

Create an AuthService Class

The best way to have authentication utilities available across your application is to create a helper class. With the class in place, you can share an instance of it by passing it as a prop.

First, create an AuthService helper class to encapsulate the login functionality and save it inside the src/utils folder as AuthService.js.

Inside this class, create an Auth0Lock class that receives your Auth0 credentials and an options object. (For a list of available options, see: Lock: User configurable options). Instead of hard-coding your credentials in this class, they are passed from the AuthService constructor parameters to the Auth0Lock instance.

With the Auth0Lock instance, you can hook a callback for the authenticated event. This event will be triggered after every successful login, passing the user authentication token (idToken) as a parameter. The setToken method stores the idToken value in local storage.

// src/utils/AuthService.js

import Auth0Lock from 'auth0-lock'
import { browserHistory } from 'react-router'

export default class AuthService {
  constructor(clientId, domain) {
    // Configure Auth0
    this.lock = new Auth0Lock(clientId, domain, {
      auth: {
        redirectUrl: 'http://localhost:3000/login',
        responseType: 'token'
      }
    })
    // Add callback for lock `authenticated` event
    this.lock.on('authenticated', this._doAuthentication.bind(this))
    // binds login functions to keep this context
    this.login = this.login.bind(this)
  }

  _doAuthentication(authResult) {
    // Saves the user token
    this.setToken(authResult.idToken)
    // navigate to the home route
    browserHistory.replace('/home')
  }

  login() {
    // Call the show method to display the widget.
    this.lock.show()
  }

  loggedIn() {
    // Checks if there is a saved token and it's still valid
    return !!this.getToken()
  }

  setToken(idToken) {
    // Saves user token to local storage
    localStorage.setItem('id_token', idToken)
  }

  getToken() {
    // Retrieves the user token from local storage
    return localStorage.getItem('id_token')
  }

  logout() {
    // Clear user token and profile data from local storage
    localStorage.removeItem('id_token');
  }
}

The other helper methods shown above include: login (to call lock.show() and display the login widget), logout (to remove the local storage data), and loggedIn (that checks if an idToken exists and returns a boolean).

Use the AuthService to Protect Private Routes

To use the new class to protect routes, import AuthService in src/views/Main/routes.js and create a new instance.

// src/views/Main/routes.js

import React from 'react'
import {Route, IndexRedirect} from 'react-router'
import AuthService from 'utils/AuthService'
import Container from './Container'
import Home from './Home/Home'
import Login from './Login/Login'

const auth = new AuthService('YOUR_CLIENT_ID', 'YOUR_AUTH0_DOMAIN');

// validate authentication for private routes
const requireAuth = (nextState, replace) => {
  if (!auth.loggedIn()) {
    replace({ pathname: '/login' })
  }
}

export const makeMainRoutes = () => {
  return (
    <Route path="/" component={Container} auth={auth}>
      <IndexRedirect to="/home" />
      <Route path="home" component={Home} onEnter={requireAuth} />
      <Route path="login" component={Login} />
    </Route>
  )
}

export default makeMainRoutes

Note: The client ID and domain for your application are passed to the AuthService in the above snippet, but the downloadable samples contain a .env.example file that should be renamed to .env and populated with these values.

In routes.js, there is now an onEnter callback assigned to the /home route. This calls requireAuth, which checks whether the user is authenticated, and redirects to /login if they are not.

Create the Login View

Create a new Login component and save it in src/views/Main/Login/. This React component should accept an auth object (which is an instance of the AuthServce) as a prop.

// src/views/Main/Login/Login.js

import React, { PropTypes as T } from 'react'
import {ButtonToolbar, Button} from 'react-bootstrap'
import AuthService from 'utils/AuthService'
import styles from './styles.module.css'

export class Login extends React.Component {
  static propTypes = {
    location: T.object,
    auth: T.instanceOf(AuthService)
  }

  render() {
    const { auth } = this.props
    return (
      <div className={styles.root}>
        <h2>Login</h2>
        <ButtonToolbar className={styles.toolbar}>
          <Button bsStyle="primary" onClick={auth.login.bind(this)}>Login</Button>
        </ButtonToolbar>
      </div>
    )
  }
}

export default Login;

The Login button onClick event calls login to show the Auth0 Lock widget.

For this to work, auth needs to be included as a prop, which can be done from another component called Container.

Send auth from Router to Container Children

To use the auth parameter in various child components, it needs to be propagated down from from the Container component.

// src/views/Main/Container.js

import React, { PropTypes as T } from 'react'
import { Jumbotron } from 'react-bootstrap'
import styles from './styles.module.css'

export class Container extends React.Component {
  render() {
    let children = null;
    if (this.props.children) {
      children = React.cloneElement(this.props.children, {
        auth: this.props.route.auth //sends auth instance from route to children
      })
    }

    return (
      <Jumbotron>
        <h2 className={styles.mainTitle}>
          <img src="https://cdn.auth0.com/styleguide/1.0.0/img/badge.svg" />
        </h2>
        {children}
      </Jumbotron>
    )
  }
}

export default Container;

Persisting Application State

Lock uses redirect mode by default, meaning that a full page refresh will occur when users go through the authentication process in your application. This can be undesirable in single page apps, especially if the application contains state that should be displayed to the user again after they authenticate. For example, it may be the case that your users can initiate authentication from an arbitrary route within your single page app and you may want to return them to that location (along with any relevant state) after authentication is complete.

The recommended solution for this is to persist any necessary application state in local storage or a cookie before the user logs in or signs up. With this data, you can provide some custom post-authentication logic in the listener for the authenticated event to allow the user to pick up from where they left off.

In cases where storing application state is not possible, Lock's popup mode can be used. Please note that popup mode is not recommended. Known bugs in certain browsers prevent popup mode from functioning as expected under some circumstances.

Previous Tutorial
1. Getting Started
Next Tutorial
3. Custom Login
Use Auth0 for FREECreate free Account