Securing React Redux Apps With JWT Tokens

rajaraodv
rajaraodv
Mar 16, 2016 · 7 min read

JSON Web Token (JWT) is a way to generate auth tokens. It’s is an open standard (RFC 7519) that defines a simple way for securely transmitting information between client and server as a JSON object.

JWT Tokens V/S Cookies

Since HTTP is a stateless protocol, after you login (via username/password, OAuth 2 etc), for every future request to the server, you need to keep telling the server that you have already logged in so it can allow you to perform authenticated/authorized actions. One way to do this is via “session” cookies and other way is to use “auth” tokens.

JWT offers many benefits over using session cookies but the 2 major ones are:

  1. Server doesn’t need to ask DB to know who the user is because the user info is embedded inside the token itself! #performance!
  2. It works the same for both native mobile apps and browser clients. i.e. servers don’t need to implement two different mechanisms (browser v/s native).

Learn more: 10 things you should know about tokens and cookies

Note: You can click on the picture to zoom and read

Note: I’ll be using the same blog-post Redux app in here as well.

Live App: https://protected-escarpment-79486.herokuapp.com

Source Code: https://github.com/rajaraodv/react-redux-blog

What Does A JWT Token look like?

The token has 3 parts: <header>.<payload>.<signature>

  1. Header: A JSON(Base64 encoded) that has info about algorithm used(like HS256, RSA) and so on.
  2. Payload: A JSON(Base64 encoded) that has info about the user.
  3. Signature: A String that was generated using #1 + #2 + “a secret” (that only the server knows), using the algorithm mentioned in #1.

Below is the picture from https://jwt.io that shows the JWT token used in our blog app in both encoded and decoded manners.

As you can imagine, if the signature is valid and can be verified using the secret, we can simply decode the payload and get the user info w/o going to DB!

JWT Payload

Payload is just a JSON should contain anything that your app needs to identify user.

Typically this is:

  1. User Id, Username, Email, Image URL
  2. Any ACL like: isAdmin, isManager etc.

Note: JWT provides formal JSON keys like sub(subject = user), scope(string or array)that you can use to pass data as well (optional).

In the blog app, after the user logs in and tries to create a new post, we want to store authorId, authorName, authorUsername and authorImage along w/ Post’s own details and that’s why I’m using those fields in the payload. And when the user tries to create the post, we can verify the token and get access to all of those fields related to the user w/o going to the DB.

Implementing JWT Token In The Server

Irrespective of how the user signed up or logged in (via email, OAuth 2), all we need to do is:

  1. Generate JWT token and return it to the client
  2. Verify JWT token for protected routes in future requests

1. Generate JWT Token And Return It

Look at all the routes that users get authenticated. In our app user is authenticated when:

  1. User Signs Up (using email or Social network)
  2. User Signs In (after Sign up)
  3. Tries to Re-Authenticate using existing token (Browser Refresh)

1.1 Token Generator Function

Token is generated using useful fields from user model and secret (JWT_SECRET environment variable)

//Generate Token using secret from process.env.JWT_SECRET

1.2 Generate JWT Token: Signup Route

router.post(‘/users/signup’, function(req, res, next) {
var body = req.body;

1.3 Generate JWT Token: SignIn Route

router.post(‘/users/signin’, function(req, res) {
User
.findOne({username: req.body.username}) <-- Check username
.exec(function(err, user) {
if (err) throw err;

1.4 Generate JWT Token: Re-Authenticate Route

This route is called when the user refreshes the browser to re-authenticate the user. The assumption here is that the app has stored the token in localstorage or sessionStorage.

How it works:

  1. When the browser is refreshed, the app checks if there is a token, if so, it asks the server to verify the token and send the user info back (as though the user just signed in)

2. The server receives the token, decodes it using secret (JWT_SECRET environment variable), if it’s valid,

//get current user from token
router.get(‘/me/from/token’, function(req, res, next) {

2. Verify JWT Token For Protected Routes

In the blog app, we are protecting creating posts and deleting posts from non authenticated user.

Easiest way to verify token is to do what we did in the re-authenticate route. But we need a middleware function to protect various routes. All we do is to check if the request has “Authorization” header. If it does, and if we can successfully decode it using our JWT_SECRET stored in the server, then we store the user into the req.user so that other routes /posts can use it.

Front End: Storing And Using JWT In React Redux App

We need to implement:

  1. Sign In page
  2. Sign Up page
  3. Logout
  4. Browser Refresh

Implementing Sign Up and Sign In pages are similar to building any other pages. To keep this blog short, I suggest you go though:

  1. Blog: A Guide For Building A React Redux CRUD App
  2. Source code: https://github.com/rajaraodv/react-redux-blog

One new thing that’s different from regular CRUD app is implementing browser refresh.

Storing JWT Token

We need to store this token somewhere. We can store it as a client-side cookie or in a localStorage or sessionStorage. There are pros and cons in each option but for this app, we’ll store it in sessionStorage.

In our blog app, both SignUpFormContainer component and SignInFormContainer component contains code to store jwtToken in sessionStorage

dispatch(signUpUser(values))
.then((response) => {
let data = response.payload.data;

Browser Refresh — JWT ReAuthentication

The AppContainer component (parent component to all pages) implements the browser refresh code.

When the browser is refreshed,

  1. "loadUserFromToken” is called.
  2. If there is no token, nothing happens
  3. If there is token, we call “meFromToken” action to ask server if the token is valid.
  4. If the token is valid, we store it back as jwtToken in sessionStorage.
  5. And let other components know by dispatching meFromTokenSuccess, this helps other components that depends on if the user is loggedIn vs not-loggedIn to display themselves properly.
const mapDispatchToProps = (dispatch) => {
return {
loadUserFromToken: () => {
let token = sessionStorage.getItem(‘jwtToken’);
if(!token || token === ‘’) {//if there is no token, dont bother
return;
}

Live App: https://protected-escarpment-79486.herokuapp.com

Source Code: https://github.com/rajaraodv/react-redux-blog

That’s it!

🎉🎉🎉 If you like this post, please ❤❤❤ it below and please share it on Twitter (https://twitter.com/rajaraodv)🎉🎉🎉

My Other Blogs

ES6

  1. 5 JavaScript “Bad” Parts That Are Fixed In ES6

WebPack

  1. Webpack — The Confusing Parts
  2. Webpack & Hot Module Replacement [HMR]
  3. Webpack’s HMR And React-Hot-Loader — The Missing Manual

Draft.js

  1. Why Draft.js And Why You Should Contribute
  2. How Draft.js Represents Rich Text Data

React And Redux :

  1. Step by Step Guide To Building React Redux Apps
  2. A Guide For Building A React Redux CRUD App (3-page app)
  3. Using Middlewares In React Redux Apps
  4. Adding A Robust Form Validation To React Redux Apps
  5. Securing React Redux Apps With JWT Tokens
  6. Handling Transactional Emails In React Redux Apps
  7. The Anatomy Of A React Redux App

Salesforce

  1. Developing React Redux Apps In Salesforce’s Visualforce

Thanks for reading!!😀🙏

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade

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