Handling User Logout in Zustand When Axios Interceptor Detects Unauthorized Status
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.