Full stack Django: Quick start with JWT auth and React/Redux (Part II)

In the previous part, we created a simple django back-end with JSON Web token authentication. Now we going to make a frontend with React and Redux

To work over first part of the tutorial, you need to have nodejs, npm, and create-react-app installed.

Redux is a library helps to organize predictable, one-way data flow in a front-end application. Everything starts from a single source of truth — a store. A store could be modified only by firing actions. Actions go through Redux middleware down to the reducer functions. Reducer functions produce a new state. And then React library using Virtual DOM reconcile UI according to this new state.

If you have experience in the desktop UI development, the Redux naming could sound unnatural. Try to think about “actions” as “events”, “reducers” as “listeners”, and when later we meed with mapStateToProps function, it literally means “getComponentPropertiesFromState”

You can read more about Redux in it’s awesome documentation

Let’s start

After a minute, we have a bare simple React application.

Choosing the front-end stack

React with Redux are the most trending libraries for the front-end development. To create a full-featured application we need to add few more dependencies.

Let’s choose also well-known and well-supported libraries

React-router is the de facto standard router implementation for the React from ReactTraining. We installed Redux binding for it.

We going to keep JWT tokens in the Redux state, and persist the state with the redux-persist library, that has awesome API, multiple storage backends support and over 3k stars on GitHub. redux-persist-transform-filter used to whitelist subset of application state for persistence. Keeping tokens in the localStorage could be unsafe if your application includes javascript from other domains (including CDN). But it’s the typical case for a complex Intranet software. And as the advantage of localStorage, we should not worry about CSRF.

Redux itself have no option to call an external API. We going to use redux-api-middleware that implements interface very similar to the redux/real-world example, but available as the package on npm. redux-api-middleware designed to do one thing only — to call an external API. That is the place we could put all our JWT Workflow logic.

jwt-decode is the lightweight JWT token decode library designed specifically for the browsers by Auth0 team.

And to make the UI shine, let’s use reactstrap the bootstrap 4 library bindings for React.

Initial setup

First of all we need to combine all these libraries to play together. Start with simple newreducers/index.js file

That declares a root reducer that keeps a router state.

Now we can create a Redux store in store.js

We just follow all libraries introductions and configure store with redux-api-middleware and persistence of the store.auth in a browserlocalStorare

Now we can modify index.js to make it work

We got bootstrap css imported, instantiate the Redux store and setup react-router.

You can run npm start at that time, and see the initial welcome page.

We finished with libraries boilerplate setup and can start working on the authentication

Authentication

First of all, we need two redux actions, one for login and one for token refresh in actions/auth.js

That’s how typical API calling actions looks like with redux-api-middleware The middleware would perform an actual call, and dispatch REQUEST/SUCCESS/FAILURE actions to the redux middleware pipeline down to reducer functions.

So, lets’ create reducers/auth.js

We keep in a state original Access and Refresh tokens, and decoded tokens payload. Let’s add few state access methods to the same file

Now we can include auth reducer to the root and export auth selectors functions in the reducers/index.js

Login Form

Let’s start work on the UI. First of all, we need a simple TextInput component in the components/TextInput.js

TextInput component provides an input box and renders field errors like we have in Django Forms. We can use this component to construct a components/LoginForm.js

In the LoginForm, we keep username and password in a local state, without persisting it. Both TextInput and LoginForm are presentation components and have no connection to the Redux. We followed good practice to keep representational components separated.

Now we can create actual connected Login page container component in the containers/Login.js

Adding a little index.css can make everything looks better.

Running altogether

We almost ready to check our login functionality. Let’s make a whole application available for authenticated users only. To do that, we need simple containers/PrivateRoute.js component

The component performs authentication status check, and if user are not logged in, redirect to the login page.

Now open our main src/index.js and bind all together

Instead of just rendering an <App/> now we switch between login and app components depends on the application URL.

To allow the frontend to connect to our backend application, add proxy settings to the package.json file

It’s time to run npm start again!

You can check that UI properly respond to the invalid inputs, then put right credentials and login.

We can open browser developer tools, and see that Access and Refresh tokens saved in the localStorage

It’s time to call our first protected API endpoint and implement JWT refresh token workflow. Go to the Part III

Reusable workflow library #django #python http://viewflow.io

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store