In today’s post, I’ll describe the new for me and it was really hard to introduce the Authentication to the application. Before I start, at first, let’s start with add missing Router to the application (to define the paths and related with them views).

Route '/' - Default page 
Route '/dashboard' - Dashboard - high order component available only for logged admin
Route '/wrong_url' - kick automatically to the default page

Let’s get started writing some code for Authentication. In order to the authentication process, you need to handle with the ‘token’ which is actually in our back-end the JWT token and assign it to out localStorage. In order to start with a sign in the form, I created the simplest form and function which on handleSubmit will call my function to send data to my API.

handleFormSubmit({ email, password }) {
this.props.signinUser({ email, password });
}
render() {
const { handleSubmit, fields: { email, password }} = this.props;
return (
<form onSubmit={handleSubmit(this.handleFormSubmit.bind(this))}>
<fieldset className="form-group">
<label>Email:</label>
<input {...email} className="form-control" />
</fieldset>
<fieldset className="form-group">
<label>Password:</label>
<input {...password} type="password" className="form-control" />
</fieldset>
{this.renderAlert()}
<button action="submit" className="btn btn-primary">Login</button>
</form>
);
}
}

Quite simple form with 2 fields (email and password) who actually everyone should know. The function with handleFormSubmitparameters is invoked and flow up to my singinUser function, which actually does the API POST request.

export function signinUser ({ email, password}) {
  return function(dispatch) {
  axios.post(`${ROOT_URL}/users`, { email, password })
  .then(response => {
  dispatch({ type: AUTH_USER })
  localStorage.setItem('token', reponse.data.token);
  browserHistory.push('/dashboard');
  })
  .catch(() => {
  dispatch(authError('Bad Login Info'));
  });
  }
}

In my whole project, I am using the Axios library to make API REQUEST. In this case, I also need to use the Redux-Thunk. The purpose of using redux thunk instead redux-promise is to dispatch multiple different actions inside of an action creator. We are not limited to single action. At the example above I need deal with few actions like updating the state, save JWT token in localStorage and redirect the admin user to the /dashboard.

To have everything separated in React, I created also the reducers, in sum one reducer responsible for the update the authorization state. In reducer, I used the switch function to handle the different cases. I created 3 cases, to user successfully authorization, the unauthorized user, and some authorization error. Every case returns the completely new state. You need to remember, the state in React must be immutable – I mean we need every change returning the completely new state.

export default function(state = {}, action) {
switch(action.type) {
case AUTH_USER:
return {...state, error: '', authenticated: true };
case UNAUTH_USER:
return {...state, authenticated: false };
case AUTH_ERROR:
return {...state, error: action.payload}
}
return state;
}

And this is how you can much more states in your application and have everything is separate logic. The next stage is to allow only the authorizated users to see the dashboard. We need to introduce new concept called High Order Component. As the name says, it is responsible for allowing the only authorized user view the desirable component. When the user in not authorize the router will kick him to the default page.

  class Authentication extends Component {
  static contextTypes = {
  router: React.PropTypes.object
  }

  componentWillMount() {
  if (!this.props.authenticated) {
  this.context.router.push('/');
  }
  }

  componentWillUpdate(nextProps){
  if (!nextProps.authenticated) {
  this.context.router.push('/');
  }
  }

  render() {
  return 
  }
  }

Actually responsible in HighOrderComponent is the function provided by react – ComponentWillMount (rendered automatically), which is checking if the user in authenticated. If yes, it allows returning the ComposedComponent, if not the router will take the user to the default page.

And that’s all. Surely, the most important thing in the handle with authentication is to have well written back-end.

Patyk Huzarski

Freelance web developer, addicted to computer engineering.