Skip to main content
createKavach() accepts a KavachConfig object. The only required field is database. Everything else is optional and enables features incrementally.
import { createKavach } from 'kavachos';

const kavach = await createKavach({
  database: { provider: 'sqlite', url: 'kavach.db' },
});

Common development setup

A minimal config for local development with email/password auth and no email sending:
import { createKavach } from 'kavachos';
import { emailPassword } from 'kavachos/auth';

const kavach = await createKavach({
  database: { provider: 'sqlite', url: './kavach.db' },
  plugins: [
    emailPassword({
      requireVerification: false, // skip in dev
      onSendVerification: async (email, token) => {
        console.log(`Verify: http://localhost:3000/verify?token=${token}`);
      },
    }),
  ],
});

Top-level options

database
DatabaseConfig
required
Database connection config. Required.
agents
AgentConfig
Agent identity settings.
mcp
McpConfig
MCP OAuth 2.1 authorization server.
auth
{ adapter?: AuthAdapter; session?: SessionConfig }
Human auth adapter and session config.
anomaly
AnomalyConfig
Anomaly detection thresholds.
approval
ApprovalConfig
CIBA async approval flow config.
trust
TrustConfig
Graduated autonomy trust scoring.
telemetry
TelemetryConfig
OpenTelemetry integration via hooks.
hooks
KavachHooks
Lifecycle hooks for sandboxing and custom validation.
baseUrl
string
Base URL for the auth server (e.g. https://auth.example.com).
secret
string
Secret key used to sign tokens. Min 32 characters.

Database config

provider
"sqlite" | "postgres" | "mysql" | "d1"
required
Database driver to use.
url
string
File path for SQLite, connection string for Postgres/MySQL. Not used with D1.
binding
D1Database
D1Database binding from the Worker environment. Required when provider is “d1”.
skipMigrations
boolean
Skip automatic CREATE TABLE IF NOT EXISTS on init. Use when you manage migrations externally (Flyway, drizzle-kit push, etc.). Defaults to false.
// Cloudflare D1 (edge)
const kavach = await createKavach({
  database: {
    provider: 'd1',
    binding: env.KAVACH_DB,  // D1Database from Worker env
  },
});

// SQLite (Node.js)
const kavach = await createKavach({
  database: { provider: 'sqlite', url: './kavach.db' },
});

// PostgreSQL
const kavach = await createKavach({
  database: { provider: 'postgres', url: process.env.DATABASE_URL },
});

// MySQL
database: { provider: 'mysql', url: process.env.DATABASE_URL }

// In-memory SQLite (tests)
database: { provider: 'sqlite', url: ':memory:' }

Agent config

Controls the agent identity lifecycle.
enabled
boolean
required
Enable agent identity management.
maxPerUser
number
Maximum number of agents a single user can create.
defaultPermissions
string[]
Permission strings assigned to every new agent unless overridden.
auditAll
boolean
Write every agent action to the audit log regardless of permission outcome.
tokenExpiry
string
Default token expiry duration string (e.g. “7d”, “24h”, “30m”).
agents: {
  enabled: true,
  maxPerUser: 10,
  defaultPermissions: [],
  auditAll: true,
  tokenExpiry: '30d',
},

MCP config

Enables the OAuth 2.1 authorization server for MCP-compliant tool access.
enabled
boolean
required
Enable the MCP authorization server.
issuer
string
Token issuer URL. Appears as the iss claim in JWTs.
baseUrl
string
Base path for MCP endpoints.
signingSecret
string
Secret used to sign JWTs. Min 32 characters. Defaults to the top-level secret.
accessTokenTtl
number
Access token lifetime in seconds. Defaults to 3600 (1 hour).
refreshTokenTtl
number
Refresh token lifetime in seconds. Defaults to 604800 (7 days).
codeTtl
number
Authorization code lifetime in seconds. Defaults to 600 (10 minutes).
enforceAuth
boolean
Reject all MCP requests without a valid Bearer token.
scopes
string[]
Custom OAuth scopes supported by this server.
allowedResources
string[]
Allowed resource URIs for RFC 8707 resource indicators.
loginPage
string
URL of your login page. Users are redirected here when unauthenticated.
URL of your consent page. Users are redirected here to approve scopes.
preRegisteredClients
OAuth clients registered at startup (first-party apps, CLIs, test fixtures).
getAdditionalClaims
Async function to add custom claims to issued tokens.
mcp: {
  enabled: true,
  issuer: 'https://auth.example.com',
  baseUrl: 'https://auth.example.com',
  accessTokenTtl: 3600,
  refreshTokenTtl: 604800,
  enforceAuth: true,
  loginPage: 'https://example.com/login',
  consentPage: 'https://example.com/consent',
},

Auth config

Connects KavachOS to your existing auth provider so it can resolve the human user behind incoming requests.
auth: {
  adapter: betterAuthAdapter(auth),   // resolves user from request
  session: {                          // optional: KavachOS-managed sessions
    secret: process.env.SESSION_SECRET,
    maxAge: 60 * 60 * 24 * 30,       // 30 days in seconds
  },
},
When auth is omitted, kavach.auth.resolveUser() always returns null (manual user management mode). See Auth adapters for all adapter options.

Session config

secret
string
required
Signing secret for session JWTs. Min 32 characters.
maxAge
number
default:"604800 (7 days)"
Session lifetime in seconds.
Name of the session cookie.

Password reset config

Requires auth.session to be configured. The caller provides an email-sending callback.
sendResetEmail
required
Callback to deliver the reset email. Receives email, raw token, and constructed URL.
resetUrl
string
required
Base URL for the reset page. Token is appended as ?token=…
tokenTtlSeconds
number
default:"3600 (1h)"
Reset token lifetime in seconds.
revokeSessionsOnReset
boolean
default:"true"
Revoke all sessions when the password is successfully reset.
minPasswordLength
number
default:"8"
Minimum new password length.
maxPasswordLength
number
default:"128"
Maximum new password length.
Always use an HTTPS URL for resetUrl in production. Reset tokens in plain HTTP links can be intercepted in transit or leaked via Referer headers.
auth: {
  adapter: betterAuthAdapter(auth),
  session: {
    secret: process.env.SESSION_SECRET!,
    maxAge: 60 * 60 * 24 * 7, // 7 days
  },
  passwordReset: {
    resetUrl: 'https://example.com/reset-password',
    tokenTtlSeconds: 3600,
    revokeSessionsOnReset: true,
    minPasswordLength: 10,
    sendResetEmail: async (email, token, url) => {
      await mailer.send({
        to: email,
        subject: 'Reset your password',
        html: `<a href="${url}">Reset password</a>`,
      });
    },
  },
},

Session freshness config

Controls when sessions are considered “fresh” for sensitive operations like password changes and passkey registration.
freshAge
number
default:"300 (5 minutes)"
Maximum session age in seconds to be considered fresh.

Plugins

KavachOS features are composable. Enable what you need:
PluginImportWhat it does
emailPasswordkavachos/authEmail + password with verification and reset
passkeykavachos/authWebAuthn/FIDO2 biometric auth
magicLinkkavachos/authPasswordless email links
emailOtpkavachos/authOne-time password codes via email
twoFactorkavachos/authTOTP 2FA with backup codes
multiSessionkavachos/authSession limits and device management
organizationkavachos/authOrganizations with RBAC
apiKeyskavachos/authStatic API key management
adminkavachos/authUser management, banning, impersonation
stripekavachos/authStripe billing integration
polarkavachos/authPolar payment integration

Anomaly config

highFrequencyThreshold
number
Calls per agent per hour before flagging as high-frequency. Defaults to 500.
highDenialRateThreshold
number
Denial rate percentage that triggers an alert. Defaults to 50.
expectedHours
{ start: number; end: number }
Flag access outside these hours (0-23) as off-hours anomaly. Optional.
anomaly: {
  highFrequencyThreshold: 200,
  highDenialRateThreshold: 30,
  expectedHours: { start: 8, end: 20 },
},

Environment variables pattern

Never hardcode secrets in config. Pass them through environment variables:
const kavach = await createKavach({
  database: {
    provider: 'postgres',
    url: process.env.DATABASE_URL!,
  },
  secret: process.env.KAVACH_SECRET!,
  mcp: {
    enabled: true,
    issuer: process.env.KAVACH_ISSUER!,
    signingSecret: process.env.KAVACH_SIGNING_SECRET,
  },
});

Dev vs production example

// config/kavach.ts
const isDev = process.env.NODE_ENV !== 'production';

export const kavach = await createKavach({
  database: isDev
    ? { provider: 'sqlite', url: './kavach-dev.db' }
    : { provider: 'postgres', url: process.env.DATABASE_URL! },

  secret: process.env.KAVACH_SECRET!,
  baseUrl: process.env.KAVACH_BASE_URL ?? 'http://localhost:3000',

  agents: {
    enabled: true,
    maxPerUser: isDev ? 100 : 25,
    auditAll: true,
    tokenExpiry: '30d',
  },

  mcp: {
    enabled: true,
    issuer: process.env.KAVACH_BASE_URL ?? 'http://localhost:3000',
    accessTokenTtl: isDev ? 86400 : 3600,
    enforceAuth: !isDev,
    loginPage: '/login',
    consentPage: '/consent',
  },

  anomaly: {
    highFrequencyThreshold: 500,
    highDenialRateThreshold: 50,
  },
});
secret and mcp.signingSecret must be at least 32 characters. In production, generate them with openssl rand -base64 32.

Next steps

Auth adapters

Connect to better-auth, Auth.js, or Clerk.

Database setup

SQLite, Postgres, or MySQL configuration.

Framework adapters

Mount KavachOS on your framework.