Authenticate React App With Stormpath - Part Two
Tags: react, beginners, javascript
Published: 2019-10-17 09:36:30

This is a continuation of <a href="https://dev.to/clintpy/authenticate-react-app-with-stormpath-part-one-4jee"> Authenticate React App With Stormpath</a>.

On this final piece, we'll set up our pages. Let's dive right in:-

### Main Page

Let's first set up our Router which will define how our navigation structure in the app. We'll do this by first creating a shared route. This will act as our main page i.e. all routes under this page will share the same main component (header). Insert this code inside the ``<Router>`` tag in ``app.js``.

```html
<Router history={browserHistory}>
  <Route path='/' component={MasterPage}>
  </Route>
</Router>
```

We have referenced ``MasterPage``, something that doesn't exist yet. Let's go ahead and create it in a new directore ``pages``, inside our ``src`` folder.

```console
$ mkdir pages
$ cd pages
```

Create a new file named ``masterPage.js`` and add this code:

```javascript
import React from 'react';
import { Link } from 'react-router';
import { LoginLink } from 'react-stormpath';
import DocumentTitle from 'react-document-title';

import Header from './Header';

export default class is extends React.Component {
  render() {
    return (
      <DocumentTitle title='My React App'>
        <div className='MasterPage'>
          <Header />
          { this.props.children }
        </div>
      </DocumentTitle>
    );
  }
}
```

As you can see, we don't have a ``Header`` component yet, so let's go and create a new file named ``Header.js`` in the same directory with the following content.


```javascript
import React from 'react';
import { Link } from 'react-router';
import { LoginLink, LogoutLink, Authenticated, NotAuthenticated } from 'react-stormpath';

export default class Header extends React.Component {
  render() {
    return (
      <nav className="navbar navbar-default navbar-static-top">
        <div className="container">
          <div id="navbar-collapse" className="collapse navbar-collapse">
            <ul className="nav navbar-nav">
              <li><Link to="/">Home</Link></li>
            </ul>
            <ul className="nav navbar-nav navbar-right">
            </ul>
          </div>
        </div>
      </nav>
    );
  }
}
```

### Index Page

In our ``MainPage`` notice the property ``this.props.children``. This will contain the components of the child routes that our router match. So if we had a route that looked like:

```html
<Route path='/' component={MasterPage}>
  <Route path='/hello' component={HelloPage} />
</Route>
```

And we tried to access ``/hello``. The ``this.props.children`` array would be populated with a ``HelloPage`` component and for that reason, that component would be rendered on our master page.

Now imagine the scenario where you try to access ``/``. Without any ``this.props.children``, this would only render your master page but with empty content. This is where ``IndexRoute`` comes into play. With an ``IndexRoute`` you can specify the component that should be rendered when you hit the path of the master page route (in our case ``/``).

But before we add our ``IndexRoute`` to our router, let's create a new file in our ``pages`` directory named ``IndexPage.js`` and add the following to it.

```javascript
import { Link } from 'react-router';
import React, { PropTypes } from 'react';
import { LoginLink } from 'react-stormpath';

export default class IndexPage extends React.Component {
  render() {
    return (
      <div className="container">
        <h2 className="text-center">Welcome!</h2>
        <hr />
        <div className="jumbotron">
          <p>
            <strong>To my React application!</strong>
          </p>
          <p>Ready to begin? Try these Stormpath features that are included in this example:</p>
          <ol className="lead">
            <li><Link to="/register">Registration</Link></li>
            <li><LoginLink /></li>
            <li><Link to="/profile">Custom Profile Data</Link></li>
          </ol>
        </div>
      </div>
    );
  }
}
```


Now let's add our ``IndexRoute``. Open up ``app.js`` and inside the tag ``<Route path='/' component={MasterPage}>`` add your ``IndexRoute`` so that it looks like the following:

```javascript
<Route path='/' component={MasterPage}>
  <IndexRoute component={IndexPage} />
</Route>
```

### Login Page

We now have an application that shows a header with a default page. But we don't have any place to login yet. So let's create a new file named ``LoginPage.js`` and add some content to it:

```javascript
import React from 'react';
import DocumentTitle from 'react-document-title';
import { LoginForm } from 'react-stormpath';

export default class LoginPage extends React.Component {
  render() {
    return (
      <DocumentTitle title={`Login`}>
        <div className="container">
          <div className="row">
            <div className="col-xs-12">
              <h3>Login</h3>
              <hr />
            </div>
          </div>
          <LoginForm />
        </div>
      </DocumentTitle>
    );
  }
}
```

