Handling User Logout in Zustand When Axios Interceptor Detects Unauthorized Status

Content Image

When building authentication systems in React applications, it's common to use state management libraries like Zustand to store and manage the authentication state. However, there may be cases where you need to trigger a user logout outside of a React component, such as when an Axios interceptor detects an unauthorized status code from the backend API.

Let's explore how we can handle this scenario using Zustand and Axios interceptors.

Zustand Authentication Store

First, let's define our Zustand store to manage the authentication state:

const authStore = (set: any) => ({
    ...initialState,
    doLogin: async (user: TLoggedInRequest) => {
        try {
            set(() => ({status: "pending"}))
            const result = await loginService.login(user)
            set(() => ({
                status: "resolved",
                user: result?.data.user,
                error: null
            }))
        } catch (error) {
            console.log("rejected error", error)
            set((state: any) => ({status: "rejected", error}))
        }
    },
    doLogout: async () => {
        await loginService.logout()
        set(() => initialState)
        history.push("/")
    }
});

In this store, we have actions for doLogin and doLogout to handle user authentication and logout respectively.

Axios HTTP Client

Next, let's define our HTTP client using Axios for making API requests:

async get<TResponse>(path: string): Promise<TResponse> {
    try {
        const response = await this.instance.get<TResponse>(path);
        return response.data;
    } catch (error: any) {
        handleServiceError(error);
    }
    return {} as TResponse;
}

This is a simplified example of a GET request method in our HTTP client.

React Component Logout

In our React component, we can access the doLogout action from the Zustand store and trigger a user logout:

const doLogoutSelector = (state: any) => state.doLogout;
const doLogout = useAuthStore(doLogoutSelector);

const signout = () => {
        doLogout()
        return <Navigate replace to="/"/>
}

When the signout function is called, it invokes the doLogout action from the store and redirects the user to the home page.

Calling Logout Outside React Component

Now, the question arises: how can we call the doLogout action outside of a React component, such as in an Axios interceptor when a 401 Unauthorized status code is detected?

The solution is simple. We can directly access the Zustand store's getState method and invoke the doLogout action:

useAuthStore.getState().doLogout()

In our Axios error interceptor, we can check for the 401 status code and call the logout action:

if (error instanceof AxiosError && response?.status === 401) {
  useAuth.getState().logout()
}

Make sure to define the useAuth store with the logout action:

export const useAuth = create((set, get) => ({
  logout: async () => {
    ...
  },
  ...
}))

By directly accessing the store's state and invoking the logout action, we can trigger a user logout from anywhere in our application, including Axios interceptors.

Conclusion

Handling user logout in a React application with Zustand becomes straightforward once we understand how to access the store's actions outside of React components. By utilizing Zustand's getState method, we can invoke the logout action from Axios interceptors or any other part of our application when needed.

Remember to properly define your authentication store actions and handle any necessary cleanup or redirection after the logout process.

With this approach, you can ensure a smooth user logout experience, even when triggered by unexpected events like unauthorized API responses.

Join our waitlist

Get notified about updates and be the first to get early access.

    Privacy Policy