The React ecosystem is huge, and there are many options for modules which aim to solve the tricky parts of making React work well. Most real-world React apps share some common requirements, and these requirements revolve around state management and routing. Arguably the most common options for these needs are Flux and React Router.

Ken has an awesome series on React and Flux here at Scotch, and there's certainly no shortage of instruction on these topics around the web. However, there are some other things we need to think about when it comes to building a real-world React app that aren't covered as often: how to call a remote API and how to authenticate users.

In this tutorial we'll build a simple contacts application that receives data from an API. We'll use an Express (NodeJS) server for this, but it should be noted early on that it isn't necessary to use Node. Rather, we can use any kind of server we want, as long as it can output JSON data.

The best way to do user authentication for any single page app is with JSON Web Tokens (JWT). There are a lot of details involved with setting up JWT authentication from scratch, so instead we'll use Auth0.

With Auth0, we can just drop in a script tag and we get immediate access to a login box and features like social login, multifactor authentication, and more.

When we sign up for Auth0, we get a free account that gives us 7,000 free users and two social identity providers. The best part is that this account is production-ready, so we have everything we need to get going with a real-world app.

Let's get started!

In this tutorial we're going to use React with ES2015, and this means that we'll need a transpiler to make sure we get all the features we expect and that it will work across all browsers. We'll use webpack for this, and the easiest way to get started with new React + Webpack project is to use a generator such as Yeoman.

Upgrade Your JS Go from vanilla JavaScript 👉 React

Watch for FREE

npm install -g yo npm install -g generator-react-webpack mkdir react-auth && cd react-auth yo react-webpack

We get some prompts to follow, and at the end of it we should have a new React project wired up with webpack.

We'll need some extra dependencies that don't come with a Yeoman installation, so let's grab those now.

npm install flux react-router bootstrap react-bootstrap keymirror superagent

We need to tweak our url-loader in our webpack config slightly so that we can make use of React Bootstrap.

... { test : /\.(png|woff|woff2|eot|ttf|svg)$/ , loader : 'url-loader?limit=8192' } , ...

Another thing we should do right off the bat is make a change to the route that webpack uses to serve the project, or else we'll get some issues with React Router. Open up server.js and down at the bottom, change:

open ( 'http://localhost:' + config.port + '/webpack-dev-server/' ) ;

to

open ( 'http://localhost:' + config.port ) ;

Let's create our Express server right as we get started so it will be ready to be consumed by our React app. This is actually a rather simple server and we just need a few modules to support it.

mkdir react-auth-server && cd react-auth-server npm init npm install express express-jwt cors touch server.js

The express-jwt package that we're bringing in will be used to create our authentication middleware to protect any API endpoints we want.

const express = require ( 'express' ) ; const app = express ( ) ; const jwt = require ( 'express-jwt' ) ; const cors = require ( 'cors' ) ; app . use ( cors ( ) ) ; const authCheck = jwt ( { secret : new Buffer ( 'YOUR_AUTH0_SECRET' , 'base64' ) , audience : 'YOUR_AUTH0_CLIENT_ID' } ) ; var contacts = [ { id : 1 , name : 'Chris Sevilleja' , email : 'chris@scotch.io' , image : '//gravatar.com/avatar/8a8bf3a2c952984defbd6bb48304b38e?s=200' } , { id : 2 , name : 'Nick Cerminara' , email : 'nick@scotch.io' , image : '//gravatar.com/avatar/5d0008252214234c609144ff3adf62cf?s=200' } , { id : 3 , name : 'Ado Kukic' , email : 'ado@scotch.io' , image : '//gravatar.com/avatar/99c4080f412ccf46b9b564db7f482907?s=200' } , { id : 4 , name : 'Holly Lloyd' , email : 'holly@scotch.io' , image : '//gravatar.com/avatar/5e074956ee8ba1fea26e30d28c190495?s=200' } , { id : 5 , name : 'Ryan Chenkie' , email : 'ryan@scotch.io' , image : '//gravatar.com/avatar/7f4ec37467f2f7db6fffc7b4d2cc8dc2?s=200' } ] ; app . get ( '/api/contacts' , ( req , res ) => { const allContacts = contacts . map ( contact => { return { id : contact . id , name : contact . name } } ) ; res . json ( allContacts ) ; } ) ; app . get ( '/api/contacts/:id' , authCheck , ( req , res ) => { res . json ( contacts . filter ( contact => contact . id === parseInt ( req . params . id ) ) ) ; } ) ; app . listen ( 3001 ) ; console . log ( 'Listening on http://localhost:3001' ) ;

