Handle Firebase Auth persistence uisng Redux in React Application

Gauss CoderGauss Coder
3 min read

When using Firebase authentication with React, the Firebase auth state (logged-in user) doesn't persist automatically across page reloads. To solve this issue, you need to use Firebase's onAuthStateChanged method, which listens for authentication state changes, and update your Redux store (or component state) accordingly. Here's how to handle Firebase auth persistence:

Step 1: Firebase Auth Persistence

Firebase automatically persists authentication state using web storage (localStorage by default). However, you still need to listen for changes when the app is loaded to ensure the correct auth state is applied.

To enable this, use onAuthStateChanged when your app starts:

import { useEffect } from 'react';
import { getAuth, onAuthStateChanged } from 'firebase/auth';
import { useDispatch } from 'react-redux';
import { setUser, clearUser } from './store/authSlice'; // Redux actions for setting user state

const App = () => {
  const dispatch = useDispatch();
  const auth = getAuth();

  useEffect(() => {
    const unsubscribe = onAuthStateChanged(auth, (user) => {
      if (user) {
        // User is signed in, dispatch to store
        dispatch(setUser({
          uid: user.uid,
          email: user.email,
          displayName: user.displayName,
        }));
      } else {
        // User is signed out, clear the user from Redux store
        dispatch(clearUser());
      }
    });

    // Cleanup subscription on unmount
    return () => unsubscribe();
  }, [auth, dispatch]);

  return (
    <div>
      {/* Rest of your app */}
    </div>
  );
};

export default App;

Step 2: Create Redux Slice for User Authentication

To manage the Firebase user state in Redux, create a slice that will handle user login/logout:

// src/store/authSlice.ts
import { createSlice, PayloadAction } from '@reduxjs/toolkit';

interface UserState {
  uid: string | null;
  email: string | null;
  displayName: string | null;
}

const initialState: UserState = {
  uid: null,
  email: null,
  displayName: null,
};

const authSlice = createSlice({
  name: 'auth',
  initialState,
  reducers: {
    setUser: (state, action: PayloadAction<UserState>) => {
      state.uid = action.payload.uid;
      state.email = action.payload.email;
      state.displayName = action.payload.displayName;
    },
    clearUser: (state) => {
      state.uid = null;
      state.email = null;
      state.displayName = null;
    },
  },
});

export const { setUser, clearUser } = authSlice.actions;
export default authSlice.reducer;

Step 3: Configure Firebase Auth Persistence Strategy (Optional)

By default, Firebase persists the auth state using localStorage. You can change this persistence strategy to sessionStorage or none if needed.

import { getAuth, setPersistence, browserLocalPersistence, browserSessionPersistence } from 'firebase/auth';

const auth = getAuth();
setPersistence(auth, browserLocalPersistence) // or browserSessionPersistence
  .then(() => {
    // Firebase auth state is persisted in localStorage or sessionStorage
  })
  .catch((error) => {
    console.error('Failed to set persistence:', error);
  });

Step 4: Persist Redux State

You can use redux-persist (as mentioned earlier) to persist your Redux state to localStorage, which will include the user's authentication state:

// src/store/index.ts
import { configureStore } from '@reduxjs/toolkit';
import { persistStore, persistReducer } from 'redux-persist';
import storage from 'redux-persist/lib/storage'; // localStorage
import authReducer from './authSlice';

const persistConfig = {
  key: 'auth',
  storage,
};

const persistedAuthReducer = persistReducer(persistConfig, authReducer);

export const store = configureStore({
  reducer: {
    auth: persistedAuthReducer,
  },
});

export const persistor = persistStore(store);

Step 5: Usage in Your App

Once everything is set up, the Firebase authentication state will be checked on app initialization using onAuthStateChanged, and persisted to localStorage using redux-persist. The Redux store will handle the rest, ensuring the user state persists even on page reload.

Summary

  1. Use onAuthStateChanged: Listen for changes in the Firebase auth state and update Redux or component state accordingly.

  2. Persist Redux state: Use redux-persist to persist Redux auth state to localStorage or sessionStorage.

  3. Optional Firebase Persistence: Customize Firebase's auth persistence strategy if needed (localStorage, sessionStorage, or none).

This setup ensures that both Firebase authentication and your Redux store maintain state after page reloads.

0
Subscribe to my newsletter

Read articles from Gauss Coder directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Gauss Coder
Gauss Coder