Authentication persistence with Redux Toolkit

In modern web applications, authentication is an essential part of ensuring secure access to resources. One common requirement is the ability for users to stay authenticated even after they close and reopen the application. This is achieved through the concept of authentication persistence.

In this blog post, we will explore how to implement authentication persistence using Redux Toolkit, a powerful library for managing state in Redux applications.

Understanding Authentication Persistence

Authentication persistence refers to the ability of an application to remember and maintain a user’s authentication state across sessions. When a user logs in, their authentication token is typically stored in local storage or a cookie. This token is then used to authenticate subsequent requests to protected resources.

To implement authentication persistence, we need to:

  1. Store the authentication token securely.
  2. Retrieve the authentication token when the application loads.
  3. Set the authentication token in each request to the server.
  4. Handle the case where the authentication token is invalid or expired.

Implementing Authentication Persistence with Redux Toolkit

Step 1: Create a Slice

In Redux Toolkit, we can create a “slice” to handle authentication related state and logic. This slice will include actions and reducers to manage the authentication token.

import { createSlice } from '@reduxjs/toolkit';

const authSlice = createSlice({
  name: 'auth',
  initialState: {
    token: null,
  },
  reducers: {
    setToken: (state, action) => {
      state.token = action.payload;
    },
    clearToken: (state) => {
      state.token = null;
    },
  },
});

export const { setToken, clearToken } = authSlice.actions;
export default authSlice.reducer;

Step 2: Persist and Retrieve the Token

To persist and retrieve the authentication token, we can use the localStorage API. In the slice, we can handle these operations during the initial state setup and whenever the token is set or cleared.

import { setToken, clearToken } from './authSlice';

const loadToken = () => {
  const token = localStorage.getItem('token');
  
  // Check if token is valid or expired
  
  // Dispatch the setToken action with the retrieved token
  
};

const saveToken = (token) => {
  localStorage.setItem('token', token);
};

export const authenticateUser = (token) => (dispatch) => {
  loadToken(token);
  saveToken(token);
  dispatch(setToken(token));
};

export const logoutUser = () => (dispatch) => {
  localStorage.removeItem('token');
  dispatch(clearToken());
};

Step 3: Set the Token in Requests

To ensure that each request sent to the server is authenticated, we can use a middleware like axios or fetch. In the middleware, we can intercept each request and set the authentication token in the headers.

import axios from 'axios';
import store from './store';

axios.interceptors.request.use((config) => {
  const { token } = store.getState().auth;
  
  if (token) {
    config.headers.Authorization = `Bearer ${token}`;
  }
  
  return config;
});

export default axios;

Step 4: Handle Invalid or Expired Tokens

If the authentication token is invalid or expired, we need to handle this situation gracefully. One way to do this is by implementing an interceptor for error responses in the middleware.

axios.interceptors.response.use(
  (response) => response,
  (error) => {
    if (error.response.status === 401) {
      store.dispatch(clearToken());
      
      // Redirect to the login page or show a notification
    }
    
    return Promise.reject(error);
  }
);

Conclusion

With Redux Toolkit, implementing authentication persistence becomes easier by leveraging the power of slices, middleware, and interceptors. By persisting and retrieving the authentication token, setting it in requests, and handling invalid tokens, we can provide a seamless authentication experience for users in our web applications.

#hashtags: #authentication #reduxtoolkit