We've got an array of contacts data here that is being returned in some fashion at our two endpoints. For the /api/contacts endpoint, we're using map to pick out just the id and name fields from the objects in the array. For the /api/contacts/:id endpoint, we're looking for the contact with a specific id and returning the whole object for just that contact. For the sake of simplicity, we're just mocking out data retrieval here. In an actual application, this data would be queried from a database.

You'll likely have noticed the authCheck that we set up near the top in our Express server. This is the middleware that is applied to the /api/contacts/:id route, and it requires some identifying information from us. Most notably, we need to give it a secret key which will be checked against the decoded JWTs that come to the API to verify validity. When we use Auth0, all we need to do is provide the middleware our secret key and client ID.

If you haven't already signed up for Auth0, head over and do that now. After you sign up, you'll find your application's client secret and client ID in the management area. Once you grab those keys, you can place them in the appropriate spots in the middleware, and you'll be good to go.

Be sure to put your localhost domain and port in the "Allowed Origins" textarea so that Auth0 will allow requests from your test domain.

Let's start by setting up our index.js file. We'll need to modify the file that was provided by the Yeoman generator to work for our app.

import 'core-js/fn/object/assign' ; import React from 'react' ; import ReactDOM from 'react-dom' ; import { browserHistory } from 'react-router' ; import Root from './Root' ; ReactDOM . render ( < Root history = { browserHistory } / > , document . getElementById ( 'app' ) ) ;

We're rendering a component called Root , which is passed a prop called browserHistory , against a DOM element called app .

To finish out the routing setup, we'll need to create a Root.js file to handle our routes.

import React , { Component } from 'react' ; import { Router , Route , IndexRoute } from 'react-router' ; import Index from './components/Index' ; import ContactDetail from './components/ContactDetail' ; import App from './components/App' ; class Root extends Component { render ( ) { return ( < Router history = { this . props . history } > < Route path = '/' component = { App } > < IndexRoute component = { Index } / > < Route path = '/contact/:id' component = { ContactDetail } / > < / Route > < / Router > ) ; } } export default Root ;

With React Router we can wrap individual Route s within a top Router and point them to specific paths and components. The Router uses a parameter called history which is used to parse the URL bar and construct location objects. We're passing down a prop called history from index.js for this, which we saw previously.

We should also take this opportunity to include the Lock widget. We can either install this with npm and include it in our webpack build, or we can include it as a script tag. Let's bring it in as a script tag for now, just for the sake of simplicity.

... < script src = " //cdn.auth0.com/js/lock-9.1.min.js " > </ script > < meta name = " viewport " content = " width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no " /> ...

The first component that we set up shoud be our top-level App component. Go ahead and rename Main.js to App.js and bring in some of the components from React Bootstrap.

