@mehdashti/auth-react
v0.2.0
Published
React authentication hooks and components for Smart Platform
Maintainers
Readme
@smart/auth-react
React authentication hooks and components for Smart Platform
Installation
pnpm add @smart/auth-react @tanstack/react-queryFeatures
- ✅ 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
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
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
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.
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.
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.
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.
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.
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
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.
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
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
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
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:
import type {
User,
AuthTokens,
LoginCredentials,
LoginResponse,
AuthContextValue,
} from "@smart/auth-react";License
MIT
