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.
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
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.
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.
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