import 'normalize.css/normalize.css' ; import 'bootstrap/dist/css/bootstrap.min.css' ; import React , { Component } from 'react' ; import Header from './Header' ; import Sidebar from './Sidebar' ; import { Grid , Row , Col } from 'react-bootstrap' ; class AppComponent extends Component { componentWillMount ( ) { this . lock = new Auth0Lock ( 'YOUR_AUTH0_CLIENT_ID' , ' YOUR_AUTH0_DOMAIN ) ; } render ( ) { return ( < div > < Header lock = { this . lock } > < / Header > < Grid > < Row > < Col xs = { 12 } md = { 3 } > < Sidebar / > < / Col > < Col xs = { 12 } md = { 9 } > { this . props . children } < / Col > < / Row > < / Grid > < / div > ) ; } } export default AppComponent ;

We've got some other components that we're calling, namely Header and Sidebar . We'll create those components next, but for now, let's focus on what's happening in componentWillMount . This is where we can set up our Auth0Lock instance, and to do so, we just need to call a new Auth0Lock and pass in our client ID and client domain. As a reminder, these two items can be retrieved from your Auth0 management area.

One important thing to note here is that we're calling {this.props.children} in the second Col . This will allow us to display child routes from React Router in this area, and in this way we can have a fixed sidebar with a dynamic view in the main portion of the app.

We're also passing down the Auth0Lock instance as a prop into Header , so let's create that next.

Let's put in a navbar header which will also serve as the location for some buttons for allowing users to log in and log out of the app.

import React , { Component } from 'react' ; import { Nav , Navbar , NavItem , Header , Brand } from 'react-bootstrap' ; class HeaderComponent extends Component { constructor ( ) { super ( ) ; this . state = { authenticated : false } this . login = this . login . bind ( this ) ; this . logout = this . logout . bind ( this ) ; } login ( ) { this . props . lock . show ( ( err , profile , token ) => { if ( err ) { alert ( err ) ; return ; } this . setState ( { authenticated : true } ) ; } ) ; } logout ( ) { this . setState ( { authenticated : false } ) ; } render ( ) { return ( < Navbar > < Navbar . Header > < Navbar . Brand > < a href = "#" > React Contacts < / a > < / Navbar . Brand > < / Navbar . Header > < Nav > < NavItem onClick = { this . login } > Login < / NavItem > < NavItem onClick = { this . logout } > Logout < / NavItem > < / Nav > < / Navbar > ) ; } } export default HeaderComponent ;

We're admittedly skimping a bit on the authentication details for the time being since we don't yet have our actions and stores set up; however, this is fine to see how things work for now. The login method is where we are popping up the Lock widget and this is controlled by the "Login" NavItem . For now we are simply setting the authenticated state to be either true or false , but we'll later see how this can be determined by the presence of a JWT for the user.

Before we can see something on the screen we need to put in our Sidebar and Index components.

import React , { Component } from 'react' ; class SidebarComponent extends Component { render ( ) { return ( < h1 > Hello from the sidebar < / h1 > ) ; } } export default SidebarComponent ;

This will eventually be the spot where we render our list of contacts that comes back from the server, but for now we just display a simple message.

We also have an Index component which is being used by the router as the IndexRoute . We can simply have this component show a message about clicking on a contact to view their profile.

import React , { Component } from 'react' ; class IndexComponent extends Component { constructor ( ) { super ( ) ; } render ( ) { return ( < h2 > Click on a contact to view their profile < / h2 > ) ; } } export default IndexComponent ;

We're now ready to view our app for the first time! But first, let's quickly remove or comment out a couple things in Root.js . We don't yet have a ConactDetail component, so let's temporarily remove the import and Route for this component.

If everything worked out, we should see the app rendered.

We should also see the Lock widget pop up when we click Login.

Flux is great for state management, but one of its downsides is that it requires a lot of code, which means this section will be a little lengthy. To keep it as trim as possible, we won't go into too much detail on what Flux is and how it works, but you can read Ken's article on the subject for a thorough overview.

To be brief about Flux, it's an architecture that helps us handle unidirectional data flow in our apps. Having an architecture where data can only flow in one direction is important as applications become large, because it's much easier to reason about things if we can avoid the tangled mess of two-way data flow.

To make this happen, Flux relies on actions, a dispatcher, and stores.

Create the Dispatcher

Let's start by creating our dispatcher.

import { Dispatcher } from 'flux' ; const AppDispatcher = new Dispatcher ( ) ; export default AppDispatcher ;

There is only ever one dispatcher for a given React + Flux application, and it's created by simply calling new Dispatcher() .

Create the Actions

Next, let's put in the actions for retrieving our contacts data from the API.

import AppDispatcher from '../dispatcher/AppDispatcher' ; import ContactConstants from '../constants/ContactConstants' ; import ContactsAPI from '../utils/ContactsAPI' ; export default { recieveContacts : ( ) => { ContactsAPI . getContacts ( 'http://localhost:3001/api/contacts' ) . then ( contacts => { AppDispatcher . dispatch ( { actionType : ContactConstants . RECIEVE_CONTACTS , contacts : contacts } ) ; } ) . catch ( message => { AppDispatcher . dispatch ( { actionType : ContactConstants . RECIEVE_CONTACTS_ERROR , message : message } ) ; } ) ; } , getContact : ( id ) => { ContactsAPI . getContact ( 'http://localhost:3001/api/contacts/' + id ) . then ( contact => { AppDispatcher . dispatch ( { actionType : ContactConstants . RECIEVE_CONTACT , contact : contact } ) ; } ) . catch ( message => { AppDispatcher . dispatch ( { actionType : ContactConstants . RECIEVE_CONTACT_ERROR , message : message } ) ; } ) ; } }

In a Flux architecture, actions need to dispatch an action type and a payload. The payload is normally the data associated with the action, and this data is picked up by the associated store to be dealt with down the line.

There are differing opinions on whether or not actions are a good place to be doing things like API calls, and some feel that anything like this should be reserved for stores. Ultimately, the setup you choose comes down to whatever works well for your app, and putting API calls in the actions provides us a good way to work with remote data.

We're relying on a ContactsAPI and ContactConstants which we have yet to create, so let's do that now.

import keyMirror from 'keymirror' ; export default keyMirror ( { RECIEVE_CONTACT : null , RECIEVE_CONTACTS : null , RECIEVE_CONTACT_ERROR : null , RECIEVE_CONTACTS_ERROR : null } ) ;

Constants give us something to identify our action types by and they are useful for syncing up our actions and stores, as we'll see later. We're using keyMirror to make the values of our constants match the keys themselves.

We've already got a sense of how our ContactsAPI should look from our ContactActions . We want to expose some methods for sending XHR requests to the server to retrieve the data and return a Promise to handle the result. For the XHR requests themselves, we'll use superagent which is a library that wraps XHR nicely and provides a clean way of doing HTTP requests.

import request from 'superagent/lib/client' ; export default { getContacts : ( url ) => { return new Promise ( ( resolve , reject ) => { request . get ( url ) . end ( ( err , response ) => { if ( err ) reject ( err ) ; resolve ( JSON . parse ( response . text ) ) ; } ) } ) ; } , getContact : ( url ) => { return new Promise ( ( resolve , reject ) => { request . get ( url ) . end ( ( err , response ) => { if ( err ) reject ( err ) ; resolve ( JSON . parse ( response . text ) ) ; } ) } ) ; } }

With superagent, we can call methods like get for a GET request. In the end method we have callback that either gives us an error or a response, and we can do whatever we want with these.

If we encounter any errors in our requests, we reject right away with the error. This rejection is picked up in the catch method in our actions. Otherwise, we resolve with the data from the API.

Before we can render any of the contacts data to the screen, we need to create the store that it will use.

import AppDispatcher from '../dispatcher/AppDispatcher' ; import ContactConstants from '../constants/ContactConstants' ; import { EventEmitter } from 'events' ; const CHANGE_EVENT = 'change' ; let _contacts = [ ] ; let _contact = { } ; function setContacts ( contacts ) { _contacts = contacts ; } function setContact ( contact ) { _contact = contact ; } class ContactStoreClass extends EventEmitter { emitChange ( ) { this . emit ( CHANGE_EVENT ) ; } addChangeListener ( callback ) { this . on ( CHANGE_EVENT , callback ) } removeChangeListener ( callback ) { this . removeListener ( CHANGE_EVENT , callback ) } getContacts ( ) { return _contacts ; } getContact ( ) { return _contact ; } } const ContactStore = new ContactStoreClass ( ) ; ContactStore . dispatchToken = AppDispatcher . register ( action => { switch ( action . actionType ) { case ContactConstants . RECIEVE_CONTACTS : setContacts ( action . contacts ) ; ContactStore . emitChange ( ) ; break case ContactConstants . RECIEVE_CONTACT : setContact ( action . contact ) ; ContactStore . emitChange ( ) ; break case ContactConstants . RECIEVE_CONTACT_ERROR : alert ( action . message ) ; ContactStore . emitChange ( ) ; break case ContactConstants . RECIEVE_CONTACTS_ERROR : alert ( action . message ) ; ContactStore . emitChange ( ) ; break default : } } ) ; export default ContactStore ;

As most stores do, we're registering a switch statement on the AppDispatcher so we can respond to the various actions that are dispatched in the app. When the RECIEVE_CONTACTS action is dispatched, it means that we're getting some contacts data from the API, and in this case we want to set the contacts onto an array. This is done in the setContacts function, after which we tell the EventListener to emit a change so that the app can know a change has been made.

We've also got logic in place for getting either a single contact or the full list of them, and these methods will be used in our components.

Before we can view our contacts, we need to create a couple components to deal specifically with our list.

The Contacts component will be used in the sidebar to display a list of our contacts. We'll set up a Link in the list so we can later show more detail on them.

import React , { Component } from 'react' ; import { ListGroup } from 'react-bootstrap' ; import ContactActions from '../actions/ContactActions' ; import ContactStore from '../stores/ContactStore' ; import ContactListItem from './ContactListItem' ; function getContactListItem ( contact ) { return ( < ContactListItem key = { contact . id } contact = { contact } / > ) ; } class ContactsComponent extends Component { constructor ( ) { super ( ) ; this . state = { contacts : [ ] } this . onChange = this . onChange . bind ( this ) ; } componentWillMount ( ) { ContactStore . addChangeListener ( this . onChange ) ; } componentDidMount ( ) { ContactActions . recieveContacts ( ) ; } componentWillUnmount ( ) { ContactStore . removeChangeListener ( this . onChange ) ; } onChange ( ) { this . setState ( { contacts : ContactStore . getContacts ( ) } ) ; } render ( ) { let contactListItems ; if ( this . state . contacts ) { contactListItems = this . state . contacts . map ( contact => getContactListItem ( contact ) ) ; } return ( < div > < ListGroup > { contactListItems } < / ListGroup > < / div > ) ; } } export default ContactsComponent ;

We need to start with an initial state, and when we use ES2015, this can be done using this.state in the constructor. We're binding the onChange method to this so that we can get the proper this context in our methods. This is crucial when we go to do things like this.setState in any of our component methods.

When the component mounts, we're asking for the initial list of contacts by calling our ContactActions.recieveContacts action directly. This will send an XHR request to the server (as we've specified in ContactsAPI ) and will trigger the ContactStore to handle the data. We need to add a change listener in the componentWillMount lifecycle method which uses the onChange method as its callback. The onChange method is responsible for setting the state with the current list of contacts from the store.

We're mapping over the contacts data that is set on state and creating list items out of each of them so that we can nicely display it in a ListGroup , which is a component that comes from React Bootstrap. We need another component for this called ContactListItem , so let's put that in now.

The ContactListItem component needs to create a ListGroupItem (another React Bootstrap component) with a React Router Link inside which will eventually take us to the listed contact's details.

import React , { Component } from 'react' ; import { ListGroupItem } from 'react-bootstrap' ; import { Link } from 'react-router' ; class ContactListItem extends Component { render ( ) { const { contact } = this . props ; return ( < ListGroupItem > < Link to = { `/contact/ ${ contact . id } ` } > < h4 > { contact . name } < / h4 > < / Link > < / ListGroupItem > ) ; } } export default ContactListItem ;

Here we're receiving the contact as a prop and simply rendering out the name property.

Fixing the Sidebar

Let's make one final adjustment before we view the app, which is to fix the Sidebar so that it shows the list of contacts instead of the message we had before.

import React , { Component } from 'react' ; import Contacts from './Contacts' ; class SidebarComponent extends Component { render ( ) { return ( < Contacts / > ) ; } } export default SidebarComponent ;

With this in place, we should now be able to view our list of contacts.

One of the last pieces of the application we'll need is the contact detail area which is meant to take up the main part of the page. When a contact name is clicked, a request should be made to the server to retrieve that contact's details which can then be displayed.

You may have noticed when we set up our Express app that we immediately applied the JWT middleware ( authCheck ) to the /contacts/:id route, meaning that without a valid JWT, we won't be able to access the resource. While this may or may not be a realistic scenario for your app, restricting just the user's details to authenticated users will give us a good way of seeing how to work with parts of our app that require authentication for this demo.

We've already got our action and store set up to handle a single contact, so let's get right to implementing the component.

import React , { Component } from 'react' ; import ContactActions from '../actions/ContactActions' ; import ContactStore from '../stores/ContactStore' ; class ContactDetailComponent extends Component { constructor ( ) { super ( ) ; this . state = { contact : { } } this . onChange = this . onChange . bind ( this ) ; } componentWillMount ( ) { ContactStore . addChangeListener ( this . onChange ) ; } componentDidMount ( ) { ContactActions . getContact ( this . props . params . id ) ; } componentWillUnmount ( ) { ContactStore . removeChangeListener ( this . onChange ) ; } componentWillReceiveProps ( nextProps ) { this . setState ( { contact : ContactActions . getContact ( nextProps . params . id ) } ) ; } onChange ( ) { this . setState ( { contact : ContactStore . getContact ( this . props . params . id ) } ) ; } render ( ) { let contact ; if ( this . state . contact ) { contact = this . state . contact ; } return ( < div > { this . state . contact && < div > < img src = { contact . image } width = "150" / > < h1 > { contact . name } < / h1 > < h3 > { contact . email } < / h3 > < / div > } < / div > ) ; } } export default ContactDetailComponent ;

This component looks very similar to our Contacts component, but it's now only dealing with a single contact object. Notice that we're passing an id argument to the getContact method on ContactActions and ContactStore . This id comes from React Router and is provided by the params . The componentWillReceiveProps method is used to bring out the id from params when we move between contacts in the list, or in other words, when we want to view the "next" contact.

Before we can view this, we need to bring back the ContactDetail route in our Root.js file.

... render ( ) { return ( < Router history = { this . props . history } > < Route path = '/' component = { App } > < IndexRoute component = { Index } / > < Route path = '/contact/:id' component = { ContactDetail } / > < / Route > < / Router > ) ; } ...

We can now click on a contact to view their details, but we're not yet able to get through.

The reason for this unauthorized error is that we have middleware protecting the contact detail resource on the server. We need to provide the server with a valid JWT before it will allow our requests to get through, and to make that happen, we first need to authenticate our user. Let's finish out the authentication pieces now.

So what exactly happens when a user logs in with Auth0? There are a number of items that are returned in the callback, and the most important one for our concerns today is the id_token , which is a JWT. We also get a number of other items, like the user's profile, an access token, a refresh token, and others.

The good news is that we're almost all the way there with authentication already since most of the work is done for us out of the box with Auth0. All we need to do to finish out the authentication piece is provide some logic to handle the user's profile data and JWT that get returned on a successful login.

We'll follow Flux architecture for this and create a set of actions, constants, and a store for authentication.

Create the AuthActions

import AppDispatcher from '../dispatcher/AppDispatcher' ; import AuthConstants from '../constants/AuthConstants' ; export default { logUserIn : ( profile , token ) => { AppDispatcher . dispatch ( { actionType : AuthConstants . LOGIN_USER , profile : profile , token : token } ) ; } , logUserOut : ( ) => { AppDispatcher . dispatch ( { actionType : AuthConstants . LOGOUT_USER } ) ; } }

The setup is similar to our ContactActions , except that here we're concerned with user login and logout. In the logUserIn method, we're dispatching the profile and the token that will come through from our Header component when we call the action.

Create the Auth Constants

We need some new constants for authentication.

import keyMirror from 'keymirror' ; export default keyMirror ( { LOGIN_USER : null , LOGOUT_USER : null } ) ;

Create the Auth Store

The AuthStore is where we are eventually handling the profile and JWT that come through after a successful login. So what do we need to do with them exactly? The easiest way to work with the profile and token is to save them in local storage so that they can be recalled and used later.

import AppDispatcher from '../dispatcher/AppDispatcher' ; import AuthConstants from '../constants/AuthConstants' ; import { EventEmitter } from 'events' ; const CHANGE_EVENT = 'change' ; function setUser ( profile , token ) { if ( ! localStorage . getItem ( 'id_token' ) ) { localStorage . setItem ( 'profile' , JSON . stringify ( profile ) ) ; localStorage . setItem ( 'id_token' , token ) ; } } function removeUser ( ) { localStorage . removeItem ( 'profile' ) ; localStorage . removeItem ( 'id_token' ) ; } class AuthStoreClass extends EventEmitter { emitChange ( ) { this . emit ( CHANGE_EVENT ) ; } addChangeListener ( callback ) { this . on ( CHANGE_EVENT , callback ) } removeChangeListener ( callback ) { this . removeListener ( CHANGE_EVENT , callback ) } isAuthenticated ( ) { if ( localStorage . getItem ( 'id_token' ) ) { return true ; } return false ; } getUser ( ) { return localStorage . getItem ( 'profile' ) ; } getJwt ( ) { return localStorage . getItem ( 'id_token' ) ; } } const AuthStore = new AuthStoreClass ( ) ; AuthStore . dispatchToken = AppDispatcher . register ( action => { switch ( action . actionType ) { case AuthConstants . LOGIN_USER : setUser ( action . profile , action . token ) ; AuthStore . emitChange ( ) ; break case AuthConstants . LOGOUT_USER : removeUser ( ) ; AuthStore . emitChange ( ) ; break default : } } ) ; export default AuthStore ;

The setUser function is what we use when a successful login comes through and it's responsible for saving the profile and token in local storage. We've also got some utility methods that will help us in our components. Among them is an isAuthenticated method which can be used to conditionally hide and show various elements depending on whether or not the user is currently authenticated.

But let's think about this for a second. In a traditional authentication setup, when the user successfully logs in, we get a session on the server, and this session is later used to say whether or not the user is currently authenticated. However, JWT authentication is stateless, and it works by having the server check the token it receives in a request against a secret key. No session or state necessary. This is great for all sorts of reasons, but it leaves us wondering how we can determine if a user is authenticated or not for the purposes of our front end app.

The good news is that all we really need to do is check whether a token is saved in local storage. If the token is invalid, the request is going to be rejected anyway and the user will need to log back in. We could take things a step further and check whether the token has expired or not, but for now just checking for the presence of a JWT is fine.

Fix the Header Component

Let's quicky modify the header component so that it uses the AuthActions and AuthStore to actually dispatch the proper actions.

... import AuthActions from '../actions/AuthActions' ; import AuthStore from '../stores/AuthStore' ; class HeaderComponent extends Component { ... login ( ) { this . props . lock . show ( ( err , profile , token ) => { if ( err ) { alert ( err ) ; return ; } AuthActions . logUserIn ( profile , token ) ; this . setState ( { authenticated : true } ) ; } ) ; } logout ( ) { AuthActions . logUserOut ( ) ; this . setState ( { authenticated : false } ) ; } ...

With all of these changes in place, we can now log in and have the user's profile and JWT saved.

So our contact detail resource is protected by JWT authentication, and now we have a valid JWT for our user. Now all we need to do is attach it as an Authorization header when we make a request. With superagent, it's easy to set this up in the request.

import AuthStore from '../stores/AuthStore' ; ... getContact : ( url ) => { return new Promise ( ( resolve , reject ) => { request . get ( url ) . set ( 'Authorization' , 'Bearer ' + AuthStore . getJwt ( ) ) . end ( ( err , response ) => { if ( err ) reject ( err ) ; resolve ( JSON . parse ( response . text ) ) ; } ) } ) ; } }

We setup the Authorization header with the Bearer scheme and get our JWT from the store to be attached. With this in place, we should now be able to access the protected content.

We're pretty much there with our app! To finish things out, let's conditionally show and hide some of the elements. We're going to want to show the "Login" nav item when the user isn't authenticated, and hide it when they are. The opposite is true for the "Logout" nav item.

... constructor ( ) { super ( ) ; this . state = { authenticated : AuthStore . isAuthenticated ( ) } ... } ... render ( ) { return ( < Navbar > < Navbar . Header > < Navbar . Brand > < a href = "#" > React Contacts < / a > < / Navbar . Brand > < / Navbar . Header > < Nav > { ! this . state . authenticated ? ( < NavItem onClick = { this . login } > Login < / NavItem > ) : ( < NavItem onClick = { this . logout } > Logout < / NavItem > ) } < / Nav > < / Navbar > ) ; } ...

Here we are getting the user's authentication state from the store as the component loads up. We then use this authenticated state to conditionally show and hide the NavItem s.

We can do something similar for the message in our Index component.

... constructor ( ) { super ( ) ; this . state = { authenticated : AuthStore . isAuthenticated ( ) } } render ( ) { return ( < div > { ! this . state . authenticated ? ( < h2 > Log in to view contact details < / h2 > ) : ( < h2 > Click on a contact to view their profile < / h2 > ) } < / div > ) ; } ...

If you've followed along, you've now got a React + Flux app that calls an API and has user authentication implemented with Auth0. Great job!

There's no doubt about it: a ton of code is involved with creating a React + Flux app and it can be hard to see the benefits of it when building small projects. However, the unidirectional data flow and app structure that Flux allows becomes really important as applications grow. Removing the mess of two-way data flow is essential for being able to reason about your app as it gets larger and larger.

Fortunately, the authentication part--which can often be tricky--is easy with Auth0. If you're using a backend other than Node for your app, be sure to check out the Auth0 SDK that applies to you. There are integrations almost all popular languages and frameworks, including:

Like this article? Follow @ryanchenkie on Twitter