Back to writing
Original post by Gagan Deep Singh, canonical on thegdsks.comAlso on Dev.toDiscuss on Dev.to

Add auth to your AI agents in 5 minutes with KavachOS

Auth libraries handle human sign-in. But what happens when your AI agent needs to read from GitHub,...

5 min read

Auth libraries handle human sign-in. But what happens when your AI agent needs to read from GitHub, deploy to production, or call another agent's API? You end up building a custom permissions layer, rolling your own tokens, and hoping your audit trail holds up.

I got tired of building that layer from scratch for every project, so I built KavachOS. It handles both human auth and agent identity in one library. Here's how to get it running.

What you'll build#

text
┌─────────────────────────────────────────────┐
│                  Your App                   │
│                                             │
│  ┌──────────┐   ┌──────────┐   ┌──────────┐ │
│  │  Human   │   │  Agent   │   │  Agent   │ │
│  │  (Ada)   │   │ (reader) │   │ (deploy) │ │
│  └────┬─────┘   └────┬─────┘   └────┬─────┘ │
│       │              │              │       │
│       ▼              ▼              ▼       │
│  ┌──────────────────────────────────────┐   │
│  │          KavachOS Auth Layer         │   │
│  │  sessions · tokens · permissions ·   │   │
│  │  delegation · audit · MCP OAuth      │   │
│  └──────────────────────────────────────┘   │
│       │                                     │
│       ▼                                     │
│  ┌──────────┐                               │
│  │ SQLite / │                               │
│  │ Postgres │                               │
│  └──────────┘                               │
└─────────────────────────────────────────────┘

A Node.js API where humans sign in with email/password, AI agents get their own identity with scoped permissions, and every action is authorized and logged.

About 5 minutes if you type fast.

Setup#

bash
mkdir my-app && cd my-app
npm init -y
npm install kavachos @kavachos/hono hono

Create index.ts:

typescript
import { createKavach } from "kavachos";
import { emailPassword } from "kavachos/auth";
import { createHonoAdapter } from "@kavachos/hono";
import { Hono } from "hono";

const kavach = await createKavach({
  database: { provider: "sqlite", url: "kavach.db" },
  plugins: [emailPassword()],
});

const app = new Hono();
app.route("/api/auth", createHonoAdapter(kavach));

That gives you a full auth API. Sign-up, sign-in, sign-out, session management. The SQLite database is created automatically.

Create a user#

bash
curl -X POST http://localhost:3000/api/auth/sign-up/email \
  -H "Content-Type: application/json" \
  -d '{"email": "ada@example.com", "password": "secret123", "name": "Ada"}'

Response:

json
{
  "data": {
    "token": "kv_sess_abc123...",
    "user": { "id": "user-1", "email": "ada@example.com", "name": "Ada" }
  }
}

Now the interesting part: agent identity#

This is where KavachOS is different from other auth libraries. You can give AI agents their own identity with scoped permissions.

typescript
// Create an agent that can read GitHub repos but needs approval to deploy
const agent = await kavach.agent.create({
  ownerId: "user-1",
  name: "github-reader",
  type: "autonomous",
  permissions: [
    { resource: "mcp:github:*", actions: ["read"] },
    {
      resource: "mcp:deploy:production",
      actions: ["execute"],
      constraints: { requireApproval: true },
    },
  ],
});

console.log(agent.token); // kv_agent_xyz789...

The agent gets a cryptographic bearer token and a set of permissions. The permissions use wildcard matching, so mcp:github:* matches mcp:github:repos, mcp:github:issues, and anything else under that namespace.

How wildcard matching works#

text
Permission:  mcp:github:*

  mcp:github:repos      ✅ match
  mcp:github:issues     ✅ match
  mcp:github:pulls      ✅ match
  mcp:deploy:staging    ❌ no match
  mcp:slack:send        ❌ no match

Authorize agent actions#

Before your agent does something, check if it's allowed:

typescript
const result = await kavach.authorize(agent.id, {
  action: "read",
  resource: "mcp:github:repos",
});

if (result.allowed) {
  // Go ahead, read the repos
  console.log("Authorized. Audit ID:", result.auditId);
} else {
  console.log("Denied:", result.reason);
}

Every authorization check is logged with an audit ID. You can trace what any agent did, when, and whether it was allowed.

Delegation chains#

Agents can delegate permissions to other agents, with limits:

text
Ada (human)
  └── github-reader (agent)
        permissions: [mcp:github:* → read, mcp:deploy:* → execute]
        │
        └── repo-scanner (sub-agent)
              permissions: [mcp:github:repos → read]
              ↑ subset of parent's permissions only
typescript
const subAgent = await kavach.agent.create({
  ownerId: agent.id, // owned by another agent, not a human
  name: "repo-scanner",
  type: "autonomous",
  permissions: [
    { resource: "mcp:github:repos", actions: ["read"] },
  ],
});

The sub-agent can only have permissions that are a subset of its parent's permissions. If the parent agent gets revoked, all its sub-agents lose access too. You can also set depth limits to prevent chains from going too deep.

Wire it to MCP#

