npm package: @harlkwin/authflow-react
Description: React components and hooks for authflow authentication
Author: AuthFlow Contributors
Latest version: 0.4.15

# AuthFlow Frontend

> React/TypeScript components and hooks for AuthFlow authentication

Complete frontend package for building authentication UIs with AuthFlow backend.

## 🎯 Features

- ✅ **Zustand State Management** - Persistent auth state with localStorage
- ✅ **TanStack Query Hooks** - Data fetching with automatic caching and refetching
- ✅ **Automatic Token Refresh** - Axios interceptors handle 401s gracefully
- ✅ **TypeScript Support** - Full type safety throughout
- ✅ **Pre-built Components** - Login, Signup, UserMenu, ProtectedRoute, PermissionGate
- ✅ **Permission System** - Declarative role and permission checking
- ✅ **Responsive Design** - Mobile-friendly with Tailwind CSS

## 📦 Installation

```bash
npm install zustand @tanstack/react-query axios react-router-dom
```

## 🚀 Quick Start

### 1. Configure API Client

```typescript
// src/config.ts
export const API_BASE_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:8001/api/v1';
```

### 2. Setup Query Client Provider

```typescript
// app/layout.tsx or main.tsx
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';

const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      staleTime: 60 * 1000, // 1 minute
      retry: 1,
    },
  },
});

export default function App({ children }) {
  return (
    <QueryClientProvider client={queryClient}>
      {children}
    </QueryClientProvider>
  );
}
```

### 3. Use Authentication

```typescript
import { useLogin, useCurrentUser, useIsAuthenticated } from '@/hooks';
import { LoginPage, ProtectedRoute, UserMenu } from '@/components';

function LoginExample() {
  const login = useLogin();
  const isAuthenticated = useIsAuthenticated();

  const handleLogin = async () => {
    await login.mutateAsync({
      username: 'demo-admin',
      password: 'admin123',
    });
  };

  if (isAuthenticated) {
    return <div>Already logged in!</div>;
  }

  return (
    <button onClick={handleLogin} disabled={login.isPending}>
      {login.isPending ? 'Logging in...' : 'Login'}
    </button>
  );
}

function Dashboard() {
  const { data: user, isLoading } = useCurrentUser();

  if (isLoading) return <div>Loading...</div>;

  return (
    <div>
      <h1>Welcome {user?.username}!</h1>
      <UserMenu />
    </div>
  );
}
```

### 4. Protected Routes

```typescript
import { ProtectedRoute } from '@/components';
import { BrowserRouter, Routes, Route } from 'react-router-dom';

function App() {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="/login" element={<LoginPage />} />
        <Route
          path="/dashboard"
          element={
            <ProtectedRoute>
              <Dashboard />
            </ProtectedRoute>
          }
        />
        <Route
          path="/admin"
          element={
            <ProtectedRoute requiredRole="admin">
              <AdminPanel />
            </ProtectedRoute>
          }
        />
      </Routes>
    </BrowserRouter>
  );
}
```

### 5. Permission-Based Rendering

```typescript
import { PermissionGate } from '@/components';
import { useAuthStore } from '@/store/authStore';

function UserManagement() {
  const canWrite = useAuthStore((state) => state.hasPermission('users:write'));
  const canDelete = useAuthStore((state) => state.hasPermission('users:delete'));

  return (
    <div>
      <h2>Users</h2>

      {/* Only show if user has permission */}
      <PermissionGate permission="users:write">
        <button>Create User</button>
      </PermissionGate>

      {/* Only show for admins or moderators */}
      <PermissionGate anyRole={['admin', 'moderator']}>
        <button>Moderate Users</button>
      </PermissionGate>

      {/* Show fallback if no permission */}
      <PermissionGate permission="users:delete" fallback={<DisabledButton />}>
        <button>Delete User</button>
      </PermissionGate>
    </div>
  );
}
```

## 📚 API Reference

### Hooks

#### Authentication

- **`useLogin()`** - Login mutation
- **`useLogout()`** - Logout mutation
- **`useRegister()`** - User registration mutation
- **`useCurrentUser()`** - Get current user query
- **`useRefreshToken()`** - Refresh token mutation
- **`useChangePassword()`** - Change password mutation
- **`useForgotPassword()`** - Forgot password mutation
- **`useResetPassword()`** - Reset password mutation
- **`useActiveSessions()`** - Get active sessions query
- **`useRevokeSession(sessionId)`** - Revoke session mutation

#### User Management

- **`useUsers(filters?)`** - List users with pagination
- **`useUser(userId)`** - Get single user
- **`useCreateUser()`** - Create user mutation
- **`useUpdateUser()`** - Update user mutation
- **`useDeleteUser()`** - Delete user mutation
- **`useUserRoles(userId)`** - Get user roles
- **`useAssignUserRoles()`** - Assign roles to user
- **`useUpdateUserPassword()`** - Update user password
- **`useUserSessions(userId)`** - Get user sessions

#### Organizations

- **`useOrganizations(filters?)`** - List organizations
- **`useOrganization(orgId)`** - Get organization
- **`useCreateOrganization()`** - Create organization
- **`useUpdateOrganization()`** - Update organization
- **`useDeleteOrganization()`** - Delete organization
- **`useOrganizationMembers(orgId)`** - Get members
- **`useAddOrganizationMember()`** - Add member
- **`useRemoveOrganizationMember()`** - Remove member
- **`useOrganizationSettings(orgId)`** - Get settings
- **`useUpdateOrganizationSettings()`** - Update settings

