React Query Authentication Hooks

2.4.3 · active · verified Wed Apr 22

react-query-auth is a specialized library designed to streamline user authentication management within React applications by leveraging `@tanstack/react-query`. It provides a `configureAuth` function that acts as a factory, generating custom hooks (`useUser`, `useLogin`, `useRegister`, `useLogout`) and an `AuthLoader` component. These utilities abstract away the complexities of integrating authentication state with React Query's caching mechanisms, treating user data as server state. The current stable version is `2.4.3`. While no explicit release cadence is stated, the versioning suggests active maintenance and development. Its key differentiator lies in its deep integration with React Query, offering a consistent approach to manage authentication alongside other server-derived data, reducing boilerplate for common authentication flows. It requires users to provide their own API interaction functions for fetching, logging in, registering, and logging out, making it adaptable to any backend or authentication method.

Common errors

Warnings

Install

Imports

Quickstart

This quickstart demonstrates how to configure `react-query-auth` with mock API functions, use the generated `useUser`, `useLogin`, and `useLogout` hooks, and implement the `AuthLoader` component to manage initial loading and authentication states within a React Query application.

import React from 'react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { configureAuth, AuthLoader } from 'react-query-auth';

const queryClient = new QueryClient();

// Mock API functions for demonstration
const api = {
  get: async (url: string) => {
    if (url === '/me') {
      // Simulate authenticated user
      const user = localStorage.getItem('mock-user');
      return user ? JSON.parse(user) : null;
    }
    throw new Error('Not found');
  },
  post: async (url: string, data?: any) => {
    if (url === '/login' && data.email === 'test@example.com' && data.password === 'password') {
      const user = { id: '123', email: data.email };
      localStorage.setItem('mock-user', JSON.stringify(user));
      return user;
    }
    if (url === '/register') {
      const user = { id: '456', email: data.email };
      localStorage.setItem('mock-user', JSON.stringify(user));
      return user;
    }
    if (url === '/logout') {
      localStorage.removeItem('mock-user');
      return null;
    }
    throw new Error('API Error');
  }
};

const { useUser, useLogin, useLogout } = configureAuth({
  userFn: () => api.get('/me'),
  loginFn: (credentials) => api.post('/login', credentials),
  registerFn: (credentials) => api.post('/register', credentials),
  logoutFn: () => api.post('/logout')
});

function UserInfo() {
  const user = useUser();
  const logout = useLogout();

  if (user.isLoading) {
    return <div>Loading user info...</div>;
  }

  if (user.error) {
    return <div style={{ color: 'red' }}>Error: {user.error.message}</div>;
  }

  if (!user.data) {
    return (
      <div>
        <div>Not logged in</div>
        <button onClick={() => useLogin().mutate({ email: 'test@example.com', password: 'password' })}>Login</button>
      </div>
    );
  }

  return (
    <div>
      <div>Logged in as {user.data.email}</div>
      <button disabled={logout.isLoading} onClick={() => logout.mutate({})}>
        Log out
      </button>
    </div>
  );
}

function AuthScreen() {
  const login = useLogin();
  const register = useRegister();

  const handleLogin = () => login.mutate({ email: 'test@example.com', password: 'password' });
  const handleRegister = () => register.mutate({ email: 'new@example.com', password: 'password' });

  return (
    <div>
      <h2>Authentication</h2>
      <button onClick={handleLogin}>Login as Test User</button>
      <button onClick={handleRegister}>Register New User</button>
      {login.error && <div style={{ color: 'red' }}>Login Error: {login.error.message}</div>}
      {register.error && <div style={{ color: 'red' }}>Register Error: {register.error.message}</div>}
    </div>
  );
}

function App() {
  return (
    <QueryClientProvider client={queryClient}>
      <h1>My Auth App</h1>
      <AuthLoader
        renderLoading={() => <div>Initial authentication check...</div>}
        renderUnauthenticated={() => <AuthScreen />}
      >
        <UserInfo />
      </AuthLoader>
    </QueryClientProvider>
  );
}

export default App;

view raw JSON →