Notice the ``LoginForm`` component. This is all we have to add in order for us to have a fully working form in which people can sign up from.

But before we can use it, we need to open up ``app.js`` and add a route for the page in our router. So inside the tag ``<Route path='/' component={MasterPage}>`` add the following:

```html
<LoginRoute path='/login' component={LoginPage} />
```

In order to be able to access the login page, we need to add this to our menu. So go ahead and open up ``Header.js`` and inside the element ``<ul className="nav navbar-nav navbar-right">`` add the following:

```html
<NotAuthenticated>
  <li>
    <LoginLink />
  </li>
</NotAuthenticated>
```

As you can see we're using the ``NotAuthenticated`` component. With this we'll only show a ``LoginLink`` when the user isn't logged in yet.

### Registration Page

Now, let's add a page where people can sign up. We'll call it ``RegistrationPage``. So create a new file named ``RegistrationPage.js`` and put the following content in it:

```javascript
import React from 'react';
import DocumentTitle from 'react-document-title';
import { RegistrationForm } from 'react-stormpath';

export default class RegistrationPage extends React.Component {
  render() {
    return (
      <DocumentTitle title={`Registration`}>
        <div className="container">
          <div className="row">
            <div className="col-xs-12">
              <h3>Registration</h3>
              <hr />
            </div>
          </div>
          <RegistrationForm />
        </div>
      </DocumentTitle>
    );
  }
}
```

Notice that we used the ``RegistrationForm`` component. As you might have guessed, this will render a Stormpath registration form. And once you've signed up it will point users to the login page where they'll be able to login.

In order to access this page. We need to add a route. So go ahead and open up ``app.js`` and inside the tag ``<Route path='/' component={MasterPage}>`` add:

```html
<Route path='/register' component={RegistrationPage} />
```

We now have a route, but people won't be able to find the page unless we link to it, so open up ``Header.js`` and add the following right before the closing tag ``(</ul>)`` of ``<ul className="nav navbar-nav navbar-right">``:


```console
<NotAuthenticated>
  <li>
    <Link to="/register">Create Account</Link>
  </li>
</NotAuthenticated>
```

Notice the use of the ``NotAuthenticated`` component. With this we'll only show the ``/register`` link when the user isn't logged in.

### Profile Page

Once a user is logged in, we want to be able to show them some personalized content (their user data). So create a new file named ``ProfilePage.js`` and put the following code in it:


```javascript
import React from 'react';
import DocumentTitle from 'react-document-title';
import { UserProfileForm } from 'react-stormpath';

export default class ProfilePage extends React.Component {
  render() {
    return (
      <DocumentTitle title={`My Profile`}>
      <div className="container">
          <div className="row">
            <div className="col-xs-12">
              <h3>My Profile</h3>
              <hr />
            </div>
          </div>
          <div className="row">
            <div className="col-xs-12">
              <UserProfileForm />
            </div>
          </div>
        </div>
      </DocumentTitle>
    );
  }
}
```

Notice that we use the ``UserProfileForm``. This is a simple helper form that allows you to edit the most basic user fields.

Though, in order to actually modify the user profile, we need to change a few things in our server. So open up ``server.js``, add ``var bodyParser = require('body-parser');`` to the top of the file and then add the following route underneath ``app.use(stormpath.init(app, ...));``:

```javascript
app.post('/me', bodyParser.json(), stormpath.loginRequired, function (req, res) {
  function writeError(message) {
    res.status(400);
    res.json({ message: message, status: 400 });
    res.end();
  }

  function saveAccount () {
    req.user.givenName = req.body.givenName;
    req.user.surname = req.body.surname;
    req.user.email = req.body.email;

    req.user.save(function (err) {
      if (err) {
        return writeError(err.userMessage || err.message);
      }
      res.end();
    });
  }

  if (req.body.password) {
    var application = req.app.get('stormpathApplication');

    application.authenticateAccount({
      username: req.user.username,
      password: req.body.existingPassword
    }, function (err) {
      if (err) {
        return writeError('The existing password that you entered was incorrect.');
      }

      req.user.password = req.body.password;

      saveAccount();
    });
  } else {
    saveAccount();
  }
});
```

