JWT Auth with Phoenix and React Router 4
Tags: phoenix, react, jwt, guardian
Published: 2017-09-12 17:00:41

---
title: JWT Auth with Phoenix and React Router 4
published: true
description: Authenticate your React front-app with a Phoenix API using JWT, Guardian and React Router 4
tags: Phoenix, React, JWT, Guardian
---

Since I clearly cannot get enough of [JWT](http://www.thegreatcodeadventure.com/jwt-auth-in-rails-from-scratch/) [authentication](http://www.thegreatcodeadventure.com/jwt-authentication-with-react-redux/), here's a look at how to use it to authenticate your shiny new Phoenix API with a React + Redux front-end application, using React Router 4. 

In this post, we'll cover:

* Using [React Router 4](https://github.com/ReactTraining/react-router) to set up both regular and authenticated routes. 
* Using React Router's `routerMiddleware` to teach our store how to handle actions provided to us by React router.
* Building a simple Phoenix API endpoint for authentication with the help of [Comeonin](https://github.com/riverrun/comeonin) and [Guardian](https://github.com/ueberauth/guardian).
* Using React to establish a connection to a Phoenix websocket and channel.
* Using a Guardian Plug to authenticate incoming API requests from React using the JWT. 

## Configuring The Routes

First things first, we'll configure our routes and append that configuration to the DOM to render our component tree. 

*For the purposes of this article, let's say that we're building a chatting application in which users can visit an index of chatrooms, `/chats`, and enter a chatroom, `chats/:id`, to start chatting*

```javascript
# web/static/js/routes/index.js

import React               from 'react';
import { Route, Redirect } from 'react-router-dom'
import App                 from '../containers/app';
import Navigation          from '../views/shared/nav';
import RegistrationsNew    from '../views/registrations/new';
import SessionsNew         from '../views/sessions/new';
import Chats               from '../views/chats';
import Actions             from '../actions/sessions';

export default function configRoutes() {
  return (
    <div>
      <Navigation />
      <Route exact path="/" component={App} />
      <Route path="/sign_up" component={RegistrationsNew} />
      <Route path="/sign_in" component={SessionsNew} />
      <AuthenticatedRoute path="/chats" component={Chats} />
    </div>
  );
}

const AuthenticatedRoute = ({ component: Component, ...rest }) => (
  <Route {...rest} render={props => (
    localStorage.getItem('phoenixAuthToken') ? (
      <Component {...props}/>
    ) : (
      <Redirect to={{
        pathname: '/sign_in',
        state: { from: props.location }
      }}/>
    )
  )}/>
)
```

If you're familiar with earlier versions of React Router, much of this code probably looks familiar. 

We've defined a function `configRoutes`, that uses React Router DOM's `Route` component to define a set of routes. We map each path to a component to render, and we import our components at the top of the file. 

We've defined the following routes:

* `/`, the root path, which points to our container component, `App`. 
* `/sign_up`, which points to the component that houses our registration form. 
* `/sign_in`, pointing to the component that houses our sign in form.
* `/chats`, pointing to the chat index component. This route is our protected, or authenticated route. 

Let's take a closer look at that authenticated route now. 

### Defining an Authenticated Route

Our authenticated route is really just a functional component. It is invoked with `props` that include a key of `component`, set to the `Chats` component that we passed in. 

Our functional component returns a `Route` component. The `render()` function of this `Route` component is responsible for rendering the `Chats` component from props, or redirecting. 

Let's take a closer look at this `render()` function:

```javascript
props => (
  localStorage.getItem('phoenixAuthToken') ? (
    <Component {...props}/>   
  ) : (
    <Redirect to={{
      pathname: '/sign_in',
      state: { from: props.location }
    }}/>
  )
)
```

Our function determines whether or not we have an authenticated user based on the presence or absence of the `phoenixAuthToken` key in `localStorage`. Later, we'll build out the functionality of storing the JWT we receive from Phoenix in `localStorage`. 

If a token is present, we'll go ahead and call the component that was passed into our `Route` as a prop, the `Chats` component. 

If no token is found, we'll use the `Redirect` component from React Router DOM to enact a redirect. 

And that's it! Now, we'll take our route configuration and append it to the DOM with ReactDOM, thereby appending our component tree to the DOM. 

### Configuring The Store and Router Component

```javascript
import React from 'react';
import ReactDOM from 'react-dom';
import { createStore, applyMiddleware } from 'redux'
import { Provider} from 'react-redux'
import thunk from 'redux-thunk'
import createHistory from 'history/createBrowserHistory'
import {
  ConnectedRouter as Router,
  routerMiddleware
} from 'react-router-redux'
import {
  Route,
  Link
} from 'react-router-dom'

import configRoutes from './routes'
import rootReducer from './reducers'

const history = createHistory()
const rMiddleware = routerMiddleware(history)

const store = createStore(
  rootReducer,
  applyMiddleware(thunk, rMiddleware)
)


ReactDOM.render(
  <Provider store={store}>
    <Router history={history}>
      <div>
        {configRoutes()}
      </div>
    </Router>
  </Provider>,
  document.getElementById('main_container')
);

``` 

There are a few things to point out here. 

First, we're using React Router's `routerMiddleware`. React Router gives us access to a set of action creator functions with which to manipulate browser history:

* `push(location)`
* `replace(location)`
* `go(number)`
* `goBack()`
* `goForward()`

We'll use `push` later to redirect after we sign in a user. 

Out of the box, however, the Redux store doesn't know how to handle the dispatch of these actions. That's where the `routerMiddleware` comes in. We create an instance of our `routerMiddleware` by invoking the `routerMiddleware` function with an argument of our browser history instance. 

Then, we pass this middleware instance to our store via the `applyMiddlware` function. Now, when we dispatch any of the actions listed above, the store will handle them by applying them to our browser history. 

It's important to note that we _still_ need to pass our browser history instance to our `Router`. This will make sure that our routes sync up with the browser history's location and the store at the same time. 


Now that we have our routes set up, let's build the authorization flow. 

## The Sign In Component

Our sign in form will live in our `sessions/new.js` component. Let's build it out:

```javascript
# /views/sessions/new.js

import React   from 'react';
import { connect }          from 'react-redux';
import { Link }             from 'react-router-dom';
import Actions              from '../../actions/sessions';

class SessionsNew extends React.Component {
  handleSubmit(e) {
    e.preventDefault();
    const { dispatch } = this.props;

    const data = {
      email: this.refs.email.value,
      password: this.refs.password.value
    };

    dispatch(Actions.signIn(data));
  }

  render() {
    const { errors } = this.props;

    return (
      <div className="container">
        <div className="container">
          <form 
            className="form-horizontal" 
            onSubmit={::this.handleSubmit}>
            <fieldset>
              <legend>Sign In</legend>
              <div className="form-group">
                <label className="col-lg-2">email</label>
                <div className="col-lg-10">
                  <input 
                    className="form-control" 
                    ref="email" 
                    id="user_email" 
                    type="text" 
                    placeholder="email" required={true} />
                </div>
              </div>

              <div className="form-group">
                <label className="col-lg-2">password</label>
                <div className="col-lg-10">
                  <input 
                    className="form-control" 
                    ref="password" 
                    id="user_password" 
                    type="password" 
                    placeholder="password" required={true} />
                </div>
              </div>
              <br/>       
            <button type="submit">Sign in</button>
            </fieldset>
          </form>
          <Link to="/sign_up">Sign up</Link>
      </div>
      </div>
    );
  }
}

export default connect()(SessionsNew)
```

Our form is pretty simple, it has a field for the user's email and a field for the user's password. On the submission of the form, we dispatch an action that will send a `POST` request to the sign in route of our Phoenix API. 

Let's build out that action now. 

## The Sign In Action

```javascript
# /actions/sessions.js

import { push }      from 'react-router-redux';
import Constants     from '../constants';
import { Socket }    from 'phoenix';
import { httpPost }  from '../utils';


const Actions = {
  signIn: (creds) => {
    return dispatch => {
      const data = {
        session: creds,
      };
      httpPost('/api/v1/sessions', data)
      .then((response) => {
        localStorage.setItem('phoenixAuthToken', 
          response.jwt);
        setCurrentUser(dispatch, response.user);
        dispatch(push('/challenges'));
      })
      .catch((error) => {
        error.response.json()
        .then((errorJSON) => {
          dispatch({
            type: Constants.SESSIONS_ERROR,
            error: errorJSON.error,
          });
        });
      });
    };
  }
}

export default Actions
```

Here, we define our `Actions` constant to implement a function, `signIn()`. We also use this same file to define a helper function, `setCurrentUser()`. 

The `signIn()` function relies on a tool we defined in another file, `httpPost()`, to make our `POST` request to the sign in endpoint of our Phoenix API. 

The `httpPost()` function relies on Fetch to make web requests:

```javascript
# web/utils/index.js

import fetch        from 'isomorphic-fetch';
import { polyfill } from 'es6-promise';

const defaultHeaders = {
  Accept: 'application/json',
  'Content-Type': 'application/json',
};

function headers() {
  const jwt = localStorage.getItem('phoenixAuthToken');

  return { ...defaultHeaders, Authorization: jwt };
}

export function checkStatus(response) {
  if (response.ok) {
    return response;
  } else {
    var error      = new Error(response.statusText);
    error.response = response;
    throw error;
  }
}

export function parseJSON(response) {
  return response.json();
}


export function httpPost(url, data) {
  const body = JSON.stringify(data);

  return fetch(url, {
    method: 'post',
    headers: headers(),
    body: body,
  }).then(checkStatus)
    .then(parseJSON);
}
```

*Note: This file will grow to include all of our HTTP requests to our API, and rely on  the `headers()` function to build authentication headers using the token we will store in `localStorage` once we authenticate our user*. 

So, we use the `httpPost` function to make our authentication request to the API, and if that request is a success, we grab the `jwt` key from the response body and store it in `localStorage`. We'll actually build out this endpoint soon, but for now we will assume that it exists and returns a successful response body of:

```json
{
  jwt: <some token>,
  user: <serialized user>
}
```

Let's take a closer look at the code in our `signIn()` function that is responsible for this action:

```javascript
localStorage.setItem('phoenixAuthToken', response.jwt);
setCurrentUser(dispatch, response.user);
dispatch(push('/challenges'));
```

After we set the `phoenixAuthToken` in `localStorage`, we invoke our helper function, `setCurrentUser`, and use the `dispatch` function to invoke a route change. This route change is enacted with the help of the `push` action creator function from React Router Redux. (Remember when we used the `routerMiddleware` to enable our store to handle the `push` action?)

We're almost ready to take a closer look at the `setCurrentUser()` function. But first, let's build out the authentication endpoint of our Phoenix API. 

## The Sign In API Endpoint

### Phoenix Authorization Dependencies

In order to authenticate users, we'll use the Comeonin library. In order to generate a JWT token for our user, we'll rely on the Guardian library. 

Let's add these dependencies to our `mix.exs` file and make sure to start up the Comeonin application when our app starts. 


```elixir
# mix.exs
...

def application do
  [
    mod: {PhoenixPair, []},
    applications: [:phoenix, :phoenix_pubsub, :phoenix_html, :cowboy, :logger, :gettext, :phoenix_ecto, :postgrex, :comeonin]
  ]
end

...
defp deps do
  [{:phoenix, "~> 1.2.1"},
   {:phoenix_pubsub, "~> 1.0"},
   {:phoenix_ecto, "~> 3.0"},
   {:postgrex, ">= 0.0.0"},
   {:phoenix_html, "~> 2.6"},
   {:phoenix_live_reload, "~> 1.0", only: :dev},
   {:gettext, "~> 0.11"},
   {:cowboy, "~> 1.0"},
   {:comeonin, "~> 2.0"},
   {:guardian, "~> 0.9.0"}]
end
```

### Defining the Route

We'll scope our API endpoints under `/api/v1`, and define our sign in route like this:

```elixir
# /web/router.ex

  scope "/api", PhoenixPair do
    pipe_through :api

    scope "/v1" do
      post "/sessions", SessionsController, :create
    end
  end
```

### Defining the Controller

The `SessionsController` will implement a create function, that contains the code for authorizing the user. 

```elixir
# web/controllers/api/v1/sessions_controller.ex

defmodule PhoenixPair.SessionsController do 
  use PhoenixPair.Web, :controller

  alias PhoenixPair.{Repo, User}

  plug :scrub_params, "session" when action in [:create]

  def create(conn, %{"session" => session_params}) do
    case PhoenixPair.Session.authenticate(session_params) do
    {:ok, user} ->
      {:ok, jwt, _full_claims} = user 
        |> Guardian.encode_and_sign(:token)
      conn
        |> put_status(:created)
        |> render("show.json", jwt: jwt, user: user)
    :error ->
      conn
      |> put_status(:unprocessable_entity)
      |> render("error.json")
    end
  end

  def unauthenticated(conn, _params) do 
    conn
    |> put_status(:forbidden)
    |> render(PhoenixPair.SessionsView, "forbidden.json", 
      error: "Not Authenticated!")
  end
end
```

### Authenticating the User

Our `create` function relies on a helper module, `PhoenixPair.Session` to authenticate the user given the email and password present in params. 

```elixir
# web/services/session.ex

defmodule PhoenixPair.Session do
  alias PhoenixPair.{Repo, User}
  def authenticate(%{"email" => e, "password" => p}) do
    case Repo.get_by(User, email: e) do
      nil -> 
        :error
      user ->
        case verify_password(p, user.encrypted_password) do
          true ->
            {:ok, user}
          _ ->
            :error
        end
    end
  end

  defp verify_password(password, pw_hash) do
    Comeonin.Bcrypt.checkpw(password, pw_hash)
  end
end

```

This module implements a function, `authenticate/1`, which expects to be invoked with an argument of a map that pattern matches to a map with keys of `"email"` and `"password"`.

It uses the email to look up the user via:

```elixir

Repo.get_by(User, email: email)
```

If no user is found our case statement with execute the `nil ->` clause and return the atom `:error`. 

If a user is found, we'll call our `verify_password` helper function. This function uses `Comeonin.Bcrypt.checkpw` to validate the password. If this validation is successful, we will return the tuple `{:ok, user}`, where `user` is the User struct returned by our `Repo.get_by` query. 

### Generating a JWT

Back in our controller, if the call to `.Session.authenticate` returns the success tuple, `{:ok, user}`, we'll use Guardian to generate a JWT. 

```elixir
...
{:ok, jwt, _full_claims} = user 
   |> Guardian.encode_and_sign(:token)
   conn
     |> put_status(:created)
     |> render("show.json", jwt: jwt, user: user)
```

If our call to `Guardian.encode_and_sign(user, :token)` was successful, we'll use our Session View to render the following JSON payload:

```json
{jwt: jwt, user: user}
```

```elixir
# web/views/sessions_view.ex

defmodule PhoenixPair.SessionsView do
  use PhoenixPair.Web, :view

  def render("show.json", %{jwt: jwt, user: user}) do
    %{
      jwt: jwt,
      user: user
    }
  end

  def render("error.json", _) do
    %{error: "Invalid email or password"}
  end

  def render("forbidden.json", %{error: error}) do
    %{error: error}
  end
end
```

If the call to `.Session.authenticate` was not successful, or if our attempt to use Guardian to generate a token was not successful, we will render an error instead. 

Now that our endpoint is up and running, let's return to our React app and discuss how we will set the current user with a successful payload. 

## Setting the Current User

What does it mean to set the current user in a React and Phoenix app? We want to leverage the power of Phoenix channels to build real-time communication features for our user. So, when we "set the current user", we will need to establish a socket connection for that user, and connect that user to their very own Phoenix channel.

On the React side, we will store the current user's information in state, under the `session` key, under a key of `currentUser`: 

```javascript
# state
{
  session: 
    currentUser: {
      name: <a href="http://beatscodeandlife.ghost.io/">"Antoin Campbell"</a>, 
      email: "antoin5@5antoins.com"
    },
    ...
  ...
}
```

So, our `setCurrentUser()` function, called in our `signIn()` action, should handle both of these responsibilities. 

### Establishing the Current User's Socket Connection

We'll import `Socket` from Phoenix, and use the Socket API to establish our user's socket connection. 


```javascript
import { Socket } from 'phoenix';

export function setCurrentUser(dispatch, user) {
  const socket = new Socket('/socket', {
    params: {token: localStorage.getItem('phxAuthToken') },
    logger: (kind, msg, data) => { console.log(`${kind}: 
      ${msg}`, data); },
  });

  socket.connect();

  const channel = socket.channel(`users:${user.id}`);
  if (channel.state != 'joined') {
    channel.join().receive('ok', () => {
      dispatch({
        type: Constants.SOCKET_CONNECTED,
        currentUser: user,
        socket: socket,
        channel: channel,
      });
    });
  }
};
```

Let's break this down. 

* First, we instantiate a new instance of `Socket` via:

```javascript

const socket = new Socket('/socket', {
  params: {token: localStorage.getItem('phxAuthToken')},
  logger: (kind, msg, data) => { console.log(`${kind}: 
    ${msg}`, data); 
}
```

Then, we invoke the `connect` function on that instance:

```javascript
socket.connect()
```

This has the effect of invoking the `connect` function of our `UserSocket`, with params of `%{"token" => token}`. We'll need to define that socket to implement the `connect` function:

```elixir
web/channels/user_socket.ex

defmodule PhoenixPair.UserSocket do
  use Phoenix.Socket
  alias PhoenixPair.{Repo, User, GuardianSerializer, Session}

  ## Channels
  channel "users:*", PhoenixPair.UsersChannel

  ## Transports
  transport :websocket, Phoenix.Transports.WebSocket
  transport :longpoll, Phoenix.Transports.LongPoll
 
  def connect(%{"token" => token}, socket) do
    case Guardian.decode_and_verify(token) do
      {:ok, claims} ->
        case GuardianSerializer.from_token(claims["sub"]) do
          {:ok, user} ->
            {:ok, assign(socket, :current_user, user)}
          {:error, _reason} ->
            :error
        end
      {:error, _reason} ->
        :error
    end
  end

  def connect(_params, socket), do: :error

  def id(socket) do
    "users_socket:{socket.assigns.current_user.id}"
  end
end
```

Our `connect` function uses Guardian to decode the JWT from params. If the decode was successful, we'll use Guardian again to pluck out the User struct from the deserialized token payload. Then, we'll assign that struct to the key of `:current_user` within our socket's storage system. This socket is shared by all additional channels we might open for this user. So, any future channels we build on this socket can access the current user via `socket.assigns.current_user`. 

Our `UserSocket` also implements a `connect` function that does not match the pattern of expected params. This function will simply return `:error`. 

```elixir
def connect(_params, socket), do: :error
```

Lastly, we define an `id` function, which returns the designation of this socket, named with the ID of our user:

```elixir
def id(socket) do: 
  "users_socket:#{socket.assigns.current_user.id}"
end
```

The socket id will allow us to identify all sockets for a given user, and therefore broadcast events through a specific user's socket. For example:

```elixir
PhoenixPair.Endpoint.broadcast("users_socket:#{user.id}", "disconnect", %{})
```

Now that our User Socket knows how to handle the calls to connect, let's go back to our React app's `setCurrentUser()` function and connect to the `UsersChannel`. 

### Connecting to the Users Channel

We'll define our `UsersChannel` to respond to a `join` function, and return the socket connection if the join was successful. 

```elixir
# web/channels/users_channel.ex

defmodule PhoenixPair.UsersChannel do 
  use PhoenixPair.Web, :channel

  def join("users:" <> user_id, _params, socket) do
    {:ok, socket} 
  end
end
```

Then, we'll have our `setCurrentUser` function in React send a message to join this channel:

```javascript
export function setCurrentUser(dispatch, user) {
  ...
  const channel = socket.channel(`users:${user.id}`);
  if (channel.state != 'joined') {
    channel.join().receive('ok', () => {
      dispatch({
        type: Constants.SOCKET_CONNECTED,
        currentUser: user,
        socket: socket,
        channel: channel
      });
    });
  }
}
```

We get our channel instance via
`socket.channel(`users:${user.id}`)`. Then, we join the channel by calling `channel.join()`. This fires the `join` function we defined in our `UsersChannel`. 

On to that function invocation, we chain a call to `receive`. The `receive` function which will be invoked when we get the "ok" response from our channel. 

Once the channel has been successfully joined, we're ready to dispatch an action to our reducer to update state with our current user, as well as the socket and channel. We want to store these last two items in our React application's state so that we can use them to enact channel communications later on as we build out our chatting app. 

## Making Authenticated API Requests

Now that we're properly storing our current user in our React app's state, and our current user's JWT in `localStorage`,  let's take a look at how we will make subsequent authenticated requests to our Phoenix API. 

We've already defined a set of helper functions in `web/static/js/utils/index.js` that use Fetch to make API requests. These functions rely on a helper method, `headers`, to set the authorization header using the token from `localStorage`:

```javascript
import React        from 'react';
import fetch        from 'isomorphic-fetch';
import { polyfill } from 'es6-promise';

const defaultHeaders = {
  Accept: 'application/json',
  'Content-Type': 'application/json',
};

function headers() {
  const jwt = localStorage.getItem('phoenixAuthToken');

  return { ...defaultHeaders, Authorization: jwt };
}

export function checkStatus(response) {
  if (response.ok) {
    return response;
  } else {
    var error = new Error(response.statusText);
    error.response = response;
    throw error;
  }
}

export function parseJSON(response) {
  return response.json();
}

export function httpGet(url) {

  return fetch(url, {
    headers: headers(),
  })
  .then(checkStatus)
  .then(parseJSON);
}

export function httpPost(url, data) {
  const body = JSON.stringify(data);

  return fetch(url, {
    method: 'post',
    headers: headers(),
    body: body,
  })
  .then(checkStatus)
  .then(parseJSON);
} 

...
```

So, all of the requests we make to our Phoenix API using the functions we've defined here, `httpPost`, `httpGet`, etc., will include the JWT in the authorization header. 

Now we have to teach our Phoenix controllers to authorize incoming requests using this header. Luckily, Guardian does a lot of this work for us. 

Let's take a look at our `ChatsController`. 

```elixir
defmodule PhoenixPair.ChatsController do 
  use PhoenixPair.Web, :controller

  plug Guardian.Plug.EnsureAuthenticated, handler: PhoenixPair.SessionsController

  alias PhoenixPair.{Repo, User, Challenge}

  def index(conn, _params) do
    challenges = Repo.all(Chat) 
    render(conn, "index.json", chats: chats)
  end
end
```

This is the line that has all the authorization magic:

```elixir
plug Guardian.Plug.EnsureAuthenticated, handler: PhoenixPair.SessionsController
```

[This plug](https://hexdocs.pm/guardian/Guardian.Plug.EnsureAuthenticated.html) checks for a valid JWT in the authorization header. 
If one isn't found, it invokes the `unauthenticated` function in the handler module. In our case, this is the `PhoenixPair.SessionsController.unauthenticated` function that we defined earlier. 

We can add this plug to any and all authenticated controllers as we build out our app. 

## Conclusion

So far, I've found that React and Phoenix play really well together. I definitely approached this authentication feature with a little trepidation, not having worked with React Router 4 before or done any token-based auth in Phoenix. 

However, integrating JWT authentication between our React front-end and our Phoenix API back-end was pretty seamless thanks to the tools provided by React Router and Guardian. 

Happy coding!