DEV Community


Posted on


A Token of Persistence: JWT Tokens and Redux Persist

A couple weeks ago, I implemented a log-in feature on my counting calories application, Counting Cookies. It was a really simplified method but it was necessary to give users private access to their records. What I was really seeking to do was persist my state in order to allow other features to work properly such as updating profile information or a single component for my daily records form.

There seems to be more than a few ways to accomplish this, all with their own strengths and drawbacks. Originally I chose a path I was most familiar with and which I described before, assigning the user’s id to session, which eventually seemed a little too simple and not compatible with keeping a user logged in. I saw a decent amount of developers choose to use tokens, but that are stored in localStorage or sessionStorage, a method that works but can be a security risk.

I chose to use JWT or JSON web tokens that are issued when a user logs in and then stored in cookies. The set-up wasn’t terribly hard, just a few updates to the backend including authenticating the token and checking if there is a current user based on the token. I also added some additional routes for logging in, logging out, and checking for a current user, to help persist state between components.

A token is considered a credential, which must be sent along when making a fetch request to the backend. Sending the credential worked out fine, but if the configuration isn’t set up correctly CORS will throw a hissy fit and prevent the application from working. CORS was originally set up to handle any requests no matter the route by using a * or a wildcard. This is not allowed when sending highly private credentials between the front and backend, so a specific address must be set, essentially giving permission to that particular website to access the data.

Make sure the host location is correct or else you’ll waste hours searching online for a solution for a problem that doesn’t exist. In my case, I was setting my origin to my backend web address rather than the frontend where the request is originally being made. But the errors CORS give you will not give you that hint, instead you will see errors like “Access-Control-Allow-Origin missing“ and other problems with the pre-flight response. I learned about them, but not necessary to this particular problem.

Once I correctly set the origin, the credentials were being sent back and forth, but refreshing my page would still reroute to the root page which is my login page. I had to take advantage of the new current_user validation that I had set up in my application controller in my backend. I created an action, also called current_user, that will fire when the initial component is first mounted, sending a fetch request to check if the user is indeed logged_in?

   def jwt_key

   def issue_token(user)
       JWT.encode({user_id:}, jwt_key, 'HS256')
   def decoded_token
         JWT.decode(token, jwt_key, true, { :algorithm => 'HS256' })
       rescue JWT::DecodeError
         [{error: "Invalid Token"}]
    def authorized
       render json: { message: 'Please log in' }, status: :unauthorized unless logged_in?

   def token
    def user_id
    def current_user
       @user ||= User.find_by(id: user_id)
    def logged_in?
Enter fullscreen mode Exit fullscreen mode

Now when I refreshed the page or tried a broken link, it would redirect to the users homepage since they were technically still signed in. That was great, until I realized my signout action wasn’t working. It’s pretty clear how to initialize a token for a user, but the drawback is the token would remain until it expired in the backend. So trying to make a fetch request to destroy the current_user was coming up fruitless, it seemed the best solution was to remove the token from the Cookies in the frontend, no fetching required.

        case 'LOGOUT_USER':
            // localStorage.clear();
            return {user: [],
                loggedIn: false,
                token: ""
Enter fullscreen mode Exit fullscreen mode

Finally, I was able to log-out of my application without it redirecting to the user’s homepage, but the state wasn’t persisting on other pages. When I clicked the link for a user’s homepage, the address bar would briefly show the correct link before redirecting itself to the root page. I needed something to persist the state as it was disappearing when a separate page was called.

Wouldn’t you know it, a kind-hearted person made a package for Redux for just that purpose, Redux-Persist. It meant I had to configure a store that would be passed to the index page when initializing the provider when originally rendered.

import {createStore, applyMiddleware} from 'redux'
import { persistReducer, persistStore } from 'redux-persist'
import storage from 'redux-persist/lib/storage'
import thunkMiddleware from 'redux-thunk';
import usersReducer from './reducers/usersReducer'
import recordsReducer from './reducers/recordsReducer'
import loginReducer from './reducers/loginReducer'
import { combineReducers } from 'redux';

const rootReducer = combineReducers({

  const persistenceConfigs = {
    key: "loggedIn",

  const persistedReducer = persistReducer(persistenceConfigs, rootReducer)
  const store = createStore(persistedReducer, applyMiddleware(thunkMiddleware));
  const persistor = persistStore(store)
  export { persistor, store }
Enter fullscreen mode Exit fullscreen mode

It worked a little too well for my needs because now I wasn’t able to logout again, before I could try my profile link. I fixed that by adding the signoutUser action as a click function to the link. Next I tackled the profile page, by moving it higher in the Switch statement, which finally got it to start working properly.

At last, my project felt like an actual functional website that people can use. Now I can focus more on the cosmetic look and deploying it to Heroku so it can be reviewed by Chingu before our project starts. I’m sure I’ll tell you all about it next week. Stay tuned!

Top comments (0)

The JavaScript Brief

1. Top 5 MERN STACK projects to improve your practical understanding

Boost your MERN Stack development skills by undertaking interesting beginner projects. These five engaging projects cover web applications and range from social media website applications to geo-social networking maps. Hone your understanding and apply modern techniques backed up by hands-on experience.

2. How To Optimize Your React App’s Performance

Learn the best optimizing techniques to make your React applications faster and more efficient. Focusing on the identification of performance bottlenecks and common pitfalls to avoid, these optimization strategies will keep your applications running smoothly even when faced with growing complexity.

3. A story of let, const, object mutation, and a bug in my code

In the pursuit of bug-free code, explore an incident involving a mix-up between const and let, making sure your custom code works effectively with third

party documentation. Discover best practices on program flow and learn about JavaScript's unpredictable aspects to ensure your core code is robust.