Configuration
All createKavach() options explained.
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
Prop
Type
Database config
Prop
Type
// 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.
Prop
Type
agents: {
enabled: true,
maxPerUser: 10,
defaultPermissions: [],
auditAll: true,
tokenExpiry: '30d',
},MCP config
Enables the OAuth 2.1 authorization server for MCP-compliant tool access.
Prop
Type
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
Prop
Type
Password reset config
Requires auth.session to be configured. The caller provides an email-sending callback.
Prop
Type
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.
Prop
Type
Plugins
KavachOS features are composable. Enable what you need:
| Plugin | Import | What it does |
|---|---|---|
emailPassword | kavachos/auth | Email + password with verification and reset |
passkey | kavachos/auth | WebAuthn/FIDO2 biometric auth |
magicLink | kavachos/auth | Passwordless email links |
emailOtp | kavachos/auth | One-time password codes via email |
twoFactor | kavachos/auth | TOTP 2FA with backup codes |
multiSession | kavachos/auth | Session limits and device management |
organization | kavachos/auth | Organizations with RBAC |
apiKeys | kavachos/auth | Static API key management |
admin | kavachos/auth | User management, banning, impersonation |
stripe | kavachos/auth | Stripe billing integration |
polar | kavachos/auth | Polar payment integration |
Anomaly config
Prop
Type
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.