React hooks
Client-side React hooks for KavachOS auth.
Overview
@kavachos/react provides React hooks and a context provider for building auth UIs on top of KavachOS. It works with Next.js App Router, Next.js Pages Router, Vite, and any React 18+ setup.
The package itself has no Node.js dependencies — it runs entirely in the browser. Your KavachOS API handler can sit behind Next.js Edge Runtime, Cloudflare Workers, Deno Deploy, or any other edge runtime, and the hooks talk to it over standard fetch.
All hooks must be rendered inside KavachProvider. The provider talks to your KavachOS API route — no direct database access from the browser.
Installation
pnpm add @kavachos/reactProvider setup
Wrap your app with KavachProvider. In Next.js App Router, create a client component and import it from your root layout.
// app/providers.tsx
'use client';
import { KavachProvider } from '@kavachos/react';
export function Providers({ children }: { children: React.ReactNode }) {
return (
<KavachProvider basePath="/api/kavach">
{children}
</KavachProvider>
);
}// app/layout.tsx
import { Providers } from './providers';
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>
<Providers>{children}</Providers>
</body>
</html>
);
}Prop
Type
Sessions are stored in localStorage under the key kavach_session. The hooks automatically restore the session on page reload.
useSession
Returns the raw session object. Useful when you need the session token or expiry directly.
import { useSession } from '@kavachos/react';
function SessionDebug() {
const { session, isLoading } = useSession();
if (isLoading) return <p>Loading...</p>;
if (!session) return <p>No active session.</p>;
return (
<p>
Session expires: {new Date(session.expiresAt).toLocaleString()}
</p>
);
}Prop
Type
useUser
Returns the authenticated user and a boolean flag. This is the most common hook for protecting UI.
import { useUser } from '@kavachos/react';
function ProfileCard() {
const { user, isAuthenticated, isLoading } = useUser();
if (isLoading) return <Skeleton />;
if (!isAuthenticated) return <SignInPrompt />;
return (
<div>
<p>{user.name}</p>
<p>{user.email}</p>
</div>
);
}Prop
Type
useSignIn
Handles email and password sign-in. Returns a signIn function and state fields.
The hook posts to POST /api/kavach/auth/sign-in (not /sign-in/email). Make sure your adapter is mounted at /api/kavach.
import { useSignIn } from '@kavachos/react';
import { useRouter } from 'next/navigation';
function SignInForm() {
const { signIn, isLoading, error } = useSignIn();
const router = useRouter();
async function handleSubmit(e: React.FormEvent<HTMLFormElement>) {
e.preventDefault();
const form = new FormData(e.currentTarget);
const result = await signIn({
email: form.get('email') as string,
password: form.get('password') as string,
});
if (result.success) router.push('/dashboard');
}
return (
<form onSubmit={handleSubmit}>
<input name="email" type="email" />
<input name="password" type="password" />
{error && <p>{error.message}</p>}
<button type="submit" disabled={isLoading}>
{isLoading ? 'Signing in...' : 'Sign in'}
</button>
</form>
);
}useSignUp
Handles new account registration. Posts to POST /api/kavach/auth/sign-up (not /sign-up/email).
import { useSignUp } from '@kavachos/react';
function SignUpForm() {
const { signUp, isLoading, error } = useSignUp();
async function handleSubmit(e: React.FormEvent<HTMLFormElement>) {
e.preventDefault();
const form = new FormData(e.currentTarget);
await signUp({
email: form.get('email') as string,
password: form.get('password') as string,
name: form.get('name') as string,
});
}
return (
<form onSubmit={handleSubmit}>
<input name="name" type="text" />
<input name="email" type="email" />
<input name="password" type="password" />
{error && <p>{error.message}</p>}
<button type="submit" disabled={isLoading}>Create account</button>
</form>
);
}useSignOut
Signs the user out and clears the local session. Optionally redirects after sign-out.
import { useSignOut } from '@kavachos/react';
function NavBar() {
const { signOut } = useSignOut();
return (
<nav>
<button onClick={() => signOut({ redirectTo: '/login' })}>
Sign out
</button>
</nav>
);
}useAgents
Lets your UI create, list, and revoke agents without going through a custom API route.
import { useAgents } from '@kavachos/react';
function Dashboard() {
const { user, isAuthenticated, isLoading } = useUser();
const { agents, create, revoke, isLoading: agentsLoading } = useAgents();
if (!isAuthenticated) return null;
async function handleCreate() {
await create({
name: 'my-bot',
type: 'autonomous',
permissions: [
{ resource: 'reports:*', actions: ['read'] },
],
});
}
return (
<div>
<button onClick={handleCreate}>New agent</button>
{agentsLoading && <p>Loading agents...</p>}
{agents.map((agent) => (
<div key={agent.id}>
<span>{agent.name}</span>
<button onClick={() => revoke(agent.id)}>Revoke</button>
</div>
))}
</div>
);
}Prop
Type