npm package: @mehdashti/auth-react
Description: React authentication hooks and components for Smart Platform
Author: mehdashti
Latest version: 0.2.0

# @smart/auth-react

> React authentication hooks and components for Smart Platform

## Installation

```bash
pnpm add @smart/auth-react @tanstack/react-query
```

## Features

- ✅ **Auth Context**: Centralized authentication state
- ✅ **Auth Hooks**: useAuth, useUser, useHasRole
- ✅ **Protected Routes**: Component for protecting authenticated routes
- ✅ **Token Management**: Automatic token storage and retrieval
- ✅ **TanStack Query Integration**: Works seamlessly with @smart/data-client

## Quick Start

### 1. Setup Auth Provider

```typescript
import { QueryClientProvider } from "@tanstack/react-query";
import { createQueryClient } from "@smart/data-client";
import { AuthProvider } from "@smart/auth-react";

const queryClient = createQueryClient();

function App() {
  return (
    <QueryClientProvider client={queryClient}>
      <AuthProvider
        loginEndpoint="/api/auth/login"
        logoutEndpoint="/api/auth/logout"
        currentUserEndpoint="/api/users/me"
        refreshEndpoint="/api/auth/refresh"
      >
        <YourApp />
      </AuthProvider>
    </QueryClientProvider>
  );
}
```

### 2. Use Auth Hooks

```typescript
import { useAuth } from "@smart/auth-react";

function LoginPage() {
  const { login, isLoading } = useAuth();

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    const formData = new FormData(e.target as HTMLFormElement);

    try {
      await login({
        email: formData.get("email") as string,
        password: formData.get("password") as string,
      });
      // Redirect to dashboard
    } catch (error) {
      console.error("Login failed:", error);
    }
  };

  return (
    <form onSubmit={handleSubmit}>
      <input name="email" type="email" required />
      <input name="password" type="password" required />
      <button type="submit" disabled={isLoading}>
        Login
      </button>
    </form>
  );
}
```

### 3. Protect Routes

```typescript
import { ProtectedRoute } from "@smart/auth-react";
import { Navigate } from "react-router-dom";

function Dashboard() {
  return (
    <ProtectedRoute
      fallback={<div>Loading...</div>}
      unauthorized={<Navigate to="/login" />}
    >
      <DashboardContent />
    </ProtectedRoute>
  );
}
```

## Hooks

### useAuth

Access authentication state and methods.

```typescript
import { useAuth } from "@smart/auth-react";

function Header() {
  const { user, isAuthenticated, logout } = useAuth();

  if (!isAuthenticated) {
    return <LoginButton />;
  }

  return (
    <div>
      <span>Welcome, {user?.email}</span>
      <button onClick={logout}>Logout</button>
    </div>
  );
}
```

### useUser

Access current user data.

```typescript
import { useUser } from "@smart/auth-react";

function UserProfile() {
  const user = useUser();

  if (!user) {
    return <div>Not logged in</div>;
  }

  return (
    <div>
      <h1>{user.name}</h1>
      <p>{user.email}</p>
    </div>
  );
}
```

### useHasRole

Check if user has a specific role.

```typescript
import { useHasRole } from "@smart/auth-react";

function AdminPanel() {
  const isAdmin = useHasRole("admin");

  if (!isAdmin) {
    return <div>Access Denied</div>;
  }

  return <div>Admin Panel</div>;
}
```

### useHasAnyRole

Check if user has any of the specified roles.

```typescript
import { useHasAnyRole } from "@smart/auth-react";

function EditorTools() {
  const canEdit = useHasAnyRole(["admin", "editor"]);

  if (!canEdit) {
    return null;
  }

  return <EditToolbar />;
}
```

## Components

### ProtectedRoute

Protect routes that require authentication.

```typescript
import { ProtectedRoute } from "@smart/auth-react";
import { Navigate } from "react-router-dom";

// Basic usage
<ProtectedRoute>
  <Dashboard />
</ProtectedRoute>

// With custom fallbacks
<ProtectedRoute
  fallback={<Spinner />}
  unauthorized={<Navigate to="/login" />}
>
  <Dashboard />
</ProtectedRoute>

// With role-based access
<ProtectedRoute
  requiredRoles={["admin"]}
  unauthorized={<Navigate to="/forbidden" />}
>
  <AdminPanel />
</ProtectedRoute>
```

## Token Management

Tokens are automatically stored in localStorage.

### Manual Token Access

```typescript
import {
  getAccessToken,
  setTokens,
  clearTokens,
} from "@smart/auth-react";

// Get current access token
const token = getAccessToken();

// Manually set tokens (not usually needed)
setTokens(accessToken, refreshToken);

// Clear tokens
clearTokens();
```

## Integration with Data Client

Use auth tokens automatically with API requests.

```typescript
import { useApiQuery, apiFetch } from "@smart/data-client";
import { getAccessToken } from "@smart/auth-react";

function UserList() {
  const { data } = useApiQuery({
    queryKey: ["users"],
    queryFn: async () => {
      const token = getAccessToken();
      return apiFetch("/api/users", {
        headers: {
          Authorization: `Bearer ${token}`,
        },
      });
    },
  });

  return <div>{/* Render users */}</div>;
}
```

## Router Integration

### React Router

```typescript
import { BrowserRouter, Routes, Route, Navigate } from "react-router-dom";
import { ProtectedRoute } from "@smart/auth-react";

function AppRoutes() {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="/login" element={<LoginPage />} />
        <Route
          path="/dashboard"
          element={
            <ProtectedRoute unauthorized={<Navigate to="/login" />}>
              <Dashboard />
            </ProtectedRoute>
          }
        />
        <Route
          path="/admin"
          element={
            <ProtectedRoute
              requiredRoles={["admin"]}
              unauthorized={<Navigate to="/" />}
            >
              <AdminPanel />
            </ProtectedRoute>
          }
        />
      </Routes>
    </BrowserRouter>
  );
}
```

### TanStack Router

```typescript
import { createRoute } from "@tanstack/react-router";
import { useAuth } from "@smart/auth-react";

const dashboardRoute = createRoute({
  getParentRoute: () => rootRoute,
  path: "/dashboard",
  beforeLoad: async () => {
    const { isAuthenticated } = useAuth();
    if (!isAuthenticated) {
      throw redirect({ to: "/login" });
    }
  },
  component: Dashboard,
});
```

## Error Handling

```typescript
import { useAuth } from "@smart/auth-react";

function LoginForm() {
  const { login } = useAuth();
  const [error, setError] = useState<string | null>(null);

  const handleLogin = async (credentials) => {
    try {
      setError(null);
      await login(credentials);
    } catch (err) {
      setError(err instanceof Error ? err.message : "Login failed");
    }
  };

  return (
    <form>
      {error && <div className="error">{error}</div>}
      {/* Form fields */}
    </form>
  );
}
```

## Type Safety

All exports are fully typed:

```typescript
import type {
  User,
  AuthTokens,
  LoginCredentials,
  LoginResponse,
  AuthContextValue,
} from "@smart/auth-react";
```

## License

MIT