#### Teams

- **`useTeams(filters?)`** - List teams
- **`useTeam(teamId)`** - Get team
- **`useCreateTeam()`** - Create team
- **`useUpdateTeam()`** - Update team
- **`useDeleteTeam()`** - Delete team
- **`useTeamMembers(teamId)`** - Get members
- **`useAddTeamMember()`** - Add member
- **`useRemoveTeamMember()`** - Remove member
- **`useTeamSubteams(teamId)`** - Get subteams
- **`useCreateSubteam()`** - Create subteam

#### Roles

- **`useRoles(filters?)`** - List roles
- **`useRole(roleId)`** - Get role
- **`useCreateRole()`** - Create role
- **`useUpdateRole()`** - Update role
- **`useDeleteRole()`** - Delete role
- **`useRoleMembers(roleId)`** - Get role members
- **`useAssignRole()`** - Assign role to user
- **`useUnassignRole()`** - Unassign role from user
- **`useRolePermissions(roleId)`** - Get role permissions

#### Convenience Hooks

- **`useIsAuthenticated()`** - Check if user is authenticated
- **`useUser()`** - Get current user from store
- **`useHasRole(role)`** - Check if user has role
- **`useHasPermission(permission)`** - Check if user has permission

### Components

#### `<LoginPage />`

Pre-built login page with form validation.

```typescript
import { LoginPage } from '@/components';

<Route path="/login" element={<LoginPage />} />
```

#### `<SignupPage />`

Pre-built signup page with validation.

```typescript
import { SignupPage } from '@/components';

<Route path="/signup" element={<SignupPage />} />
```

#### `<UserMenu />`

User dropdown menu with profile, settings, and logout.

```typescript
import { UserMenu } from '@/components';

<header>
  <UserMenu />
</header>
```

#### `<ProtectedRoute>`

Route-level authentication and authorization guard.

```typescript
import { ProtectedRoute } from '@/components';

// Require authentication only
<ProtectedRoute>
  <Dashboard />
</ProtectedRoute>

// Require specific role
<ProtectedRoute requiredRole="admin">
  <AdminPanel />
</ProtectedRoute>

// Require specific permission
<ProtectedRoute requiredPermission="users:write">
  <UserManagement />
</ProtectedRoute>

// Custom fallback
<ProtectedRoute
  requiredRole="admin"
  fallback={<div>Access Denied</div>}
>
  <AdminPanel />
</ProtectedRoute>
```

#### `<PermissionGate>`

Conditional rendering based on permissions or roles.

```typescript
import { PermissionGate } from '@/components';

// Require permission
<PermissionGate permission="users:write">
  <button>Edit User</button>
</PermissionGate>

// Require role
<PermissionGate role="admin">
  <AdminTools />
</PermissionGate>

// Require any of multiple roles
<PermissionGate anyRole={["admin", "moderator"]}>
  <ModeratorPanel />
</PermissionGate>

// With fallback
<PermissionGate permission="users:delete" fallback={<DisabledButton />}>
  <button>Delete User</button>
</PermissionGate>
```

### Store

#### `useAuthStore`

Zustand store for auth state management.

```typescript
import { useAuthStore } from '@/store/authStore';

// Get state
const user = useAuthStore((state) => state.user);
const isAuthenticated = useAuthStore((state) => state.isAuthenticated);

// Call actions
const login = useAuthStore((state) => state.login);
const logout = useAuthStore((state) => state.logout);

// Check permissions
const hasRole = useAuthStore((state) => state.hasRole('admin'));
const hasPermission = useAuthStore((state) => state.hasPermission('users:write'));
const hasAnyRole = useAuthStore((state) => state.hasAnyRole(['admin', 'moderator']));
const isInGroup = useAuthStore((state) => state.isInGroup('my-org'));
```

#### Store Selectors

```typescript
import {
  selectUser,
  selectIsAuthenticated,
  selectAccessToken,
  selectIsLoading,
  selectUserRoles,
  selectUserGroups,
} from '@/store/authStore';

const user = useAuthStore(selectUser);
const isAuthenticated = useAuthStore(selectIsAuthenticated);
```

## 🎨 Styling

Components use Tailwind CSS classes. To customize styles:

1. **Override with custom classes:**

```typescript
<LoginPage className="my-custom-class" />
```

2. **Create your own components** using the hooks:

```typescript
import { useLogin } from '@/hooks';

function CustomLoginForm() {
  const login = useLogin();
  // Your custom UI
}
```

## 🔧 Advanced Usage

### Custom API Client Configuration

```typescript
// src/api/client.ts
import { apiClient } from '@/api/client';

// Add custom headers
apiClient.defaults.headers.common['X-Custom-Header'] = 'value';

// Add request interceptor
apiClient.interceptors.request.use((config) => {
  // Custom logic
  return config;
});
```

### Programmatic Navigation After Login

```typescript
import { useLogin } from '@/hooks';
import { useNavigate } from 'react-router-dom';

function LoginForm() {
  const login = useLogin();
  const navigate = useNavigate();

  const handleLogin = async (credentials) => {
    try {
      await login.mutateAsync(credentials);
      navigate('/dashboard'); // Redirect after login
    } catch (error) {
      // Handle error
    }
  };
}
```

## 📖 Examples

See the `/examples` directory for complete working examples:

- Next.js 14 App Router
- Next.js 14 Pages Router
- React SPA with React Router
- Multi-tenant application

## 🤝 Contributing

Contributions welcome! Please read the contributing guide.

## 📄 License

MIT