If you're using the Model Context Protocol, KavachOS ships an OAuth 2.1 authorization server:

typescript
import { mcpOAuth } from "kavachos/mcp";

const kavach = await createKavach({
  database: { provider: "sqlite", url: "kavach.db" },
  plugins: [emailPassword(), mcpOAuth()],
});

This gives you PKCE S256, dynamic client registration (RFC 7591), and resource indicators (RFC 8707). Your MCP tools can authenticate through standard OAuth flows.

What the MCP OAuth flow looks like#

text
MCP Client                    KavachOS                    MCP Server
    │                            │                            │
    │  1. Authorization Request  │                            │
    │  (PKCE + code_challenge)   │                            │
    │ ─────────────────────────► │                            │
    │                            │                            │
    │  2. Auth Code              │                            │
    │ ◄───────────────────────── │                            │
    │                            │                            │
    │  3. Token Exchange         │                            │
    │  (code + code_verifier)    │                            │
    │ ─────────────────────────► │                            │
    │                            │                            │
    │  4. Access Token           │                            │
    │ ◄───────────────────────── │                            │
    │                            │                            │
    │  5. API Call with Token    │                            │
    │ ──────────────────────────────────────────────────────► │
    │                            │                            │

Add more auth methods#

Want magic links? Passkeys? OAuth with Google? They're all plugins:

typescript
import {
  emailPassword,
  magicLink,
  passkey,
  totp,
} from "kavachos/auth";

const kavach = await createKavach({
  database: { provider: "postgres", url: process.env.DATABASE_URL },
  plugins: [
    emailPassword(),
    magicLink({
      sendMagicLink: async (email, url) => {
        await resend.emails.send({
          to: email,
          subject: "Sign in to MyApp",
          html: `<a href="${url}">Click to sign in</a>`,
        });
      },
    }),
    passkey(),
    totp(),
  ],
});

All 14 auth methods#

Method Plugin Notes
Email + password emailPassword() HIBP breach checking built in
Magic link magicLink() Bring your own email sender
Email OTP emailOtp() 6-digit code via email
Phone SMS phoneOtp() Bring your own SMS sender
Passkey/WebAuthn passkey() Passwordless biometric
TOTP 2FA totp() Google Authenticator, Authy
Anonymous anonymous() Guest sessions
Google One-tap googleOneTap() One-click sign-in
Username/password usernamePassword() For non-email systems
Sign In With Ethereum siwe() Web3 wallet auth
Device authorization deviceAuth() TV/CLI flows (RFC 8628)
Captcha captcha() Turnstile, reCAPTCHA
Password reset passwordReset() Signed, expiring tokens
Session freshness sessionFreshness() Re-auth for sensitive ops

Framework adapters#

KavachOS runs on whatever you're using:

Framework Install Adapter
Hono npm i @kavachos/hono createHonoAdapter(kavach)
Express npm i @kavachos/express createExpressRouter(kavach)
Next.js npm i @kavachos/nextjs createNextjsHandler(kavach)
Fastify npm i @kavachos/fastify kavachPlugin(kavach)
Nuxt npm i @kavachos/nuxt createNuxtHandler(kavach)
SvelteKit npm i @kavachos/sveltekit createSvelteKitHandler(kavach)
Astro npm i @kavachos/astro createAstroHandler(kavach)
NestJS npm i @kavachos/nestjs KavachModule.register(kavach)
SolidStart npm i @kavachos/solidstart createSolidHandler(kavach)
TanStack Start npm i @kavachos/tanstack createTanStackHandler(kavach)

React hooks#

On the frontend:

tsx
import { KavachProvider, useSession, useSignIn } from "@kavachos/react";

function App() {
  return (
    <KavachProvider>
      <LoginPage />
    </KavachProvider>
  );
}

function LoginPage() {
  const { signIn } = useSignIn();
  const { session } = useSession();

  if (session) return <p>Signed in as {session.user.email}</p>;

  return (
    <button onClick={() => signIn("ada@example.com", "secret123")}>
      Sign in
    </button>
  );
}

Also available: @kavachos/vue, @kavachos/svelte, @kavachos/expo (React Native), @kavachos/electron.

Deploy to the edge#

Three runtime dependencies: drizzle-orm, jose, zod. That's it. Runs on Cloudflare Workers, Deno, Bun, and Node without code changes.

text
Runtime support:

  Node.js 20+          ✅
  Cloudflare Workers   ✅  (D1 database)
  Deno                 ✅
  Bun                  ✅

Dependencies:

  drizzle-orm    ORM + query builder
  jose           JWT signing/verification
  zod            Schema validation

  Total: 3
typescript
// Cloudflare Workers + D1
const kavach = await createKavach({
  database: { provider: "d1", binding: env.KAVACH_DB },
  plugins: [emailPassword()],
});

What's next#

KavachOS is MIT licensed and open source. The full docs are at docs.kavachos.com.

Code: github.com/kavachos/kavachos


#gdsks #glincker #kavachOS #askverdict #auth0 #authlibrary

This article is published here first and cross-posted to Dev.to. This page is the canonical version.
Contact