This will allow the form to change both the given name, surname, email and password of user. If you have additional fields that you wish to edit, then simply customize the ``UserProfileForm`` form and add the fields that you wish to edit in the route above.

Now, in order for us to access this page from the menu, open up Header.js and right below ``<li><Link to="/">Home</Link></li>`` add:

```html
<Authenticated>
  <li>
    <Link to="/profile">Profile</Link>
  </li>
</Authenticated>
```

With this, using the Authenticated "https://github.com/stormpath/stormpath-sdk-react/blob/master/docs/api.md#authenticated) component, when we have a user session we'll render a link to the ``/profile page`` and allow our users to view their user profile.

In order for us to be able to access the page, we must as with the other pages add it to the router. Open up ``app.js`` and inside the tag ``<Route path='/' component={MasterPage}>`` add:

```html
<AuthenticatedRoute path='/profile' component={ProfilePage} />
```

Notice that we're using ``AuthenticatedRoute``. This is a route that can only be accessed if there is an authenticated user session. If there's no session, then the user will automatically be redirected to the path of the ``LoginLink``.

### Home Route

Now when we've setup most of our routing. Let's look at a special route called the ``HomeRoute``. This route itself doesn't do anything. But acts as a "marker", to indicate where to redirect to when logging in and logging out.

So in order to specify where we want to end up when we log out, open up ``app.js`` and change the:

```html
<Route path='/' component={MasterPage}>
  ...
</Route>
```

into:

```html
<HomeRoute path='/' component={MasterPage}>
  ...
</HomeRoute>
```

Now when logging out, the Stormpath SDK will know that it should redirect to the '/' path. Now, to specify where to redirect when logging out, change the ``AuthenticatedRoute`` that we created in the previous step:

```html
<AuthenticatedRoute path='/profile' component={ProfilePage} />
```

So that it looks like:

```html
<AuthenticatedRoute>
  <HomeRoute path='/profile' component={ProfilePage} />
</AuthenticatedRoute>
```

Notice how the ``AuthenticatedRoute`` wraps the ``HomeRoute``. This is used to indicate the authenticated route that we want to redirect to after login.

### Logout

Finally, once our users have signed up and logged in. We want to give them the option to logout. Fortunately, adding this is really simple.

So open up ``Header.js`` and inside ``<ul className="nav navbar-nav navbar-right">`` add this code to the end:

```html
<Authenticated>
  <li>
    <LogoutLink />
  </li>
</Authenticated>
```

Notice the ``LogoutLink`` component. Once this is clicked, the user session will be automatically destroyed and the user will be redirected to the unauthenticated ``HomeRoute``.

### User State in Components

Access user state in your components by requesting the authenticated and user context types:

```javascript
class ContextExample extends React.Component {
  static contextTypes = {
    authenticated: React.PropTypes.bool,
    user: React.PropTypes.object
  };

  render() {
    if (!this.context.authenticated) {
      return (
        <div>
          You need to <LoginLink />.
        </div>
      );
    }

    return (
      <div>
        Welcome {this.context.user.username}!
      </div>
    );
  }
}
```

### Import Components

To be able to reference our pages we need to import them. And in order to make importing easy, we'll put them all together in an ``index.js`` file so we only have to import it once. So let's create a new file named ``index.js`` in our pages directory and export all of our pages from it, as shown below:

```javascript
export MasterPage from './MasterPage'
export IndexPage from './IndexPage'
export LoginPage from './LoginPage'
export RegistrationPage from './RegistrationPage'
export ProfilePage from './ProfilePage'
```

With this, we'll only have to do one import in order to have access to all of our pages.

So let's do that. Open up app.js file and at the top of the file, add the following import statement:

```javascript
import { MasterPage, IndexPage, LoginPage, RegistrationPage, ProfilePage } from './pages';
```

### Run The Project

Now we have an application where our users can sign up, login, and show their user data. So let's try it out!

As before, start our server by running the following:

```console
$ node server.js
```
And if everything is running successfully you should be able to see this message:

```console
Listening at http://localhost:3000
```

So, open up ``http://localhost:3000`` in your browser and try it out!

### Wrapping Up

As you have seen in this tutorial, React is a really powerful tool and when used together with ES6, JSX and Stormpath, building apps suddenly becomes fun again.

If you have questions regarding the Stormpath React SDK, be sure to check out its API documentation.

Happy Hacking!